ALSA: scarlett2: Add skeleton hwdep/ioctl interface
authorGeoffrey D. Bennett <g@b4.vu>
Tue, 19 Dec 2023 17:39:23 +0000 (04:09 +1030)
committerTakashi Iwai <tiwai@suse.de>
Fri, 29 Dec 2023 14:39:27 +0000 (15:39 +0100)
Add skeleton hwdep/ioctl interface, beginning with
SCARLETT2_IOCTL_PVERSION and SCARLETT2_IOCTL_REBOOT.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
Link: https://lore.kernel.org/r/24ffcd47a8a02ebad3c8b2438104af8f0169164e.1703001053.git.g@b4.vu
Signed-off-by: Takashi Iwai <tiwai@suse.de>
MAINTAINERS
include/uapi/sound/scarlett2.h [new file with mode: 0644]
sound/usb/mixer_scarlett2.c

index ae3f72f578542a4f9414059d4455c6d760702834..80c65096538cfea46aa8fdab36a2eda567ef2eb3 100644 (file)
@@ -8279,6 +8279,7 @@ S:        Maintained
 W:     https://github.com/geoffreybennett/scarlett-gen2
 B:     https://github.com/geoffreybennett/scarlett-gen2/issues
 T:     git https://github.com/geoffreybennett/scarlett-gen2.git
+F:     include/uapi/sound/scarlett2.h
 F:     sound/usb/mixer_scarlett2.c
 
 FORCEDETH GIGABIT ETHERNET DRIVER
diff --git a/include/uapi/sound/scarlett2.h b/include/uapi/sound/scarlett2.h
new file mode 100644 (file)
index 0000000..ec0b7da
--- /dev/null
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ *   Focusrite Scarlett 2 Protocol Driver for ALSA
+ *   (including Scarlett 2nd Gen, 3rd Gen, Clarett USB, and Clarett+
+ *   series products)
+ *
+ *   Copyright (c) 2023 by Geoffrey D. Bennett <g at b4.vu>
+ */
+#ifndef __UAPI_SOUND_SCARLETT2_H
+#define __UAPI_SOUND_SCARLETT2_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define SCARLETT2_HWDEP_MAJOR 1
+#define SCARLETT2_HWDEP_MINOR 0
+#define SCARLETT2_HWDEP_SUBMINOR 0
+
+#define SCARLETT2_HWDEP_VERSION \
+       ((SCARLETT2_HWDEP_MAJOR << 16) | \
+        (SCARLETT2_HWDEP_MINOR << 8) | \
+         SCARLETT2_HWDEP_SUBMINOR)
+
+#define SCARLETT2_HWDEP_VERSION_MAJOR(v) (((v) >> 16) & 0xFF)
+#define SCARLETT2_HWDEP_VERSION_MINOR(v) (((v) >> 8) & 0xFF)
+#define SCARLETT2_HWDEP_VERSION_SUBMINOR(v) ((v) & 0xFF)
+
+/* Get protocol version */
+#define SCARLETT2_IOCTL_PVERSION _IOR('S', 0x60, int)
+
+/* Reboot */
+#define SCARLETT2_IOCTL_REBOOT _IO('S', 0x61)
+
+#endif /* __UAPI_SOUND_SCARLETT2_H */
index b62fc0038671debb4f2720817549a0d95f9d9019..d27628e4bda825818fefc072f0a44b1aaef27c30 100644 (file)
 
 #include <sound/control.h>
 #include <sound/tlv.h>
+#include <sound/hwdep.h>
+
+#include <uapi/sound/scarlett2.h>
 
 #include "usbaudio.h"
 #include "mixer.h"
@@ -1439,6 +1442,16 @@ static int scarlett2_usb(
        /* validate the response */
 
        if (err != resp_buf_size) {
+
+               /* ESHUTDOWN and EPROTO are valid responses to a
+                * reboot request
+                */
+               if (cmd == SCARLETT2_USB_REBOOT &&
+                   (err == -ESHUTDOWN || err == -EPROTO)) {
+                       err = 0;
+                       goto unlock;
+               }
+
                usb_audio_err(
                        mixer->chip,
                        "%s USB response result cmd %x was %d expected %zu\n",
@@ -4697,6 +4710,49 @@ static int snd_scarlett2_controls_create(
        return 0;
 }
 
+/*** hwdep interface ***/
+
+/* Reboot the device. */
+static int scarlett2_reboot(struct usb_mixer_interface *mixer)
+{
+       return scarlett2_usb(mixer, SCARLETT2_USB_REBOOT, NULL, 0, NULL, 0);
+}
+
+static int scarlett2_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
+                                unsigned int cmd, unsigned long arg)
+{
+       struct usb_mixer_interface *mixer = hw->private_data;
+
+       switch (cmd) {
+
+       case SCARLETT2_IOCTL_PVERSION:
+               return put_user(SCARLETT2_HWDEP_VERSION,
+                               (int __user *)arg) ? -EFAULT : 0;
+
+       case SCARLETT2_IOCTL_REBOOT:
+               return scarlett2_reboot(mixer);
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+static int scarlett2_hwdep_init(struct usb_mixer_interface *mixer)
+{
+       struct snd_hwdep *hw;
+       int err;
+
+       err = snd_hwdep_new(mixer->chip->card, "Focusrite Control", 0, &hw);
+       if (err < 0)
+               return err;
+
+       hw->private_data = mixer;
+       hw->exclusive = 1;
+       hw->ops.ioctl = scarlett2_hwdep_ioctl;
+
+       return 0;
+}
+
 int snd_scarlett2_init(struct usb_mixer_interface *mixer)
 {
        struct snd_usb_audio *chip = mixer->chip;
@@ -4738,11 +4794,20 @@ int snd_scarlett2_init(struct usb_mixer_interface *mixer)
                USB_ID_PRODUCT(chip->usb_id));
 
        err = snd_scarlett2_controls_create(mixer, entry);
-       if (err < 0)
+       if (err < 0) {
                usb_audio_err(mixer->chip,
                              "Error initialising %s Mixer Driver: %d",
                              entry->series_name,
                              err);
+               return err;
+       }
+
+       err = scarlett2_hwdep_init(mixer);
+       if (err < 0)
+               usb_audio_err(mixer->chip,
+                             "Error creating %s hwdep device: %d",
+                             entry->series_name,
+                             err);
 
        return err;
 }