Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.6.17 /sound/usb/usbaudio.c

Filename:/sound/usb/usbaudio.c
Lines Added:128
Lines Deleted:40
Also changed in: (Previous) 2.6.17-rc6  2.6.17-rc5  2.6.17-rc4  2.6.17-rc3  2.6.17-rc2  2.6.17-rc1 
(Following) 2.6.17-git5  2.6.17-git6  2.6.17-git7  2.6.17-git8  2.6.17-git9  2.6.17-git10 

Location
[  2.6.17
  [  sound
    [  usb
       o  usbaudio.c

Patch

diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index d501338..4e614ac 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -47,6 +47,7 @@ #include <linux/string.h>
 #include <linux/usb.h>
 #include <linux/vmalloc.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/pcm.h>
@@ -69,6 +70,7 @@ static int vid[SNDRV_CARDS] = { [0 ... (
 static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */
 static int nrpacks = 4;      /* max. number of packets per urb */
 static int async_unlink = 1;
+static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");
@@ -84,6 +86,8 @@ module_param(nrpacks, int, 0644);
 MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB.");
 module_param(async_unlink, bool, 0444);
 MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
+module_param_array(device_setup, int, NULL, 0444);
+MODULE_PARM_DESC(device_setup, "Specific device setup (if needed).");
 
 
 /*
@@ -202,7 +206,7 @@ struct snd_usb_stream {
  * the all interfaces on the same card as one sound device.
  */
 
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 static struct snd_usb_audio *usb_chip[SNDRV_CARDS];
 
 
@@ -475,6 +479,18 @@ static int retire_playback_sync_urb_hs(s
    return 0;
 }
 
+/* determine the number of frames in the next packet */
+static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs)
+{
+   if (subs->fill_max)
+      return subs->maxframesize;
+   else {
+      subs->phase = (subs->phase & 0xffff)
+         + (subs->freqm << subs->datainterval);
+      return min(subs->phase >> 16, subs->maxframesize);
+   }
+}
+
 /*
  * Prepare urb for streaming before playback starts.
  *
@@ -492,16 +508,7 @@ static int prepare_startup_playback_urb(
    urb->dev = ctx->subs->dev;
    urb->number_of_packets = subs->packs_per_ms;
    for (i = 0; i < subs->packs_per_ms; ++i) {
-      /* calculate the size of a packet */
-      if (subs->fill_max)
-         counts = subs->maxframesize; /* fixed */
-      else {
-         subs->phase = (subs->phase & 0xffff)
-            + (subs->freqm << subs->datainterval);
-         counts = subs->phase >> 16;
-         if (counts > subs->maxframesize)
-            counts = subs->maxframesize;
-      }
+      counts = snd_usb_audio_next_packet_size(subs);
       urb->iso_frame_desc[i].offset = offs * stride;
       urb->iso_frame_desc[i].length = counts * stride;
       offs += counts;
@@ -538,16 +545,7 @@ static int prepare_playback_urb(struct s
    urb->number_of_packets = 0;
    spin_lock_irqsave(&subs->lock, flags);
    for (i = 0; i < ctx->packets; i++) {
-      /* calculate the size of a packet */
-      if (subs->fill_max)
-         counts = subs->maxframesize; /* fixed */
-      else {
-         subs->phase = (subs->phase & 0xffff)
-            + (subs->freqm << subs->datainterval);
-         counts = subs->phase >> 16;
-         if (counts > subs->maxframesize)
-            counts = subs->maxframesize;
-      }
+      counts = snd_usb_audio_next_packet_size(subs);
       /* set up descriptor */
       urb->iso_frame_desc[i].offset = offs * stride;
       urb->iso_frame_desc[i].length = counts * stride;
@@ -725,10 +723,9 @@ static int snd_pcm_alloc_vmalloc_buffer(
 static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs)
 {
    struct snd_pcm_runtime *runtime = subs->runtime;
-   if (runtime->dma_area) {
-      vfree(runtime->dma_area);
-      runtime->dma_area = NULL;
-   }
+
+   vfree(runtime->dma_area);
+   runtime->dma_area = NULL;
    return 0;
 }
 
@@ -779,6 +776,35 @@ static int deactivate_urbs(struct snd_us
 }
 
 
+static const char *usb_error_string(int err)
+{
+   switch (err) {
+   case -ENODEV:
+      return "no device";
+   case -ENOENT:
+      return "endpoint not enabled";
+   case -EPIPE:
+      return "endpoint stalled";
+   case -ENOSPC:
+      return "not enough bandwidth";
+   case -ESHUTDOWN:
+      return "device disabled";
+   case -EHOSTUNREACH:
+      return "device suspended";
+#ifndef CONFIG_USB_EHCI_SPLIT_ISO
+   case -ENOSYS:
+      return "enable CONFIG_USB_EHCI_SPLIT_ISO to play through a hub";
+#endif
+   case -EINVAL:
+   case -EAGAIN:
+   case -EFBIG:
+   case -EMSGSIZE:
+      return "internal error";
+   default:
+      return "unknown error";
+   }
+}
+
 /*
  * set up and start data/sync urbs
  */
@@ -811,16 +837,22 @@ static int start_urbs(struct snd_usb_sub
    subs->unlink_mask = 0;
    subs->running = 1;
    for (i = 0; i < subs->nurbs; i++) {
-      if ((err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC)) < 0) {
-         snd_printk(KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err);
+      err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC);
+      if (err < 0) {
+         snd_printk(KERN_ERR "cannot submit datapipe "
+               "for urb %d, error %d: %s\n",
+               i, err, usb_error_string(err));
          goto __error;
       }
       set_bit(i, &subs->active_mask);
    }
    if (subs->syncpipe) {
       for (i = 0; i < SYNC_URBS; i++) {
-         if ((err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC)) < 0) {
-            snd_printk(KERN_ERR "cannot submit syncpipe for urb %d, err = %d\n", i, err);
+         err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC);
+         if (err < 0) {
+            snd_printk(KERN_ERR "cannot submit syncpipe "
+                  "for urb %d, error %d: %s\n",
+                  i, err, usb_error_string(err));
             goto __error;
          }
          set_bit(i + 16, &subs->active_mask);
@@ -1390,8 +1422,8 @@ static int snd_usb_hw_params(struct snd_
    channels = params_channels(hw_params);
    fmt = find_format(subs, format, rate, channels);
    if (! fmt) {
-      snd_printd(KERN_DEBUG "cannot set format: format = %s, rate = %d, channels = %d\n",
-            snd_pcm_format_name(format), rate, channels);
+      snd_printd(KERN_DEBUG "cannot set format: format = 0x%x, rate = %d, channels = %d\n",
+            format, rate, channels);
       return -EINVAL;
    }
 
@@ -2017,6 +2049,8 @@ static struct usb_driver usb_audio_drive
 };
 
 
+#if defined(CONFIG_PROCFS) && defined(CONFIG_SND_VERBOSE_PROCFS)
+
 /*
  * proc interface for list the supported pcm formats
  */
@@ -2032,7 +2066,7 @@ static void proc_dump_substream_formats(
       fp = list_entry(p, struct audioformat, list);
       snd_iprintf(buffer, "  Interface %d\n", fp->iface);
       snd_iprintf(buffer, "    Altset %d\n", fp->altsetting);
-      snd_iprintf(buffer, "    Format: %s\n", snd_pcm_format_name(fp->format));
+      snd_iprintf(buffer, "    Format: 0x%x\n", fp->format);
       snd_iprintf(buffer, "    Channels: %d\n", fp->channels);
       snd_iprintf(buffer, "    Endpoint: %d %s (%s)\n",
              fp->endpoint & USB_ENDPOINT_NUMBER_MASK,
@@ -2107,6 +2141,13 @@ static void proc_pcm_format_add(struct s
       snd_info_set_text_ops(entry, stream, 1024, proc_pcm_format_read);
 }
 
+#else
+
+static inline void proc_pcm_format_add(struct snd_usb_stream *stream)
+{
+}
+
+#endif
 
 /*
  * initialize the substream instance.
@@ -2509,6 +2550,8 @@ #endif
    return 0;
 }
 
+static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
+                int iface, int altno);
 static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
 {
    struct usb_device *dev;
@@ -2543,6 +2586,12 @@ static int parse_audio_endpoints(struct 
       stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ?
          SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
       altno = altsd->bAlternateSetting;
+   
+      /* audiophile usb: skip altsets incompatible with device_setup
+       */
+      if (chip->usb_id == USB_ID(0x0763, 0x2003) && 
+          audiophile_skip_setting_quirk(chip, iface_no, altno))
+         continue;
 
       /* get audio formats */
       fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, AS_GENERAL);
@@ -2637,7 +2686,7 @@ static int parse_audio_endpoints(struct 
          continue;
       }
 
-      snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint 0x%x\n", dev->devnum, iface_no, i, fp->endpoint);
+      snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint 0x%x\n", dev->devnum, iface_no, altno, fp->endpoint);
       err = add_audio_endpoint(chip, stream, fp);
       if (err < 0) {
          kfree(fp->rate_table);
@@ -3045,6 +3094,45 @@ static int snd_usb_audigy2nx_boot_quirk(
    return 0;
 }
 
+/*
+ * Setup quirks
+ */
+#define AUDIOPHILE_SET         0x01 /* if set, parse device_setup */
+#define AUDIOPHILE_SET_DTS              0x02 /* if set, enable DTS Digital Output */
+#define AUDIOPHILE_SET_96K              0x04 /* 48-96KHz rate if set, 8-48KHz otherwise */
+#define AUDIOPHILE_SET_24B      0x08 /* 24bits sample if set, 16bits otherwise */
+#define AUDIOPHILE_SET_DI      0x10 /* if set, enable Digital Input */
+#define AUDIOPHILE_SET_MASK      0x1F /* bit mask for setup value */
+#define AUDIOPHILE_SET_24B_48K_DI   0x19 /* value for 24bits+48KHz+Digital Input */
+#define AUDIOPHILE_SET_24B_48K_NOTDI   0x09 /* value for 24bits+48KHz+No Digital Input */
+#define AUDIOPHILE_SET_16B_48K_DI   0x11 /* value for 16bits+48KHz+Digital Input */
+#define AUDIOPHILE_SET_16B_48K_NOTDI   0x01 /* value for 16bits+48KHz+No Digital Input */
+
+static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
+                int iface, int altno)
+{
+   if (device_setup[chip->index] & AUDIOPHILE_SET) {
+      if ((device_setup[chip->index] & AUDIOPHILE_SET_DTS)
+          && altno != 6)
+         return 1; /* skip this altsetting */
+      if ((device_setup[chip->index] & AUDIOPHILE_SET_96K)
+          && altno != 1)
+         return 1; /* skip this altsetting */
+      if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) ==
+          AUDIOPHILE_SET_24B_48K_DI && altno != 2)
+         return 1; /* skip this altsetting */
+      if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) ==
+          AUDIOPHILE_SET_24B_48K_NOTDI && altno != 3)
+         return 1; /* skip this altsetting */
+      if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) ==
+          AUDIOPHILE_SET_16B_48K_DI && altno != 4)
+         return 1; /* skip this altsetting */
+      if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) ==
+          AUDIOPHILE_SET_16B_48K_NOTDI && altno != 5)
+         return 1; /* skip this altsetting */
+   }   
+   return 0; /* keep this altsetting */
+}
 
 /*
  * audio-interface quirks
@@ -3070,7 +3158,7 @@ static int snd_usb_create_quirk(struct s
       [QUIRK_MIDI_NOVATION] = snd_usb_create_midi_interface,
       [QUIRK_MIDI_RAW] = snd_usb_create_midi_interface,
       [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface,
-      [QUIRK_MIDI_MIDITECH] = snd_usb_create_midi_interface,
+      [QUIRK_MIDI_CME] = snd_usb_create_midi_interface,
       [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
       [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
       [QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk,
@@ -3282,7 +3370,7 @@ static void *snd_usb_audio_probe(struct 
 
    /* check whether it's already registered */
    chip = NULL;
-   down(®ister_mutex);
+   mutex_lock(®ister_mutex);
    for (i = 0; i < SNDRV_CARDS; i++) {
       if (usb_chip[i] && usb_chip[i]->dev == dev) {
          if (usb_chip[i]->shutdown) {
@@ -3335,13 +3423,13 @@ static void *snd_usb_audio_probe(struct 
 
    usb_chip[chip->index] = chip;
    chip->num_interfaces++;
-   up(®ister_mutex);
+   mutex_unlock(®ister_mutex);
    return chip;
 
  __error:
    if (chip && !chip->num_interfaces)
       snd_card_free(chip->card);
-   up(®ister_mutex);
+   mutex_unlock(®ister_mutex);
  __err_val:
    return NULL;
 }
@@ -3361,7 +3449,7 @@ static void snd_usb_audio_disconnect(str
 
    chip = ptr;
    card = chip->card;
-   down(®ister_mutex);
+   mutex_lock(®ister_mutex);
    chip->shutdown = 1;
    chip->num_interfaces--;
    if (chip->num_interfaces <= 0) {
@@ -3379,10 +3467,10 @@ static void snd_usb_audio_disconnect(str
          snd_usb_mixer_disconnect(p);
       }
       usb_chip[chip->index] = NULL;
-      up(®ister_mutex);
+      mutex_unlock(®ister_mutex);
       snd_card_free(card);
    } else {
-      up(®ister_mutex);
+      mutex_unlock(®ister_mutex);
    }
 }
 


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.