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_device *device, int idx,
  68                              const struct hiface_vendor_quirk *quirk,
  69                              struct hiface_chip **rchip)
  70{
  71        struct snd_card *card = NULL;
  72        struct hiface_chip *chip;
  73        int ret;
  74        int len;
  75
  76        *rchip = NULL;
  77
  78        /* if we are here, card can be registered in alsa. */
  79        ret = snd_card_create(index[idx], id[idx], THIS_MODULE, sizeof(*chip), &card);
  80        if (ret < 0) {
  81                dev_err(&device->dev, "cannot create alsa card.\n");
  82                return ret;
  83        }
  84
  85        strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
  86
  87        if (quirk && quirk->device_name)
  88                strlcpy(card->shortname, quirk->device_name, sizeof(card->shortname));
  89        else
  90                strlcpy(card->shortname, "M2Tech generic audio", sizeof(card->shortname));
  91
  92        strlcat(card->longname, card->shortname, sizeof(card->longname));
  93        len = strlcat(card->longname, " at ", sizeof(card->longname));
  94        if (len < sizeof(card->longname))
  95                usb_make_path(device, card->longname + len,
  96                              sizeof(card->longname) - len);
  97
  98        chip = card->private_data;
  99        chip->dev = device;
 100        chip->card = card;
 101
 102        *rchip = chip;
 103        return 0;
 104}
 105
 106static int hiface_chip_probe(struct usb_interface *intf,
 107                             const struct usb_device_id *usb_id)
 108{
 109        const struct hiface_vendor_quirk *quirk = (struct hiface_vendor_quirk *)usb_id->driver_info;
 110        int ret;
 111        int i;
 112        struct hiface_chip *chip;
 113        struct usb_device *device = interface_to_usbdev(intf);
 114
 115        ret = usb_set_interface(device, 0, 0);
 116        if (ret != 0) {
 117                dev_err(&device->dev, "can't set first interface for " CARD_NAME " device.\n");
 118                return -EIO;
 119        }
 120
 121        /* check whether the card is already registered */
 122        chip = NULL;
 123        mutex_lock(&register_mutex);
 124
 125        for (i = 0; i < SNDRV_CARDS; i++)
 126                if (enable[i])
 127                        break;
 128
 129        if (i >= SNDRV_CARDS) {
 130                dev_err(&device->dev, "no available " CARD_NAME " audio device\n");
 131                ret = -ENODEV;
 132                goto err;
 133        }
 134
 135        ret = hiface_chip_create(device, i, quirk, &chip);
 136        if (ret < 0)
 137                goto err;
 138
 139        snd_card_set_dev(chip->card, &intf->dev);
 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