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