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