linux/sound/usb/hiface/chip.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Linux driver for M2Tech hiFace compatible devices
   4 *
   5 * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V.
   6 *
   7 * Authors:  Michael Trimarchi <michael@amarulasolutions.com>
   8 *           Antonio Ospite <ao2@amarulasolutions.com>
   9 *
  10 * The driver is based on the work done in TerraTec DMX 6Fire USB
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/slab.h>
  15#include <sound/initval.h>
  16
  17#include "chip.h"
  18#include "pcm.h"
  19
  20MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
  21MODULE_AUTHOR("Antonio Ospite <ao2@amarulasolutions.com>");
  22MODULE_DESCRIPTION("M2Tech hiFace USB-SPDIF audio driver");
  23MODULE_LICENSE("GPL v2");
  24
  25static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
  26static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
  27static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
  28
  29#define DRIVER_NAME "snd-usb-hiface"
  30#define CARD_NAME "hiFace"
  31
  32module_param_array(index, int, NULL, 0444);
  33MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
  34module_param_array(id, charp, NULL, 0444);
  35MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
  36module_param_array(enable, bool, NULL, 0444);
  37MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
  38
  39static DEFINE_MUTEX(register_mutex);
  40
  41struct hiface_vendor_quirk {
  42        const char *device_name;
  43        u8 extra_freq;
  44};
  45
  46static int hiface_chip_create(struct usb_interface *intf,
  47                              struct usb_device *device, int idx,
  48                              const struct hiface_vendor_quirk *quirk,
  49                              struct hiface_chip **rchip)
  50{
  51        struct snd_card *card = NULL;
  52        struct hiface_chip *chip;
  53        int ret;
  54        int len;
  55
  56        *rchip = NULL;
  57
  58        /* if we are here, card can be registered in alsa. */
  59        ret = snd_card_new(&intf->dev, index[idx], id[idx], THIS_MODULE,
  60                           sizeof(*chip), &card);
  61        if (ret < 0) {
  62                dev_err(&device->dev, "cannot create alsa card.\n");
  63                return ret;
  64        }
  65
  66        strscpy(card->driver, DRIVER_NAME, sizeof(card->driver));
  67
  68        if (quirk && quirk->device_name)
  69                strscpy(card->shortname, quirk->device_name, sizeof(card->shortname));
  70        else
  71                strscpy(card->shortname, "M2Tech generic audio", sizeof(card->shortname));
  72
  73        strlcat(card->longname, card->shortname, sizeof(card->longname));
  74        len = strlcat(card->longname, " at ", sizeof(card->longname));
  75        if (len < sizeof(card->longname))
  76                usb_make_path(device, card->longname + len,
  77                              sizeof(card->longname) - len);
  78
  79        chip = card->private_data;
  80        chip->dev = device;
  81        chip->card = card;
  82
  83        *rchip = chip;
  84        return 0;
  85}
  86
  87static int hiface_chip_probe(struct usb_interface *intf,
  88                             const struct usb_device_id *usb_id)
  89{
  90        const struct hiface_vendor_quirk *quirk = (struct hiface_vendor_quirk *)usb_id->driver_info;
  91        int ret;
  92        int i;
  93        struct hiface_chip *chip;
  94        struct usb_device *device = interface_to_usbdev(intf);
  95
  96        ret = usb_set_interface(device, 0, 0);
  97        if (ret != 0) {
  98                dev_err(&device->dev, "can't set first interface for " CARD_NAME " device.\n");
  99                return -EIO;
 100        }
 101
 102        /* check whether the card is already registered */
 103        chip = NULL;
 104        mutex_lock(&register_mutex);
 105
 106        for (i = 0; i < SNDRV_CARDS; i++)
 107                if (enable[i])
 108                        break;
 109
 110        if (i >= SNDRV_CARDS) {
 111                dev_err(&device->dev, "no available " CARD_NAME " audio device\n");
 112                ret = -ENODEV;
 113                goto err;
 114        }
 115
 116        ret = hiface_chip_create(intf, device, i, quirk, &chip);
 117        if (ret < 0)
 118                goto err;
 119
 120        ret = hiface_pcm_init(chip, quirk ? quirk->extra_freq : 0);
 121        if (ret < 0)
 122                goto err_chip_destroy;
 123
 124        ret = snd_card_register(chip->card);
 125        if (ret < 0) {
 126                dev_err(&device->dev, "cannot register " CARD_NAME " card\n");
 127                goto err_chip_destroy;
 128        }
 129
 130        mutex_unlock(&register_mutex);
 131
 132        usb_set_intfdata(intf, chip);
 133        return 0;
 134
 135err_chip_destroy:
 136        snd_card_free(chip->card);
 137err:
 138        mutex_unlock(&register_mutex);
 139        return ret;
 140}
 141
 142static void hiface_chip_disconnect(struct usb_interface *intf)
 143{
 144        struct hiface_chip *chip;
 145        struct snd_card *card;
 146
 147        chip = usb_get_intfdata(intf);
 148        if (!chip)
 149                return;
 150
 151        card = chip->card;
 152
 153        /* Make sure that the userspace cannot create new request */
 154        snd_card_disconnect(card);
 155
 156        hiface_pcm_abort(chip);
 157        snd_card_free_when_closed(card);
 158}
 159
 160static const struct usb_device_id device_table[] = {
 161        {
 162                USB_DEVICE(0x04b4, 0x0384),
 163                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 164                        .device_name = "Young",
 165                        .extra_freq = 1,
 166                }
 167        },
 168        {
 169                USB_DEVICE(0x04b4, 0x930b),
 170                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 171                        .device_name = "hiFace",
 172                }
 173        },
 174        {
 175                USB_DEVICE(0x04b4, 0x931b),
 176                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 177                        .device_name = "North Star",
 178                }
 179        },
 180        {
 181                USB_DEVICE(0x04b4, 0x931c),
 182                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 183                        .device_name = "W4S Young",
 184                }
 185        },
 186        {
 187                USB_DEVICE(0x04b4, 0x931d),
 188                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 189                        .device_name = "Corrson",
 190                }
 191        },
 192        {
 193                USB_DEVICE(0x04b4, 0x931e),
 194                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 195                        .device_name = "AUDIA",
 196                }
 197        },
 198        {
 199                USB_DEVICE(0x04b4, 0x931f),
 200                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 201                        .device_name = "SL Audio",
 202                }
 203        },
 204        {
 205                USB_DEVICE(0x04b4, 0x9320),
 206                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 207                        .device_name = "Empirical",
 208                }
 209        },
 210        {
 211                USB_DEVICE(0x04b4, 0x9321),
 212                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 213                        .device_name = "Rockna",
 214                }
 215        },
 216        {
 217                USB_DEVICE(0x249c, 0x9001),
 218                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 219                        .device_name = "Pathos",
 220                }
 221        },
 222        {
 223                USB_DEVICE(0x249c, 0x9002),
 224                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 225                        .device_name = "Metronome",
 226                }
 227        },
 228        {
 229                USB_DEVICE(0x249c, 0x9006),
 230                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 231                        .device_name = "CAD",
 232                }
 233        },
 234        {
 235                USB_DEVICE(0x249c, 0x9008),
 236                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 237                        .device_name = "Audio Esclusive",
 238                }
 239        },
 240        {
 241                USB_DEVICE(0x249c, 0x931c),
 242                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 243                        .device_name = "Rotel",
 244                }
 245        },
 246        {
 247                USB_DEVICE(0x249c, 0x932c),
 248                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 249                        .device_name = "Eeaudio",
 250                }
 251        },
 252        {
 253                USB_DEVICE(0x245f, 0x931c),
 254                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 255                        .device_name = "CHORD",
 256                }
 257        },
 258        {
 259                USB_DEVICE(0x25c6, 0x9002),
 260                .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
 261                        .device_name = "Vitus",
 262                }
 263        },
 264        {}
 265};
 266
 267MODULE_DEVICE_TABLE(usb, device_table);
 268
 269static struct usb_driver hiface_usb_driver = {
 270        .name = DRIVER_NAME,
 271        .probe = hiface_chip_probe,
 272        .disconnect = hiface_chip_disconnect,
 273        .id_table = device_table,
 274};
 275
 276module_usb_driver(hiface_usb_driver);
 277