From c1ab5d59a0ff0981828a169886b10045dfdf64c6 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 30 Mar 2005 16:22:01 +0200 Subject: [ALSA] usb-audio - allow USB MIDI quirks to specify endpoints explicitly USB generic driver This patch reintroduces the check for endpoint numbers that are specified explicitly in the quirk structure. This check was accidentally dropped in the last rewrite of snd_usbmidi_detect_endpoints(). Signed-off-by: Clemens Ladisch --- sound/usb/usbmidi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/usb') diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 5d32857ff95..600d990ddc9 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -1229,6 +1229,9 @@ static int snd_usbmidi_detect_endpoints(snd_usb_midi_t* umidi, if (le16_to_cpu(umidi->chip->dev->descriptor.idVendor) == 0x0582) snd_usbmidi_switch_roland_altsetting(umidi); + if (endpoint[0].out_ep || endpoint[0].in_ep) + return 0; + intf = umidi->iface; if (!intf || intf->num_altsetting < 1) return -ENOENT; -- cgit From 54ab87e6f53099b9a480b56149fa621c3132c076 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 1 Apr 2005 13:14:14 +0200 Subject: [ALSA] Add mixer map for Sound Blaster MP3+ USB generic driver Added the mixer mapping for Sound Blaster MP3+ by Pavel Mihaylov Signed-off-by: Takashi Iwai --- sound/usb/usbmixer_maps.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'sound/usb') diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index c69b4b0875f..1e994c9d86d 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -91,6 +91,33 @@ static struct usbmix_name_map extigy_map[] = { { 0 } /* terminator */ }; +/* Sound Blaster MP3+ controls mapping + * The default mixer channels have totally misleading names, + * e.g. no Master and fake PCM volume + * Pavel Mihaylov + */ +static struct usbmix_name_map mp3plus_map[] = { + /* 1: IT pcm */ + /* 2: IT mic */ + /* 3: IT line */ + /* 4: IT digital in */ + /* 5: OT digital out */ + /* 6: OT speaker */ + /* 7: OT pcm capture */ + { 8, "Capture Input Source" }, /* FU, default PCM Capture Source */ + /* (Mic, Input 1 = Line input, Input 2 = Optical input) */ + { 9, "Master Playback" }, /* FU, default Speaker 1 */ + /* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */ + /* { 10, "Mic Capture", 2 }, */ /* FU, Mic Capture */ + { 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */ + { 11, "Line Capture" }, /* FU, default PCM Capture */ + { 12, "Digital In Playback" }, /* FU, default PCM 1 */ + /* { 13, "Mic Playback" }, */ /* FU, default Mic Playback */ + { 14, "Line Playback" }, /* FU, default Speaker */ + /* 15: MU */ + { 0 } /* terminator */ +}; + /* LineX FM Transmitter entry - needed to bypass controls bug */ static struct usbmix_name_map linex_map[] = { /* 1: IT pcm */ @@ -128,6 +155,7 @@ static struct usbmix_name_map justlink_map[] = { static struct usbmix_ctl_map usbmix_ctl_maps[] = { { 0x41e, 0x3000, extigy_map, 1 }, + { 0x41e, 0x3010, mp3plus_map, 0 }, { 0x8bb, 0x2702, linex_map, 1 }, { 0xc45, 0x1158, justlink_map, 0 }, { 0 } /* terminator */ -- cgit From 5af4c83375cba113fb7e1ed57024a5442ca5060e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 6 Apr 2005 09:47:02 +0200 Subject: [ALSA] usb-audio - BOSS GS-10 PCM support USB generic driver This patch adds quirks to support 24-bit PCM I/O in the 'Advanced Driver' mode of the BOSS GS-10. Signed-off-by: Clemens Ladisch --- sound/usb/usbquirks.h | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 88bbd944d4b..00781fea211 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -609,15 +609,33 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* + * This quirk is for the "Advanced Driver" mode. If off, the GS-10 + * has ID 0x003c and is standard compliant, but has only 16-bit PCM + * and no MIDI. + */ USB_DEVICE_VENDOR_SPEC(0x0582, 0x003b), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "BOSS", .product_name = "GS-10", - .ifnum = 3, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0003, - .in_cables = 0x0003 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = & (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 3, + .type = QUIRK_MIDI_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } } } }, -- cgit From 230cd5e24853ed4dd960461989b8ed0986d37a99 Mon Sep 17 00:00:00 2001 From: Karsten Wiese Date: Wed, 20 Apr 2005 10:12:35 +0200 Subject: [ALSA] prevent oops & dead keyboard on usb unplugging while the device is being used USB generic driver,USB USX2Y Without this patch, some usb kobjects, which are parents to the usx2y's kobjects can be freed before the usx2y's. This led to an oops in get_kobj_path_length() and a dead keyboard, when the usx2y's kobjects were freed. The patch ensures the correct sequence. Tested ok on kernel 2.6.12-rc2. Signed-off-by: Karsten Wiese Signed-off-by: Takashi Iwai --- sound/usb/usbaudio.c | 2 +- sound/usb/usx2y/usbusx2y.c | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 84b0bbddbd2..aae66144d41 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -3289,7 +3289,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) } usb_chip[chip->index] = NULL; up(®ister_mutex); - snd_card_free_in_thread(card); + snd_card_free(card); } else { up(®ister_mutex); } diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index b06a267e5da..89ee8b73201 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -1,6 +1,11 @@ /* * usbusy2y.c - ALSA USB US-428 Driver * +2005-04-14 Karsten Wiese + Version 0.8.7.2: + Call snd_card_free() instead of snd_card_free_in_thread() to prevent oops with dead keyboard symptom. + Tested ok with kernel 2.6.12-rc2. + 2004-12-14 Karsten Wiese Version 0.8.7.1: snd_pcm_open for rawusb pcm-devices now returns -EBUSY if called without rawusb's hwdep device being open. @@ -143,7 +148,7 @@ MODULE_AUTHOR("Karsten Wiese "); -MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.1"); +MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.2"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604), "NAME_ALLCAPS"(0x8001)(0x8005)(0x8007) }}"); @@ -430,8 +435,6 @@ static void usX2Y_usb_disconnect(struct usb_device* device, void* ptr) if (ptr) { usX2Ydev_t* usX2Y = usX2Y((snd_card_t*)ptr); struct list_head* p; - if (usX2Y->chip_status == USX2Y_STAT_CHIP_HUP) // on 2.6.1 kernel snd_usbmidi_disconnect() - return; // calls us back. better leave :-) . usX2Y->chip.shutdown = 1; usX2Y->chip_status = USX2Y_STAT_CHIP_HUP; usX2Y_unlinkSeq(&usX2Y->AS04); @@ -443,7 +446,7 @@ static void usX2Y_usb_disconnect(struct usb_device* device, void* ptr) } if (usX2Y->us428ctls_sharedmem) wake_up(&usX2Y->us428ctls_wait_queue_head); - snd_card_free_in_thread((snd_card_t*)ptr); + snd_card_free((snd_card_t*)ptr); } } -- cgit From 863ad944b9a32dc43baa76143275411824d5928e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 22 Apr 2005 08:52:03 +0200 Subject: [ALSA] usb-audio: add Audigy 2 NX control names USB generic driver Add a mixer control map for the SB Audigy 2 NX so that we get meaningful mixer control names. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer_maps.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'sound/usb') diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 1e994c9d86d..4918a185422 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -118,6 +118,50 @@ static struct usbmix_name_map mp3plus_map[] = { { 0 } /* terminator */ }; +/* Topology of SB Audigy 2 NX + + +----------------------------->EU[27]--+ + | v + | +----------------------------------->SU[29]---->FU[22]-->Dig_OUT[24] + | | ^ +USB_IN[1]-+------------+ +->EU[17]->+->FU[11]-+ + | v | v | +Dig_IN[4]---+->FU[6]-->MU[16]->FU[18]-+->EU[21]->SU[31]----->FU[30]->Hph_OUT[20] + | ^ | | +Lin_IN[7]-+--->FU[8]---+ +->EU[23]->FU[28]------------->Spk_OUT[19] + | | v + +--->FU[12]------------------------------------->SU[14]--->USB_OUT[15] + | ^ + +->FU[13]--------------------------------------+ +*/ +static struct usbmix_name_map audigy2nx_map[] = { + /* 1: IT pcm playback */ + /* 4: IT digital in */ + { 6, "Digital In Playback" }, /* FU */ + /* 7: IT line in */ + { 8, "Line Playback" }, /* FU */ + { 11, "What-U-Hear Capture" }, /* FU */ + { 12, "Line Capture" }, /* FU */ + { 13, "Digital In Capture" }, /* FU */ + { 14, "Capture Source" }, /* SU */ + /* 15: OT pcm capture */ + /* 16: MU w/o controls */ + { 17, NULL }, /* DISABLED: EU (for what?) */ + { 18, "Master Playback" }, /* FU */ + /* 19: OT speaker */ + /* 20: OT headphone */ + { 21, NULL }, /* DISABLED: EU (for what?) */ + { 22, "Digital Out Playback" }, /* FU */ + { 23, NULL }, /* DISABLED: EU (for what?) */ + /* 24: OT digital out */ + { 27, NULL }, /* DISABLED: EU (for what?) */ + { 28, "Speaker Playback" }, /* FU */ + { 29, "Digital Out Source" }, /* SU */ + { 30, "Headphone Playback" }, /* FU */ + { 31, "Headphone Source" }, /* SU */ + { 0 } /* terminator */ +}; + /* LineX FM Transmitter entry - needed to bypass controls bug */ static struct usbmix_name_map linex_map[] = { /* 1: IT pcm */ @@ -156,6 +200,7 @@ static struct usbmix_name_map justlink_map[] = { static struct usbmix_ctl_map usbmix_ctl_maps[] = { { 0x41e, 0x3000, extigy_map, 1 }, { 0x41e, 0x3010, mp3plus_map, 0 }, + { 0x41e, 0x3020, audigy2nx_map, 0 }, { 0x8bb, 0x2702, linex_map, 1 }, { 0xc45, 0x1158, justlink_map, 0 }, { 0 } /* terminator */ -- cgit From 08fe15899df9696a6d34abf96230ae0691f5de66 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 22 Apr 2005 15:33:01 +0200 Subject: [ALSA] usb-audio - show exact synchronous frequency in proc file USB generic driver In the streamX proc file, show the exact number of samples per USB frame as 16.16 hexadecimal floating point value. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index aae66144d41..a7183c5876b 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -1990,10 +1990,11 @@ static void proc_dump_substream_status(snd_usb_substream_t *subs, snd_info_buffe snd_iprintf(buffer, "%d ", subs->dataurb[i].packets); snd_iprintf(buffer, "]\n"); snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize); - snd_iprintf(buffer, " Momentary freq = %u Hz\n", + snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n", snd_usb_get_speed(subs->dev) == USB_SPEED_FULL ? get_full_speed_hz(subs->freqm) - : get_high_speed_hz(subs->freqm)); + : get_high_speed_hz(subs->freqm), + subs->freqm >> 16, subs->freqm & 0xffff); } else { snd_iprintf(buffer, " Status: Stop\n"); } -- cgit From 8e062ec7108f8a91149e6bccddc3b7341e406274 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 22 Apr 2005 15:49:52 +0200 Subject: [ALSA] usb-audio - add selector unit names override for Audigy 2 NX USB generic driver Add a mechanism to specify source names of selector units, and add such names for the SB Audigy 2 NX. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 21 +++++++++++++++++- sound/usb/usbmixer_maps.c | 54 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 69 insertions(+), 6 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 5f1906915aa..6ad154aaba1 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -70,6 +70,7 @@ struct usb_mixer_build { DECLARE_BITMAP(unitbitmap, 32*32); usb_audio_term_t oterm; const struct usbmix_name_map *map; + const struct usbmix_selector_map *selector_map; }; struct usb_mixer_elem_info { @@ -187,6 +188,21 @@ static int check_ignored_ctl(mixer_build_t *state, int unitid, int control) return 0; } +/* get the mapped selector source name */ +static int check_mapped_selector_name(mixer_build_t *state, int unitid, + int index, char *buf, int buflen) +{ + const struct usbmix_selector_map *p; + + if (! state->selector_map) + return 0; + for (p = state->selector_map; p->id; p++) { + if (p->id == unitid && index < p->count) + return strlcpy(buf, p->names[index], buflen); + } + return 0; +} + /* * find an audio control unit with the given unit id */ @@ -1415,7 +1431,9 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned kfree(cval); return -ENOMEM; } - if (check_input_term(state, desc[5 + i], &iterm) >= 0) + len = check_mapped_selector_name(state, unitid, i, namelist[i], + MAX_ITEM_NAME_LEN); + if (! len && check_input_term(state, desc[5 + i], &iterm) >= 0) len = get_term_name(state, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0); if (! len) sprintf(namelist[i], "Input %d", i); @@ -1521,6 +1539,7 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) for (map = usbmix_ctl_maps; map->vendor; map++) { if (map->vendor == state.vendor && map->product == state.product) { state.map = map->map; + state.selector_map = map->selector_map; chip->ignore_ctl_error = map->ignore_ctl_error; break; } diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 4918a185422..adb0abb3ee8 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -26,10 +26,17 @@ struct usbmix_name_map { int control; }; +struct usbmix_selector_map { + int id; + int count; + const char **names; +}; + struct usbmix_ctl_map { int vendor; int product; const struct usbmix_name_map *map; + const struct usbmix_selector_map *selector_map; int ignore_ctl_error; }; @@ -162,6 +169,25 @@ static struct usbmix_name_map audigy2nx_map[] = { { 0 } /* terminator */ }; +static struct usbmix_selector_map audigy2nx_selectors[] = { + { + .id = 14, /* Capture Source */ + .count = 3, + .names = (const char*[]) {"Line", "Digital In", "What-U-Hear"} + }, + { + .id = 29, /* Digital Out Source */ + .count = 3, + .names = (const char*[]) {"Front", "PCM", "Digital In"} + }, + { + .id = 31, /* Headphone Source */ + .count = 2, + .names = (const char*[]) {"Front", "Side"} + }, + { 0 } /* terminator */ +}; + /* LineX FM Transmitter entry - needed to bypass controls bug */ static struct usbmix_name_map linex_map[] = { /* 1: IT pcm */ @@ -198,11 +224,29 @@ static struct usbmix_name_map justlink_map[] = { */ static struct usbmix_ctl_map usbmix_ctl_maps[] = { - { 0x41e, 0x3000, extigy_map, 1 }, - { 0x41e, 0x3010, mp3plus_map, 0 }, - { 0x41e, 0x3020, audigy2nx_map, 0 }, - { 0x8bb, 0x2702, linex_map, 1 }, - { 0xc45, 0x1158, justlink_map, 0 }, + { + .vendor = 0x41e, .product = 0x3000, + .map = extigy_map, + .ignore_ctl_error = 1, + }, + { + .vendor = 0x41e, .product = 0x3010, + .map = mp3plus_map, + }, + { + .vendor = 0x41e, .product = 0x3020, + .map = audigy2nx_map, + .selector_map = audigy2nx_selectors, + }, + { + .vendor = 0x8bb, .product = 0x2702, + .map = linex_map, + .ignore_ctl_error = 1, + }, + { + .vendor = 0xc45, .product = 0x1158, + .map = justlink_map, + }, { 0 } /* terminator */ }; -- cgit From ee7333970bee3e7565feeb3edfef4db81cbe72e5 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 25 Apr 2005 10:34:13 +0200 Subject: [ALSA] usb-audio - remove superfluous parameter USB generic driver,USB USX2Y This patch removes the superfluous driver parameter from the disconnect functions. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 6 +++--- sound/usb/usbaudio.h | 2 +- sound/usb/usbmidi.c | 2 +- sound/usb/usx2y/usbusx2y.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a7183c5876b..08c5efcf5be 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2588,7 +2588,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) * disconnect streams * called from snd_usb_audio_disconnect() */ -static void snd_usb_stream_disconnect(struct list_head *head, struct usb_driver *driver) +static void snd_usb_stream_disconnect(struct list_head *head) { int idx; snd_usb_stream_t *as; @@ -3282,11 +3282,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) snd_card_disconnect(card); /* release the pcm resources */ list_for_each(p, &chip->pcm_list) { - snd_usb_stream_disconnect(p, &usb_audio_driver); + snd_usb_stream_disconnect(p); } /* release the midi resources */ list_for_each(p, &chip->midi_list) { - snd_usbmidi_disconnect(p, &usb_audio_driver); + snd_usbmidi_disconnect(p); } usb_chip[chip->index] = NULL; up(®ister_mutex); diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index eecbf19fcb6..14f7cf7e363 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -223,7 +223,7 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif); int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk); void snd_usbmidi_input_stop(struct list_head* p); void snd_usbmidi_input_start(struct list_head* p); -void snd_usbmidi_disconnect(struct list_head *p, struct usb_driver *driver); +void snd_usbmidi_disconnect(struct list_head *p); /* * retrieve usb_interface descriptor from the host interface diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 600d990ddc9..304a13451ec 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -912,7 +912,7 @@ static void snd_usbmidi_free(snd_usb_midi_t* umidi) /* * Unlinks all URBs (must be done before the usb_device is deleted). */ -void snd_usbmidi_disconnect(struct list_head* p, struct usb_driver *driver) +void snd_usbmidi_disconnect(struct list_head* p) { snd_usb_midi_t* umidi; int i; diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index 89ee8b73201..e6e6da15967 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -442,7 +442,7 @@ static void usX2Y_usb_disconnect(struct usb_device* device, void* ptr) snd_card_disconnect((snd_card_t*)ptr); /* release the midi resources */ list_for_each(p, &usX2Y->chip.midi_list) { - snd_usbmidi_disconnect(p, &snd_usX2Y_usb_driver); + snd_usbmidi_disconnect(p); } if (usX2Y->us428ctls_sharedmem) wake_up(&usX2Y->us428ctls_wait_queue_head); -- cgit From 8c1872dcf29e2a194197e1d5a9c366a265986b84 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 28 Apr 2005 09:31:53 +0200 Subject: [ALSA] usb-audio - restrict Audigy 2 NX frequencies to 48/96 kHz USB generic driver On the SB Audigy 2 NX, frequency feedback doesn't quite work when playing at 44.1 kHz, so temporarily disable this frequency. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 08c5efcf5be..e4b91045ca1 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2422,15 +2422,17 @@ static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, if (err < 0) return err; #if 1 - /* FIXME: temporary hack for extigy */ + /* FIXME: temporary hack for extigy/audigy 2 nx */ /* extigy apparently supports sample rates other than 48k * but not in ordinary way. so we enable only 48k atm. */ if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e && - le16_to_cpu(dev->descriptor.idProduct) == 0x3000) { + (le16_to_cpu(dev->descriptor.idProduct) == 0x3000 || + le16_to_cpu(dev->descriptor.idProduct) == 0x3020)) { if (fmt[3] == USB_FORMAT_TYPE_I && stream == SNDRV_PCM_STREAM_PLAYBACK && - fp->rates != SNDRV_PCM_RATE_48000) + fp->rates != SNDRV_PCM_RATE_48000 && + fp->rates != SNDRV_PCM_RATE_96000) return -1; /* use 48k only */ } #endif -- cgit From 707e60732fc25fe3760f916d083b262a86a666c0 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 29 Apr 2005 09:56:17 +0200 Subject: [ALSA] usb-audio - reduce size of unitbitmap array USB generic driver Unit/terminal IDs are 8-bit integers, so the unitbitmap variable does not need to be bigger than 256 bits. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/usb') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 6ad154aaba1..e601f4ba5f2 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -67,7 +67,7 @@ struct usb_mixer_build { unsigned int ctrlif; unsigned short vendor; unsigned short product; - DECLARE_BITMAP(unitbitmap, 32*32); + DECLARE_BITMAP(unitbitmap, 256); usb_audio_term_t oterm; const struct usbmix_name_map *map; const struct usbmix_selector_map *selector_map; -- cgit From 84957a8ab086377a025e0448fa716ed5983f3c3a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 29 Apr 2005 16:23:13 +0200 Subject: [ALSA] usb-audio - move mixer data into separate struct USB generic driver Move all data related to audio control interfaces into a separate struct local to usbmixer.c. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 5 ++ sound/usb/usbaudio.h | 3 +- sound/usb/usbmixer.c | 142 +++++++++++++++++++++++++++++++++++---------------- 3 files changed, 105 insertions(+), 45 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index e4b91045ca1..eeb09bb8cbf 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -3091,6 +3091,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, chip->card = card; INIT_LIST_HEAD(&chip->pcm_list); INIT_LIST_HEAD(&chip->midi_list); + INIT_LIST_HEAD(&chip->mixer_list); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_usb_audio_free(chip); @@ -3290,6 +3291,10 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) list_for_each(p, &chip->midi_list) { snd_usbmidi_disconnect(p); } + /* release mixer resources */ + list_for_each(p, &chip->mixer_list) { + snd_usb_mixer_disconnect(p); + } usb_chip[chip->index] = NULL; up(®ister_mutex); snd_card_free(card); diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 14f7cf7e363..41d842dab3e 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -136,7 +136,7 @@ struct snd_usb_audio { struct list_head midi_list; /* list of midi interfaces */ int next_midi_device; - unsigned int ignore_ctl_error; /* for mixer */ + struct list_head mixer_list; /* list of mixer interfaces */ }; /* @@ -219,6 +219,7 @@ void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsub int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout); int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif); +void snd_usb_mixer_disconnect(struct list_head *p); int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk); void snd_usbmidi_input_stop(struct list_head* p); diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index e601f4ba5f2..7bbccebd76c 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -50,6 +50,14 @@ typedef struct usb_audio_term usb_audio_term_t; typedef struct usb_mixer_elem_info usb_mixer_elem_info_t; +struct usb_mixer_interface { + snd_usb_audio_t *chip; + unsigned int ctrlif; + struct list_head list; + unsigned int ignore_ctl_error; +}; + + struct usb_audio_term { int id; int type; @@ -62,9 +70,9 @@ struct usbmix_name_map; struct usb_mixer_build { snd_usb_audio_t *chip; + struct usb_mixer_interface *mixer; unsigned char *buffer; unsigned int buflen; - unsigned int ctrlif; unsigned short vendor; unsigned short product; DECLARE_BITMAP(unitbitmap, 256); @@ -74,8 +82,7 @@ struct usb_mixer_build { }; struct usb_mixer_elem_info { - snd_usb_audio_t *chip; - unsigned int ctrlif; + struct usb_mixer_interface *mixer; unsigned int id; unsigned int control; /* CS or ICN (high byte) */ unsigned int cmask; /* channel mask bitmap: 0 = master */ @@ -317,16 +324,18 @@ static int get_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i int timeout = 10; while (timeout-- > 0) { - if (snd_usb_ctl_msg(cval->chip->dev, usb_rcvctrlpipe(cval->chip->dev, 0), + if (snd_usb_ctl_msg(cval->mixer->chip->dev, + usb_rcvctrlpipe(cval->mixer->chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - validx, cval->ctrlif | (cval->id << 8), + validx, cval->mixer->ctrlif | (cval->id << 8), buf, val_len, 100) >= 0) { *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); return 0; } } - snd_printdd(KERN_ERR "cannot get ctl value: req = 0x%x, wValue = 0x%x, wIndex = 0x%x, type = %d\n", request, validx, cval->ctrlif | (cval->id << 8), cval->val_type); + snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", + request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); return -EINVAL; } @@ -355,13 +364,15 @@ static int set_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i buf[0] = value_set & 0xff; buf[1] = (value_set >> 8) & 0xff; while (timeout -- > 0) - if (snd_usb_ctl_msg(cval->chip->dev, usb_sndctrlpipe(cval->chip->dev, 0), + if (snd_usb_ctl_msg(cval->mixer->chip->dev, + usb_sndctrlpipe(cval->mixer->chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - validx, cval->ctrlif | (cval->id << 8), + validx, cval->mixer->ctrlif | (cval->id << 8), buf, val_len, 100) >= 0) return 0; - snd_printdd(KERN_ERR "cannot set ctl value: req = 0x%x, wValue = 0x%x, wIndex = 0x%x, type = %d, data = 0x%x/0x%x\n", request, validx, cval->ctrlif | (cval->id << 8), cval->val_type, buf[0], buf[1]); + snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n", + request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type, buf[0], buf[1]); return -EINVAL; } @@ -401,12 +412,13 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou * if failed, give up and free the control instance. */ -static int add_control_to_empty(snd_card_t *card, snd_kcontrol_t *kctl) +static int add_control_to_empty(mixer_build_t *state, snd_kcontrol_t *kctl) { int err; - while (snd_ctl_find_id(card, &kctl->id)) + + while (snd_ctl_find_id(state->chip->card, &kctl->id)) kctl->id.index++; - if ((err = snd_ctl_add(card, kctl)) < 0) { + if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) { snd_printd(KERN_ERR "cannot add control (err = %d)\n", err); snd_ctl_free_one(kctl); } @@ -624,7 +636,8 @@ static int get_min_max(usb_mixer_elem_info_t *cval, int default_min) } if (get_ctl_value(cval, GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || get_ctl_value(cval, GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { - snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", cval->id, cval->ctrlif, cval->control, cval->id); + snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", + cval->id, cval->mixer->ctrlif, cval->control, cval->id); return -EINVAL; } if (get_ctl_value(cval, GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { @@ -684,7 +697,7 @@ static int mixer_ctl_feature_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t if (cval->cmask & (1 << c)) { err = get_cur_mix_value(cval, c + 1, &val); if (err < 0) { - if (cval->chip->ignore_ctl_error) { + if (cval->mixer->ignore_ctl_error) { ucontrol->value.integer.value[0] = cval->min; return 0; } @@ -700,7 +713,7 @@ static int mixer_ctl_feature_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t /* master channel */ err = get_cur_mix_value(cval, 0, &val); if (err < 0) { - if (cval->chip->ignore_ctl_error) { + if (cval->mixer->ignore_ctl_error) { ucontrol->value.integer.value[0] = cval->min; return 0; } @@ -726,7 +739,7 @@ static int mixer_ctl_feature_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t if (cval->cmask & (1 << c)) { err = get_cur_mix_value(cval, c + 1, &oval); if (err < 0) { - if (cval->chip->ignore_ctl_error) + if (cval->mixer->ignore_ctl_error) return 0; return err; } @@ -743,7 +756,7 @@ static int mixer_ctl_feature_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t } else { /* master channel */ err = get_cur_mix_value(cval, 0, &oval); - if (err < 0 && cval->chip->ignore_ctl_error) + if (err < 0 && cval->mixer->ignore_ctl_error) return 0; if (err < 0) return err; @@ -795,8 +808,7 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return; } - cval->chip = state->chip; - cval->ctrlif = state->ctrlif; + cval->mixer = state->mixer; cval->id = unitid; cval->control = control; cval->cmask = ctl_mask; @@ -880,7 +892,7 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res); - add_control_to_empty(state->chip->card, kctl); + add_control_to_empty(state, kctl); } @@ -963,8 +975,7 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc, if (! cval) return; - cval->chip = state->chip; - cval->ctrlif = state->ctrlif; + cval->mixer = state->mixer; cval->id = unitid; cval->control = in_ch + 1; /* based on 1 */ cval->val_type = USB_MIXER_S16; @@ -995,7 +1006,7 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc, snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max); - add_control_to_empty(state->chip->card, kctl); + add_control_to_empty(state, kctl); } @@ -1058,7 +1069,7 @@ static int mixer_ctl_procunit_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t int err, val; err = get_cur_ctl_value(cval, cval->control << 8, &val); - if (err < 0 && cval->chip->ignore_ctl_error) { + if (err < 0 && cval->mixer->ignore_ctl_error) { ucontrol->value.integer.value[0] = cval->min; return 0; } @@ -1077,7 +1088,7 @@ static int mixer_ctl_procunit_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t err = get_cur_ctl_value(cval, cval->control << 8, &oval); if (err < 0) { - if (cval->chip->ignore_ctl_error) + if (cval->mixer->ignore_ctl_error) return 0; return err; } @@ -1215,8 +1226,7 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return -ENOMEM; } - cval->chip = state->chip; - cval->ctrlif = state->ctrlif; + cval->mixer = state->mixer; cval->id = unitid; cval->control = valinfo->control; cval->val_type = valinfo->val_type; @@ -1257,7 +1267,7 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max); - if ((err = add_control_to_empty(state->chip->card, kctl)) < 0) + if ((err = add_control_to_empty(state, kctl)) < 0) return err; } return 0; @@ -1305,7 +1315,7 @@ static int mixer_ctl_selector_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t err = get_cur_ctl_value(cval, 0, &val); if (err < 0) { - if (cval->chip->ignore_ctl_error) { + if (cval->mixer->ignore_ctl_error) { ucontrol->value.enumerated.item[0] = 0; return 0; } @@ -1324,7 +1334,7 @@ static int mixer_ctl_selector_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t err = get_cur_ctl_value(cval, 0, &oval); if (err < 0) { - if (cval->chip->ignore_ctl_error) + if (cval->mixer->ignore_ctl_error) return 0; return err; } @@ -1402,8 +1412,7 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return -ENOMEM; } - cval->chip = state->chip; - cval->ctrlif = state->ctrlif; + cval->mixer = state->mixer; cval->id = unitid; cval->val_type = USB_MIXER_U8; cval->channels = 1; @@ -1468,7 +1477,7 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", cval->id, kctl->id.name, num_ins); - if ((err = add_control_to_empty(state->chip->card, kctl)) < 0) + if ((err = add_control_to_empty(state, kctl)) < 0) return err; return 0; @@ -1511,27 +1520,38 @@ static int parse_audio_unit(mixer_build_t *state, int unitid) } } +static void snd_usb_mixer_free(struct usb_mixer_interface *mixer) +{ + kfree(mixer); +} + +static int snd_usb_mixer_dev_free(snd_device_t *device) +{ + struct usb_mixer_interface *mixer = device->device_data; + snd_usb_mixer_free(mixer); + return 0; +} + /* * create mixer controls * * walk through all OUTPUT_TERMINAL descriptors to search for mixers */ -int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) +static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) { unsigned char *desc; mixer_build_t state; int err; const struct usbmix_ctl_map *map; - struct usb_device_descriptor *dev = &chip->dev->descriptor; - struct usb_host_interface *hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; - - strcpy(chip->card->mixername, "USB Mixer"); + struct usb_device_descriptor *dev = &mixer->chip->dev->descriptor; + struct usb_host_interface *hostif; + hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0]; memset(&state, 0, sizeof(state)); - state.chip = chip; + state.chip = mixer->chip; + state.mixer = mixer; state.buffer = hostif->extra; state.buflen = hostif->extralen; - state.ctrlif = ctrlif; state.vendor = le16_to_cpu(dev->idVendor); state.product = le16_to_cpu(dev->idProduct); @@ -1540,13 +1560,10 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) if (map->vendor == state.vendor && map->product == state.product) { state.map = map->map; state.selector_map = map->selector_map; - chip->ignore_ctl_error = map->ignore_ctl_error; + mixer->ignore_ctl_error = map->ignore_ctl_error; break; } } -#ifdef IGNORE_CTL_ERROR - chip->ignore_ctl_error = 1; -#endif desc = NULL; while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, OUTPUT_TERMINAL)) != NULL) { @@ -1562,3 +1579,40 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) } return 0; } + +int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) +{ + static snd_device_ops_t dev_ops = { + .dev_free = snd_usb_mixer_dev_free + }; + struct usb_mixer_interface *mixer; + int err; + + strcpy(chip->card->mixername, "USB Mixer"); + + mixer = kcalloc(1, sizeof(*mixer), GFP_KERNEL); + if (!mixer) + return -ENOMEM; + mixer->chip = chip; + mixer->ctrlif = ctrlif; +#ifdef IGNORE_CTL_ERROR + mixer->ignore_ctl_error = 1; +#endif + + if ((err = snd_usb_mixer_controls(mixer)) < 0) { + snd_usb_mixer_free(mixer); + return err; + } + + err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); + if (err < 0) { + snd_usb_mixer_free(mixer); + return err; + } + list_add(&mixer->list, &chip->mixer_list); + return 0; +} + +void snd_usb_mixer_disconnect(struct list_head *p) +{ +} -- cgit From 6639b6c2367f884ca172b78d69f7da17bfab2e5e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 29 Apr 2005 16:26:14 +0200 Subject: [ALSA] usb-audio - add mixer control notifications USB generic driver Add support for the optional status interrupt endpoint in audio control interfaces, and translate USB status notifications into ALSA mixer control notifications. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 98 insertions(+), 3 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 7bbccebd76c..dd045ea6fb0 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -55,6 +55,8 @@ struct usb_mixer_interface { unsigned int ctrlif; struct list_head list; unsigned int ignore_ctl_error; + struct urb *urb; + usb_mixer_elem_info_t **id_elems; /* array[256], indexed by unit id */ }; @@ -83,13 +85,15 @@ struct usb_mixer_build { struct usb_mixer_elem_info { struct usb_mixer_interface *mixer; + usb_mixer_elem_info_t *next_id_elem; /* list of controls with same id */ + snd_ctl_elem_id_t *elem_id; unsigned int id; unsigned int control; /* CS or ICN (high byte) */ unsigned int cmask; /* channel mask bitmap: 0 = master */ int channels; int val_type; int min, max, res; - unsigned int initialized: 1; + u8 initialized; }; @@ -414,6 +418,7 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou static int add_control_to_empty(mixer_build_t *state, snd_kcontrol_t *kctl) { + usb_mixer_elem_info_t *cval = kctl->private_data; int err; while (snd_ctl_find_id(state->chip->card, &kctl->id)) @@ -421,8 +426,12 @@ static int add_control_to_empty(mixer_build_t *state, snd_kcontrol_t *kctl) if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) { snd_printd(KERN_ERR "cannot add control (err = %d)\n", err); snd_ctl_free_one(kctl); + return err; } - return err; + cval->elem_id = &kctl->id; + cval->next_id_elem = state->mixer->id_elems[cval->id]; + state->mixer->id_elems[cval->id] = cval; + return 0; } @@ -1522,6 +1531,11 @@ static int parse_audio_unit(mixer_build_t *state, int unitid) static void snd_usb_mixer_free(struct usb_mixer_interface *mixer) { + kfree(mixer->id_elems); + if (mixer->urb) { + kfree(mixer->urb->transfer_buffer); + usb_free_urb(mixer->urb); + } kfree(mixer); } @@ -1580,6 +1594,76 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) return 0; } +static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, + int unitid) +{ + usb_mixer_elem_info_t *info; + + for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem) + snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + info->elem_id); +} + +static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs) +{ + struct usb_mixer_interface *mixer = urb->context; + + if (urb->status == 0) { + u8 *buf = urb->transfer_buffer; + int i; + + for (i = urb->actual_length; i >= 2; buf += 2, i -= 2) { + snd_printd(KERN_DEBUG "status interrupt: %02x %02x\n", + buf[0], buf[1]); + /* ignore any notifications not from the control interface */ + if ((buf[0] & 0x0f) != 0) + continue; + if (!(buf[0] & 0x40)) + snd_usb_mixer_notify_id(mixer, buf[1]); + } + } + if (urb->status != -ENOENT && urb->status != -ECONNRESET) { + urb->dev = mixer->chip->dev; + usb_submit_urb(urb, GFP_ATOMIC); + } +} + +/* create the handler for the optional status interrupt endpoint */ +static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) +{ + struct usb_host_interface *hostif; + struct usb_endpoint_descriptor *ep; + void *transfer_buffer; + int buffer_length; + unsigned int epnum; + + hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0]; + /* we need one interrupt input endpoint */ + if (get_iface_desc(hostif)->bNumEndpoints < 1) + return 0; + ep = get_endpoint(hostif, 0); + if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN || + (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) + return 0; + + epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + buffer_length = le16_to_cpu(ep->wMaxPacketSize); + transfer_buffer = kmalloc(buffer_length, GFP_KERNEL); + if (!transfer_buffer) + return -ENOMEM; + mixer->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!mixer->urb) { + kfree(transfer_buffer); + return -ENOMEM; + } + usb_fill_int_urb(mixer->urb, mixer->chip->dev, + usb_rcvintpipe(mixer->chip->dev, epnum), + transfer_buffer, buffer_length, + snd_usb_mixer_status_complete, mixer, ep->bInterval); + usb_submit_urb(mixer->urb, GFP_KERNEL); + return 0; +} + int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) { static snd_device_ops_t dev_ops = { @@ -1598,8 +1682,14 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) #ifdef IGNORE_CTL_ERROR mixer->ignore_ctl_error = 1; #endif + mixer->id_elems = kcalloc(256, sizeof(*mixer->id_elems), GFP_KERNEL); + if (!mixer->id_elems) { + kfree(mixer); + return -ENOMEM; + } - if ((err = snd_usb_mixer_controls(mixer)) < 0) { + if ((err = snd_usb_mixer_controls(mixer)) < 0 || + (err = snd_usb_mixer_status_create(mixer)) < 0) { snd_usb_mixer_free(mixer); return err; } @@ -1615,4 +1705,9 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) void snd_usb_mixer_disconnect(struct list_head *p) { + struct usb_mixer_interface *mixer; + + mixer = list_entry(p, struct usb_mixer_interface, list); + if (mixer->urb) + usb_kill_urb(mixer->urb); } -- cgit From b259b10c420a59a2fdbcf5a3498253ebcbdffa1e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 29 Apr 2005 16:29:28 +0200 Subject: [ALSA] usb-audio - add Extigy/Audigy 2 NX remote control support ALSA Core,USB generic driver Add an hwdep interface that supports reading remote control data from Sound Blaster Extigy and Audigy 2 NX devices. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) (limited to 'sound/usb') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index dd045ea6fb0..7ea42d43d7f 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "usbaudio.h" @@ -57,6 +58,19 @@ struct usb_mixer_interface { unsigned int ignore_ctl_error; struct urb *urb; usb_mixer_elem_info_t **id_elems; /* array[256], indexed by unit id */ + + /* Sound Blaster remote control stuff */ + enum { + RC_NONE, + RC_EXTIGY, + RC_AUDIGY2NX, + } rc_type; + unsigned long rc_hwdep_open; + u32 rc_code; + wait_queue_head_t rc_waitq; + struct urb *rc_urb; + struct usb_ctrlrequest *rc_setup_packet; + u8 rc_buffer[6]; }; @@ -1536,6 +1550,9 @@ static void snd_usb_mixer_free(struct usb_mixer_interface *mixer) kfree(mixer->urb->transfer_buffer); usb_free_urb(mixer->urb); } + if (mixer->rc_urb) + usb_free_urb(mixer->rc_urb); + kfree(mixer->rc_setup_packet); kfree(mixer); } @@ -1604,6 +1621,17 @@ static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, info->elem_id); } +static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, + int unitid) +{ + /* SB remote control */ + if (mixer->rc_type != RC_NONE && unitid == 0) { + /* read control code from device memory */ + mixer->rc_urb->dev = mixer->chip->dev; + usb_submit_urb(mixer->rc_urb, GFP_ATOMIC); + } +} + static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs) { struct usb_mixer_interface *mixer = urb->context; @@ -1620,6 +1648,8 @@ static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs) continue; if (!(buf[0] & 0x40)) snd_usb_mixer_notify_id(mixer, buf[1]); + else + snd_usb_mixer_memory_change(mixer, buf[1]); } } if (urb->status != -ENOENT && urb->status != -ECONNRESET) { @@ -1664,6 +1694,126 @@ static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) return 0; } +static void snd_usb_soundblaster_remote_complete(struct urb *urb, + struct pt_regs *regs) +{ + struct usb_mixer_interface *mixer = urb->context; + /* + * format of remote control data: + * Extigy: xx 00 + * Audigy 2 NX: 06 80 xx 00 00 00 + */ + int offset = mixer->rc_type == RC_EXTIGY ? 0 : 2; + u32 code; + + if (urb->status < 0 || urb->actual_length <= offset) + return; + code = mixer->rc_buffer[offset]; + /* the Mute button actually changes the mixer control */ + if (code == 13) + snd_usb_mixer_notify_id(mixer, 18); + mixer->rc_code = code; + wmb(); + wake_up(&mixer->rc_waitq); +} + +static int snd_usb_sbrc_hwdep_open(snd_hwdep_t *hw, struct file *file) +{ + struct usb_mixer_interface *mixer = hw->private_data; + + if (test_and_set_bit(0, &mixer->rc_hwdep_open)) + return -EBUSY; + return 0; +} + +static int snd_usb_sbrc_hwdep_release(snd_hwdep_t *hw, struct file *file) +{ + struct usb_mixer_interface *mixer = hw->private_data; + + clear_bit(0, &mixer->rc_hwdep_open); + smp_mb__after_clear_bit(); + return 0; +} + +static long snd_usb_sbrc_hwdep_read(snd_hwdep_t *hw, char __user *buf, + long count, loff_t *offset) +{ + struct usb_mixer_interface *mixer = hw->private_data; + int err; + u32 rc_code; + + if (count != 1) + return -EINVAL; + err = wait_event_interruptible(mixer->rc_waitq, + (rc_code = xchg(&mixer->rc_code, 0)) != 0); + if (err == 0) { + err = put_user(rc_code, buf); + } + return err < 0 ? err : count; +} + +static unsigned int snd_usb_sbrc_hwdep_poll(snd_hwdep_t *hw, struct file *file, + poll_table *wait) +{ + struct usb_mixer_interface *mixer = hw->private_data; + + poll_wait(file, &mixer->rc_waitq, wait); + return mixer->rc_code ? POLLIN | POLLRDNORM : 0; +} + +static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) +{ + snd_hwdep_t *hwdep; + int err, len; + + switch (le16_to_cpu(mixer->chip->dev->descriptor.idProduct)) { + case 0x3000: + mixer->rc_type = RC_EXTIGY; + len = 2; + break; + case 0x3020: + mixer->rc_type = RC_AUDIGY2NX; + len = 6; + break; + default: + return 0; + } + + init_waitqueue_head(&mixer->rc_waitq); + err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep); + if (err < 0) + return err; + snprintf(hwdep->name, sizeof(hwdep->name), + "%s remote control", mixer->chip->card->shortname); + hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC; + hwdep->private_data = mixer; + hwdep->ops.read = snd_usb_sbrc_hwdep_read; + hwdep->ops.open = snd_usb_sbrc_hwdep_open; + hwdep->ops.release = snd_usb_sbrc_hwdep_release; + hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; + + mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!mixer->rc_urb) + return -ENOMEM; + mixer->rc_setup_packet = kmalloc(sizeof(*mixer->rc_setup_packet), GFP_KERNEL); + if (!mixer->rc_setup_packet) { + usb_free_urb(mixer->rc_urb); + mixer->rc_urb = NULL; + return -ENOMEM; + } + mixer->rc_setup_packet->bRequestType = + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + mixer->rc_setup_packet->bRequest = GET_MEM; + mixer->rc_setup_packet->wValue = cpu_to_le16(0); + mixer->rc_setup_packet->wIndex = cpu_to_le16(0); + mixer->rc_setup_packet->wLength = cpu_to_le16(len); + usb_fill_control_urb(mixer->rc_urb, mixer->chip->dev, + usb_rcvctrlpipe(mixer->chip->dev, 0), + (u8*)mixer->rc_setup_packet, mixer->rc_buffer, len, + snd_usb_soundblaster_remote_complete, mixer); + return 0; +} + int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) { static snd_device_ops_t dev_ops = { @@ -1694,6 +1844,13 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) return err; } + if (le16_to_cpu(chip->dev->descriptor.idVendor) == 0x041e) { + if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) { + snd_usb_mixer_free(mixer); + return err; + } + } + err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); if (err < 0) { snd_usb_mixer_free(mixer); @@ -1710,4 +1867,6 @@ void snd_usb_mixer_disconnect(struct list_head *p) mixer = list_entry(p, struct usb_mixer_interface, list); if (mixer->urb) usb_kill_urb(mixer->urb); + if (mixer->rc_urb) + usb_kill_urb(mixer->rc_urb); } -- cgit From 27d10f5664c7650af3b2ffadfefaf19b36dc7bd8 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 May 2005 08:51:26 +0200 Subject: [ALSA] usb-audio - cache vendor/product IDs USB generic driver Cache the decoded values of idVendor/idProduct to get rid of most of those ugly le16_to_cpu() calls. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 104 +++++++++++++++++++-------------------- sound/usb/usbaudio.h | 6 +++ sound/usb/usbmidi.c | 123 ++++++++++++++++++++++------------------------ sound/usb/usbmixer.c | 38 +++++++------- sound/usb/usbmixer_maps.c | 13 +++-- 5 files changed, 139 insertions(+), 145 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index eeb09bb8cbf..e759b73942c 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2184,17 +2184,15 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor /* * check if the device uses big-endian samples */ -static int is_big_endian_format(struct usb_device *dev, struct audioformat *fp) +static int is_big_endian_format(snd_usb_audio_t *chip, struct audioformat *fp) { - /* M-Audio */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x0763) { - /* Quattro: captured data only */ - if (le16_to_cpu(dev->descriptor.idProduct) == 0x2001 && - fp->endpoint & USB_DIR_IN) - return 1; - /* Audiophile USB */ - if (le16_to_cpu(dev->descriptor.idProduct) == 0x2003) + switch (chip->usb_id) { + case USB_ID(0x0763, 0x2001): /* M-Audio Quattro: captured data only */ + if (fp->endpoint & USB_DIR_IN) return 1; + break; + case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ + return 1; } return 0; } @@ -2208,7 +2206,7 @@ static int is_big_endian_format(struct usb_device *dev, struct audioformat *fp) * @format: the format tag (wFormatTag) * @fmt: the format type descriptor */ -static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format_i_type(snd_usb_audio_t *chip, struct audioformat *fp, int format, unsigned char *fmt) { int pcm_format; @@ -2221,12 +2219,12 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat switch (format) { case 0: /* some devices don't define this correctly... */ snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n", - dev->devnum, fp->iface, fp->altsetting); + chip->dev->devnum, fp->iface, fp->altsetting); /* fall-through */ case USB_AUDIO_FORMAT_PCM: if (sample_width > sample_bytes * 8) { snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n", - dev->devnum, fp->iface, fp->altsetting, + chip->dev->devnum, fp->iface, fp->altsetting, sample_width, sample_bytes); } /* check the format byte size */ @@ -2235,13 +2233,13 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat pcm_format = SNDRV_PCM_FORMAT_S8; break; case 2: - if (is_big_endian_format(dev, fp)) + if (is_big_endian_format(chip, fp)) pcm_format = SNDRV_PCM_FORMAT_S16_BE; /* grrr, big endian!! */ else pcm_format = SNDRV_PCM_FORMAT_S16_LE; break; case 3: - if (is_big_endian_format(dev, fp)) + if (is_big_endian_format(chip, fp)) pcm_format = SNDRV_PCM_FORMAT_S24_3BE; /* grrr, big endian!! */ else pcm_format = SNDRV_PCM_FORMAT_S24_3LE; @@ -2251,14 +2249,14 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat break; default: snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n", - dev->devnum, fp->iface, fp->altsetting, sample_width, sample_bytes); + chip->dev->devnum, fp->iface, + fp->altsetting, sample_width, sample_bytes); break; } break; case USB_AUDIO_FORMAT_PCM8: /* Dallas DS4201 workaround */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x04fa && - le16_to_cpu(dev->descriptor.idProduct) == 0x4201) + if (chip->usb_id == USB_ID(0x04fa, 0x4201)) pcm_format = SNDRV_PCM_FORMAT_S8; else pcm_format = SNDRV_PCM_FORMAT_U8; @@ -2274,7 +2272,7 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat break; default: snd_printk(KERN_INFO "%d:%u:%d : unsupported format type %d\n", - dev->devnum, fp->iface, fp->altsetting, format); + chip->dev->devnum, fp->iface, fp->altsetting, format); break; } return pcm_format; @@ -2291,13 +2289,13 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat * @offset: the start offset of descriptor pointing the rate type * (7 for type I and II, 8 for type II) */ -static int parse_audio_format_rates(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format_rates(snd_usb_audio_t *chip, struct audioformat *fp, unsigned char *fmt, int offset) { int nr_rates = fmt[offset]; if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", - dev->devnum, fp->iface, fp->altsetting); + chip->dev->devnum, fp->iface, fp->altsetting); return -1; } @@ -2344,7 +2342,7 @@ static int parse_audio_format_rates(struct usb_device *dev, struct audioformat * /* * parse the format type I and III descriptors */ -static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format_i(snd_usb_audio_t *chip, struct audioformat *fp, int format, unsigned char *fmt) { int pcm_format; @@ -2356,7 +2354,7 @@ static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp, */ pcm_format = SNDRV_PCM_FORMAT_S16_LE; } else { - pcm_format = parse_audio_format_i_type(dev, fp, format, fmt); + pcm_format = parse_audio_format_i_type(chip, fp, format, fmt); if (pcm_format < 0) return -1; } @@ -2364,16 +2362,16 @@ static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp, fp->channels = fmt[4]; if (fp->channels < 1) { snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n", - dev->devnum, fp->iface, fp->altsetting, fp->channels); + chip->dev->devnum, fp->iface, fp->altsetting, fp->channels); return -1; } - return parse_audio_format_rates(dev, fp, fmt, 7); + return parse_audio_format_rates(chip, fp, fmt, 7); } /* * prase the format type II descriptor */ -static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format_ii(snd_usb_audio_t *chip, struct audioformat *fp, int format, unsigned char *fmt) { int brate, framesize; @@ -2388,7 +2386,7 @@ static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp, break; default: snd_printd(KERN_INFO "%d:%u:%d : unknown format tag 0x%x is detected. processed as MPEG.\n", - dev->devnum, fp->iface, fp->altsetting, format); + chip->dev->devnum, fp->iface, fp->altsetting, format); fp->format = SNDRV_PCM_FORMAT_MPEG; break; } @@ -2397,10 +2395,10 @@ static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp, framesize = combine_word(&fmt[6]); /* fmt[6,7]: wSamplesPerFrame */ snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); fp->frame_size = framesize; - return parse_audio_format_rates(dev, fp, fmt, 8); /* fmt[8..] sample rates */ + return parse_audio_format_rates(chip, fp, fmt, 8); /* fmt[8..] sample rates */ } -static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format(snd_usb_audio_t *chip, struct audioformat *fp, int format, unsigned char *fmt, int stream) { int err; @@ -2408,14 +2406,14 @@ static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, switch (fmt[3]) { case USB_FORMAT_TYPE_I: case USB_FORMAT_TYPE_III: - err = parse_audio_format_i(dev, fp, format, fmt); + err = parse_audio_format_i(chip, fp, format, fmt); break; case USB_FORMAT_TYPE_II: - err = parse_audio_format_ii(dev, fp, format, fmt); + err = parse_audio_format_ii(chip, fp, format, fmt); break; default: snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n", - dev->devnum, fp->iface, fp->altsetting, fmt[3]); + chip->dev->devnum, fp->iface, fp->altsetting, fmt[3]); return -1; } fp->fmt_type = fmt[3]; @@ -2426,9 +2424,8 @@ static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, /* extigy apparently supports sample rates other than 48k * but not in ordinary way. so we enable only 48k atm. */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e && - (le16_to_cpu(dev->descriptor.idProduct) == 0x3000 || - le16_to_cpu(dev->descriptor.idProduct) == 0x3020)) { + if (chip->usb_id == USB_ID(0x041e, 0x3000) || + chip->usb_id == USB_ID(0x041e, 0x3020)) { if (fmt[3] == USB_FORMAT_TYPE_I && stream == SNDRV_PCM_STREAM_PLAYBACK && fp->rates != SNDRV_PCM_RATE_48000 && @@ -2532,8 +2529,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) /* some quirks for attributes here */ /* workaround for AudioTrak Optoplay */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x0a92 && - le16_to_cpu(dev->descriptor.idProduct) == 0x0053) { + if (chip->usb_id == USB_ID(0x0a92, 0x0053)) { /* Optoplay sets the sample rate attribute although * it seems not supporting it in fact. */ @@ -2541,8 +2537,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) } /* workaround for M-Audio Audiophile USB */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x0763 && - le16_to_cpu(dev->descriptor.idProduct) == 0x2003) { + if (chip->usb_id == USB_ID(0x0763, 0x2003)) { /* doesn't set the sample rate attribute, but supports it */ fp->attributes |= EP_CS_ATTR_SAMPLE_RATE; } @@ -2551,11 +2546,9 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) * plantronics headset and Griffin iMic have set adaptive-in * although it's really not... */ - if ((le16_to_cpu(dev->descriptor.idVendor) == 0x047f && - le16_to_cpu(dev->descriptor.idProduct) == 0x0ca1) || + if (chip->usb_id == USB_ID(0x047f, 0x0ca1) || /* Griffin iMic (note that there is an older model 77d:223) */ - (le16_to_cpu(dev->descriptor.idVendor) == 0x077d && - le16_to_cpu(dev->descriptor.idProduct) == 0x07af)) { + chip->usb_id == USB_ID(0x077d, 0x07af)) { fp->ep_attr &= ~EP_ATTR_MASK; if (stream == SNDRV_PCM_STREAM_PLAYBACK) fp->ep_attr |= EP_ATTR_ADAPTIVE; @@ -2564,7 +2557,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) } /* ok, let's parse further... */ - if (parse_audio_format(dev, fp, format, fmt, stream) < 0) { + if (parse_audio_format(chip, fp, format, fmt, stream) < 0) { kfree(fp->rate_table); kfree(fp); continue; @@ -2799,7 +2792,7 @@ static int create_ua700_ua25_quirk(snd_usb_audio_t *chip, .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &ua25_ep }; - if (le16_to_cpu(chip->dev->descriptor.idProduct) == 0x002b) + if (chip->usb_id == USB_ID(0x0582, 0x002b)) return snd_usb_create_midi_interface(chip, iface, &ua700_quirk); else @@ -3018,8 +3011,8 @@ static void proc_audio_usbid_read(snd_info_entry_t *entry, snd_info_buffer_t *bu snd_usb_audio_t *chip = entry->private_data; if (! chip->shutdown) snd_iprintf(buffer, "%04x:%04x\n", - le16_to_cpu(chip->dev->descriptor.idVendor), - le16_to_cpu(chip->dev->descriptor.idProduct)); + USB_ID_VENDOR(chip->usb_id), + USB_ID_PRODUCT(chip->usb_id)); } static void snd_usb_audio_create_proc(snd_usb_audio_t *chip) @@ -3089,6 +3082,8 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, chip->index = idx; chip->dev = dev; chip->card = card; + chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); INIT_LIST_HEAD(&chip->pcm_list); INIT_LIST_HEAD(&chip->midi_list); INIT_LIST_HEAD(&chip->mixer_list); @@ -3101,8 +3096,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, strcpy(card->driver, "USB-Audio"); sprintf(component, "USB%04x:%04x", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); + USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); snd_component_add(card, component); /* retrieve the device string as shortname */ @@ -3114,8 +3108,8 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, card->shortname, sizeof(card->shortname)) <= 0) { /* no name available from anywhere, so use ID */ sprintf(card->shortname, "USB Device %#04x:%#04x", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); + USB_ID_VENDOR(chip->usb_id), + USB_ID_PRODUCT(chip->usb_id)); } } @@ -3173,17 +3167,19 @@ static void *snd_usb_audio_probe(struct usb_device *dev, snd_usb_audio_t *chip; struct usb_host_interface *alts; int ifnum; + u32 id; alts = &intf->altsetting[0]; ifnum = get_iface_desc(alts)->bInterfaceNumber; + id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) goto __err_val; /* SB Extigy needs special boot-up sequence */ /* if more models come, this will go to the quirk list. */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e && - le16_to_cpu(dev->descriptor.idProduct) == 0x3000) { + if (id == USB_ID(0x041e, 0x3000)) { if (snd_usb_extigy_boot_quirk(dev, intf) < 0) goto __err_val; config = dev->actconfig; @@ -3217,8 +3213,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev, } for (i = 0; i < SNDRV_CARDS; i++) if (enable[i] && ! usb_chip[i] && - (vid[i] == -1 || vid[i] == le16_to_cpu(dev->descriptor.idVendor)) && - (pid[i] == -1 || pid[i] == le16_to_cpu(dev->descriptor.idProduct))) { + (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) && + (pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) { if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) { goto __error; } diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 41d842dab3e..aedb42aaa74 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -118,6 +118,11 @@ /* maximum number of endpoints per interface */ #define MIDI_MAX_ENDPOINTS 2 +/* handling of USB vendor/product ID pairs as 32-bit numbers */ +#define USB_ID(vendor, product) (((vendor) << 16) | (product)) +#define USB_ID_VENDOR(id) ((id) >> 16) +#define USB_ID_PRODUCT(id) ((u16)(id)) + /* */ @@ -127,6 +132,7 @@ struct snd_usb_audio { int index; struct usb_device *dev; snd_card_t *card; + u32 usb_id; int shutdown; int num_interfaces; diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 304a13451ec..bee70068dce 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -955,88 +955,87 @@ static snd_rawmidi_substream_t* snd_usbmidi_find_substream(snd_usb_midi_t* umidi * such as internal control or synthesizer ports. */ static struct { - __u16 vendor; - __u16 product; + u32 id; int port; const char *name_format; } snd_usbmidi_port_names[] = { /* Roland UA-100 */ - {0x0582, 0x0000, 2, "%s Control"}, + { USB_ID(0x0582, 0x0000), 2, "%s Control" }, /* Roland SC-8850 */ - {0x0582, 0x0003, 0, "%s Part A"}, - {0x0582, 0x0003, 1, "%s Part B"}, - {0x0582, 0x0003, 2, "%s Part C"}, - {0x0582, 0x0003, 3, "%s Part D"}, - {0x0582, 0x0003, 4, "%s MIDI 1"}, - {0x0582, 0x0003, 5, "%s MIDI 2"}, + { USB_ID(0x0582, 0x0003), 0, "%s Part A" }, + { USB_ID(0x0582, 0x0003), 1, "%s Part B" }, + { USB_ID(0x0582, 0x0003), 2, "%s Part C" }, + { USB_ID(0x0582, 0x0003), 3, "%s Part D" }, + { USB_ID(0x0582, 0x0003), 4, "%s MIDI 1" }, + { USB_ID(0x0582, 0x0003), 5, "%s MIDI 2" }, /* Roland U-8 */ - {0x0582, 0x0004, 0, "%s MIDI"}, - {0x0582, 0x0004, 1, "%s Control"}, + { USB_ID(0x0582, 0x0004), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x0004), 1, "%s Control" }, /* Roland SC-8820 */ - {0x0582, 0x0007, 0, "%s Part A"}, - {0x0582, 0x0007, 1, "%s Part B"}, - {0x0582, 0x0007, 2, "%s MIDI"}, + { USB_ID(0x0582, 0x0007), 0, "%s Part A" }, + { USB_ID(0x0582, 0x0007), 1, "%s Part B" }, + { USB_ID(0x0582, 0x0007), 2, "%s MIDI" }, /* Roland SK-500 */ - {0x0582, 0x000b, 0, "%s Part A"}, - {0x0582, 0x000b, 1, "%s Part B"}, - {0x0582, 0x000b, 2, "%s MIDI"}, + { USB_ID(0x0582, 0x000b), 0, "%s Part A" }, + { USB_ID(0x0582, 0x000b), 1, "%s Part B" }, + { USB_ID(0x0582, 0x000b), 2, "%s MIDI" }, /* Roland SC-D70 */ - {0x0582, 0x000c, 0, "%s Part A"}, - {0x0582, 0x000c, 1, "%s Part B"}, - {0x0582, 0x000c, 2, "%s MIDI"}, + { USB_ID(0x0582, 0x000c), 0, "%s Part A" }, + { USB_ID(0x0582, 0x000c), 1, "%s Part B" }, + { USB_ID(0x0582, 0x000c), 2, "%s MIDI" }, /* Edirol UM-880 */ - {0x0582, 0x0014, 8, "%s Control"}, + { USB_ID(0x0582, 0x0014), 8, "%s Control" }, /* Edirol SD-90 */ - {0x0582, 0x0016, 0, "%s Part A"}, - {0x0582, 0x0016, 1, "%s Part B"}, - {0x0582, 0x0016, 2, "%s MIDI 1"}, - {0x0582, 0x0016, 3, "%s MIDI 2"}, + { USB_ID(0x0582, 0x0016), 0, "%s Part A" }, + { USB_ID(0x0582, 0x0016), 1, "%s Part B" }, + { USB_ID(0x0582, 0x0016), 2, "%s MIDI 1" }, + { USB_ID(0x0582, 0x0016), 3, "%s MIDI 2" }, /* Edirol UM-550 */ - {0x0582, 0x0023, 5, "%s Control"}, + { USB_ID(0x0582, 0x0023), 5, "%s Control" }, /* Edirol SD-20 */ - {0x0582, 0x0027, 0, "%s Part A"}, - {0x0582, 0x0027, 1, "%s Part B"}, - {0x0582, 0x0027, 2, "%s MIDI"}, + { USB_ID(0x0582, 0x0027), 0, "%s Part A" }, + { USB_ID(0x0582, 0x0027), 1, "%s Part B" }, + { USB_ID(0x0582, 0x0027), 2, "%s MIDI" }, /* Edirol SD-80 */ - {0x0582, 0x0029, 0, "%s Part A"}, - {0x0582, 0x0029, 1, "%s Part B"}, - {0x0582, 0x0029, 2, "%s MIDI 1"}, - {0x0582, 0x0029, 3, "%s MIDI 2"}, + { USB_ID(0x0582, 0x0029), 0, "%s Part A" }, + { USB_ID(0x0582, 0x0029), 1, "%s Part B" }, + { USB_ID(0x0582, 0x0029), 2, "%s MIDI 1" }, + { USB_ID(0x0582, 0x0029), 3, "%s MIDI 2" }, /* Edirol UA-700 */ - {0x0582, 0x002b, 0, "%s MIDI"}, - {0x0582, 0x002b, 1, "%s Control"}, + { USB_ID(0x0582, 0x002b), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x002b), 1, "%s Control" }, /* Roland VariOS */ - {0x0582, 0x002f, 0, "%s MIDI"}, - {0x0582, 0x002f, 1, "%s External MIDI"}, - {0x0582, 0x002f, 2, "%s Sync"}, + { USB_ID(0x0582, 0x002f), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x002f), 1, "%s External MIDI" }, + { USB_ID(0x0582, 0x002f), 2, "%s Sync" }, /* Edirol PCR */ - {0x0582, 0x0033, 0, "%s MIDI"}, - {0x0582, 0x0033, 1, "%s 1"}, - {0x0582, 0x0033, 2, "%s 2"}, + { USB_ID(0x0582, 0x0033), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x0033), 1, "%s 1" }, + { USB_ID(0x0582, 0x0033), 2, "%s 2" }, /* BOSS GS-10 */ - {0x0582, 0x003b, 0, "%s MIDI"}, - {0x0582, 0x003b, 1, "%s Control"}, + { USB_ID(0x0582, 0x003b), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x003b), 1, "%s Control" }, /* Edirol UA-1000 */ - {0x0582, 0x0044, 0, "%s MIDI"}, - {0x0582, 0x0044, 1, "%s Control"}, + { USB_ID(0x0582, 0x0044), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x0044), 1, "%s Control" }, /* Edirol UR-80 */ - {0x0582, 0x0048, 0, "%s MIDI"}, - {0x0582, 0x0048, 1, "%s 1"}, - {0x0582, 0x0048, 2, "%s 2"}, + { USB_ID(0x0582, 0x0048), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x0048), 1, "%s 1" }, + { USB_ID(0x0582, 0x0048), 2, "%s 2" }, /* Edirol PCR-A */ - {0x0582, 0x004d, 0, "%s MIDI"}, - {0x0582, 0x004d, 1, "%s 1"}, - {0x0582, 0x004d, 2, "%s 2"}, + { USB_ID(0x0582, 0x004d), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x004d), 1, "%s 1" }, + { USB_ID(0x0582, 0x004d), 2, "%s 2" }, /* M-Audio MidiSport 8x8 */ - {0x0763, 0x1031, 8, "%s Control"}, - {0x0763, 0x1033, 8, "%s Control"}, + { USB_ID(0x0763, 0x1031), 8, "%s Control" }, + { USB_ID(0x0763, 0x1033), 8, "%s Control" }, /* MOTU Fastlane */ - {0x07fd, 0x0001, 0, "%s MIDI A"}, - {0x07fd, 0x0001, 1, "%s MIDI B"}, + { USB_ID(0x07fd, 0x0001), 0, "%s MIDI A" }, + { USB_ID(0x07fd, 0x0001), 1, "%s MIDI B" }, /* Emagic Unitor8/AMT8/MT4 */ - {0x086a, 0x0001, 8, "%s Broadcast"}, - {0x086a, 0x0002, 8, "%s Broadcast"}, - {0x086a, 0x0003, 4, "%s Broadcast"}, + { USB_ID(0x086a, 0x0001), 8, "%s Broadcast" }, + { USB_ID(0x086a, 0x0002), 8, "%s Broadcast" }, + { USB_ID(0x086a, 0x0003), 4, "%s Broadcast" }, }; static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi, @@ -1044,7 +1043,6 @@ static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi, snd_rawmidi_substream_t** rsubstream) { int i; - __u16 vendor, product; const char *name_format; snd_rawmidi_substream_t* substream = snd_usbmidi_find_substream(umidi, stream, number); @@ -1055,11 +1053,8 @@ static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi, /* TODO: read port name from jack descriptor */ name_format = "%s MIDI %d"; - vendor = le16_to_cpu(umidi->chip->dev->descriptor.idVendor); - product = le16_to_cpu(umidi->chip->dev->descriptor.idProduct); for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_names); ++i) { - if (snd_usbmidi_port_names[i].vendor == vendor && - snd_usbmidi_port_names[i].product == product && + if (snd_usbmidi_port_names[i].id == umidi->chip->usb_id && snd_usbmidi_port_names[i].port == number) { name_format = snd_usbmidi_port_names[i].name_format; break; @@ -1226,7 +1221,7 @@ static int snd_usbmidi_detect_endpoints(snd_usb_midi_t* umidi, struct usb_endpoint_descriptor* epd; int i, out_eps = 0, in_eps = 0; - if (le16_to_cpu(umidi->chip->dev->descriptor.idVendor) == 0x0582) + if (USB_ID_VENDOR(umidi->chip->usb_id) == 0x0582) snd_usbmidi_switch_roland_altsetting(umidi); if (endpoint[0].out_ep || endpoint[0].in_ep) diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 7ea42d43d7f..bfaec4fc185 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -89,8 +89,6 @@ struct usb_mixer_build { struct usb_mixer_interface *mixer; unsigned char *buffer; unsigned int buflen; - unsigned short vendor; - unsigned short product; DECLARE_BITMAP(unitbitmap, 256); usb_audio_term_t oterm; const struct usbmix_name_map *map; @@ -906,11 +904,16 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, /* note that detection between firmware 2.1.1.7 (N101) and later 2.1.1.21 */ /* is not very clear from datasheets */ /* I hope that the min value is -15360 for newer firmware --jk */ - if (((state->vendor == 0x471 && (state->product == 0x104 || state->product == 0x105 || state->product == 0x101)) || - (state->vendor == 0x672 && state->product == 0x1041)) && !strcmp(kctl->id.name, "PCM Playback Volume") && - cval->min == -15616) { - snd_printk("USB Audio: using volume control quirk for the UDA1321/N101 chip\n"); - cval->max = -256; + switch (state->chip->usb_id) { + case USB_ID(0x0471, 0x0101): + case USB_ID(0x0471, 0x0104): + case USB_ID(0x0471, 0x0105): + case USB_ID(0x0672, 0x1041): + if (!strcmp(kctl->id.name, "PCM Playback Volume") && + cval->min == -15616) { + snd_printk("using volume control quirk for the UDA1321/N101 chip\n"); + cval->max = -256; + } } snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", @@ -1574,7 +1577,6 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) mixer_build_t state; int err; const struct usbmix_ctl_map *map; - struct usb_device_descriptor *dev = &mixer->chip->dev->descriptor; struct usb_host_interface *hostif; hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0]; @@ -1583,12 +1585,10 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) state.mixer = mixer; state.buffer = hostif->extra; state.buflen = hostif->extralen; - state.vendor = le16_to_cpu(dev->idVendor); - state.product = le16_to_cpu(dev->idProduct); /* check the mapping table */ - for (map = usbmix_ctl_maps; map->vendor; map++) { - if (map->vendor == state.vendor && map->product == state.product) { + for (map = usbmix_ctl_maps; map->id; map++) { + if (map->id == state.chip->usb_id) { state.map = map->map; state.selector_map = map->selector_map; mixer->ignore_ctl_error = map->ignore_ctl_error; @@ -1766,12 +1766,12 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) snd_hwdep_t *hwdep; int err, len; - switch (le16_to_cpu(mixer->chip->dev->descriptor.idProduct)) { - case 0x3000: + switch (mixer->chip->usb_id) { + case USB_ID(0x041e, 0x3000): mixer->rc_type = RC_EXTIGY; len = 2; break; - case 0x3020: + case USB_ID(0x041e, 0x3020): mixer->rc_type = RC_AUDIGY2NX; len = 6; break; @@ -1844,11 +1844,9 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) return err; } - if (le16_to_cpu(chip->dev->descriptor.idVendor) == 0x041e) { - if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) { - snd_usb_mixer_free(mixer); - return err; - } + if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) { + snd_usb_mixer_free(mixer); + return err; } err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index adb0abb3ee8..f05500b05ec 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -33,8 +33,7 @@ struct usbmix_selector_map { }; struct usbmix_ctl_map { - int vendor; - int product; + u32 id; const struct usbmix_name_map *map; const struct usbmix_selector_map *selector_map; int ignore_ctl_error; @@ -225,26 +224,26 @@ static struct usbmix_name_map justlink_map[] = { static struct usbmix_ctl_map usbmix_ctl_maps[] = { { - .vendor = 0x41e, .product = 0x3000, + .id = USB_ID(0x041e, 0x3000), .map = extigy_map, .ignore_ctl_error = 1, }, { - .vendor = 0x41e, .product = 0x3010, + .id = USB_ID(0x041e, 0x3010), .map = mp3plus_map, }, { - .vendor = 0x41e, .product = 0x3020, + .id = USB_ID(0x041e, 0x3020), .map = audigy2nx_map, .selector_map = audigy2nx_selectors, }, { - .vendor = 0x8bb, .product = 0x2702, + .id = USB_ID(0x08bb, 0x2702), .map = linex_map, .ignore_ctl_error = 1, }, { - .vendor = 0xc45, .product = 0x1158, + .id = USB_ID(0x0c45, 0x1158), .map = justlink_map, }, { 0 } /* terminator */ -- cgit From 4dc40a3cc4778ebcb6212bdb71b48690a153be07 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 May 2005 08:52:32 +0200 Subject: [ALSA] usb-audio - allow type 0 extension units USB generic driver Extension units can have type 0, so do not ignore them when constructing mixer controls. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index bfaec4fc185..5683ae0b5ba 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -1232,9 +1232,6 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char } type = combine_word(&dsc[4]); - if (! type) - return 0; /* undefined? */ - for (info = list; info && info->type; info++) if (info->type == type) break; -- cgit From 1149a64fe4916fe6fdc8938043a0dc9a6551ab63 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 May 2005 08:53:46 +0200 Subject: [ALSA] usb-audio - use proper interval between synchronization packets USB generic driver Add sanity checks when reading the bRefresh value, and actually use it for the synchronization packets instead of polling at 1000 Hz. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index e759b73942c..e1a648d7fff 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -1051,10 +1051,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by u->urb->pipe = subs->syncpipe; u->urb->transfer_flags = URB_ISO_ASAP; u->urb->number_of_packets = u->packets; - if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) - u->urb->interval = 8; - else - u->urb->interval = 1; + u->urb->interval = 1 << subs->syncinterval; u->urb->context = u; u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb); } @@ -1272,7 +1269,12 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt) subs->syncpipe = usb_rcvisocpipe(dev, ep); else subs->syncpipe = usb_sndisocpipe(dev, ep); - subs->syncinterval = get_endpoint(alts, 1)->bRefresh; + if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && + get_endpoint(alts, 1)->bRefresh >= 1 && + get_endpoint(alts, 1)->bRefresh <= 9) + subs->syncinterval = get_endpoint(alts, 1)->bRefresh; + else + subs->syncinterval = 1; } /* always fill max packet size */ -- cgit From ca81090a00e3e7152fe1f3d7398f11d57919428e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 May 2005 08:55:54 +0200 Subject: [ALSA] usb-audio - use only one packet in synchronization feedback URBs USB generic driver Do not use more than one packet in synchronization feedback URBs because it would be pointless to send or receive more than one value at the same time. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 93 ++++++++++++++++++---------------------------------- 1 file changed, 31 insertions(+), 62 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index e1a648d7fff..a5e97d081c3 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -177,7 +177,7 @@ struct snd_usb_substream { unsigned int nurbs; /* # urbs */ snd_urb_ctx_t dataurb[MAX_URBS]; /* data urb table */ snd_urb_ctx_t syncurb[SYNC_URBS]; /* sync urb table */ - char syncbuf[SYNC_URBS * MAX_PACKS * 4]; /* sync buffer; it's so small - let's get static */ + char syncbuf[SYNC_URBS * 4]; /* sync buffer; it's so small - let's get static */ char *tmpbuf; /* temporary buffer for playback */ u64 formats; /* format bitmasks (all or'ed) */ @@ -251,17 +251,13 @@ static int prepare_capture_sync_urb(snd_usb_substream_t *subs, { unsigned char *cp = urb->transfer_buffer; snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - int i, offs; - urb->number_of_packets = ctx->packets; urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) { - urb->iso_frame_desc[i].length = 3; - urb->iso_frame_desc[i].offset = offs; - cp[0] = subs->freqn >> 2; - cp[1] = subs->freqn >> 10; - cp[2] = subs->freqn >> 18; - } + urb->iso_frame_desc[0].length = 3; + urb->iso_frame_desc[0].offset = 0; + cp[0] = subs->freqn >> 2; + cp[1] = subs->freqn >> 10; + cp[2] = subs->freqn >> 18; return 0; } @@ -277,18 +273,14 @@ static int prepare_capture_sync_urb_hs(snd_usb_substream_t *subs, { unsigned char *cp = urb->transfer_buffer; snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - int i, offs; - urb->number_of_packets = ctx->packets; urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) { - urb->iso_frame_desc[i].length = 4; - urb->iso_frame_desc[i].offset = offs; - cp[0] = subs->freqn; - cp[1] = subs->freqn >> 8; - cp[2] = subs->freqn >> 16; - cp[3] = subs->freqn >> 24; - } + urb->iso_frame_desc[0].length = 4; + urb->iso_frame_desc[0].offset = 0; + cp[0] = subs->freqn; + cp[1] = subs->freqn >> 8; + cp[2] = subs->freqn >> 16; + cp[3] = subs->freqn >> 24; return 0; } @@ -418,15 +410,11 @@ static int prepare_playback_sync_urb(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *urb) { - int i, offs; snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - urb->number_of_packets = ctx->packets; urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) { - urb->iso_frame_desc[i].length = 3; - urb->iso_frame_desc[i].offset = offs; - } + urb->iso_frame_desc[0].length = 3; + urb->iso_frame_desc[0].offset = 0; return 0; } @@ -440,15 +428,11 @@ static int prepare_playback_sync_urb_hs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *urb) { - int i, offs; snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - urb->number_of_packets = ctx->packets; urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) { - urb->iso_frame_desc[i].length = 4; - urb->iso_frame_desc[i].offset = offs; - } + urb->iso_frame_desc[0].length = 4; + urb->iso_frame_desc[0].offset = 0; return 0; } @@ -462,17 +446,12 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *urb) { - int i; - unsigned int f, found; - unsigned char *cp = urb->transfer_buffer; + unsigned int f; unsigned long flags; - found = 0; - for (i = 0; i < urb->number_of_packets; i++, cp += 4) { - if (urb->iso_frame_desc[i].status || - urb->iso_frame_desc[i].actual_length < 3) - continue; - f = combine_triple(cp) << 2; + if (urb->iso_frame_desc[0].status == 0 && + urb->iso_frame_desc[0].actual_length == 3) { + f = combine_triple((u8*)urb->transfer_buffer) << 2; #if 0 if (f < subs->freqn - (subs->freqn>>3) || f > subs->freqmax) { snd_printd(KERN_WARNING "requested frequency %d (%u,%03uHz) out of range (current nominal %d (%u,%03uHz))\n", @@ -481,11 +460,8 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs, continue; } #endif - found = f; - } - if (found) { spin_lock_irqsave(&subs->lock, flags); - subs->freqm = found; + subs->freqm = f; spin_unlock_irqrestore(&subs->lock, flags); } @@ -502,21 +478,14 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *urb) { - int i; - unsigned int found; - unsigned char *cp = urb->transfer_buffer; + unsigned int f; unsigned long flags; - found = 0; - for (i = 0; i < urb->number_of_packets; i++, cp += 4) { - if (urb->iso_frame_desc[i].status || - urb->iso_frame_desc[i].actual_length < 4) - continue; - found = combine_quad(cp) & 0x0fffffff; - } - if (found) { + if (urb->iso_frame_desc[0].status == 0 && + urb->iso_frame_desc[0].actual_length == 4) { + f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff; spin_lock_irqsave(&subs->lock, flags); - subs->freqm = found; + subs->freqm = f; spin_unlock_irqrestore(&subs->lock, flags); } @@ -1039,18 +1008,18 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by snd_urb_ctx_t *u = &subs->syncurb[i]; u->index = i; u->subs = subs; - u->packets = nrpacks; - u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); + u->packets = 1; + u->urb = usb_alloc_urb(1, GFP_KERNEL); if (! u->urb) { release_substream_urbs(subs, 0); return -ENOMEM; } - u->urb->transfer_buffer = subs->syncbuf + i * nrpacks * 4; - u->urb->transfer_buffer_length = nrpacks * 4; + u->urb->transfer_buffer = subs->syncbuf + i * 4; + u->urb->transfer_buffer_length = 4; u->urb->dev = subs->dev; u->urb->pipe = subs->syncpipe; u->urb->transfer_flags = URB_ISO_ASAP; - u->urb->number_of_packets = u->packets; + u->urb->number_of_packets = 1; u->urb->interval = 1 << subs->syncinterval; u->urb->context = u; u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb); -- cgit From 434b7f56872fc5783c77f362e895da8e22168325 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 May 2005 08:58:31 +0200 Subject: [ALSA] usb-audio - make SB remote control device LIRC compatible USB generic driver Add ioctls to the Sound Blaster remote control hwdep device so that it can be used with LIRC. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 5683ae0b5ba..d90d6fa7431 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -39,6 +39,18 @@ #include "usbaudio.h" +#if 0 +#include +#else +/* only those symbols from lirc.h we actually need: */ +#include +#define LIRC_MODE2REC(x) ((x) << 16) +#define LIRC_MODE_CODE 0x00000008 +#define LIRC_CAN_REC_CODE LIRC_MODE2REC(LIRC_MODE_CODE) +#define LIRC_GET_FEATURES _IOR('i', 0x00000000, __u32) +#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, __u32) +#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, __u32) +#endif /* */ @@ -1739,12 +1751,15 @@ static long snd_usb_sbrc_hwdep_read(snd_hwdep_t *hw, char __user *buf, int err; u32 rc_code; - if (count != 1) + if (count != 1 && count != 4) return -EINVAL; err = wait_event_interruptible(mixer->rc_waitq, (rc_code = xchg(&mixer->rc_code, 0)) != 0); if (err == 0) { - err = put_user(rc_code, buf); + if (count == 1) + err = put_user(rc_code, buf); + else + err = put_user(rc_code, (u32 __user *)buf); } return err < 0 ? err : count; } @@ -1758,6 +1773,25 @@ static unsigned int snd_usb_sbrc_hwdep_poll(snd_hwdep_t *hw, struct file *file, return mixer->rc_code ? POLLIN | POLLRDNORM : 0; } +static int snd_usb_sbrc_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, + unsigned int cmd, unsigned long arg) +{ + u32 __user *argp = (u32 __user *)arg; + u32 mode; + + switch (cmd) { + case LIRC_GET_FEATURES: + return put_user(LIRC_CAN_REC_CODE, argp); + case LIRC_GET_REC_MODE: + return put_user(LIRC_MODE_CODE, argp); + case LIRC_SET_REC_MODE: + if (get_user(mode, argp)) + return -EFAULT; + return mode == LIRC_MODE_CODE ? 0 : -ENOSYS; + } + return -ENOTTY; +} + static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) { snd_hwdep_t *hwdep; @@ -1788,6 +1822,7 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) hwdep->ops.open = snd_usb_sbrc_hwdep_open; hwdep->ops.release = snd_usb_sbrc_hwdep_release; hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; + hwdep->ops.ioctl = snd_usb_sbrc_hwdep_ioctl; mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); if (!mixer->rc_urb) -- cgit From 93446edcd05589201f20cf8843e8c4f990c18ae4 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 3 May 2005 08:02:40 +0200 Subject: [ALSA] usb-audio - Audigy 2 NX blinkenlights USB generic driver Adds mixer controls for the CMSS/Dolby Digital/Power LEDs on the SB Audigy 2 NX. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 106 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 95 insertions(+), 11 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index d90d6fa7431..ec880ff5262 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -83,6 +83,8 @@ struct usb_mixer_interface { struct urb *rc_urb; struct usb_ctrlrequest *rc_setup_packet; u8 rc_buffer[6]; + + u8 audigy2nx_leds[3]; }; @@ -1846,6 +1848,85 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) return 0; } +static int snd_audigy2nx_led_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_audigy2nx_led_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); + int index = kcontrol->private_value; + + ucontrol->value.integer.value[0] = mixer->audigy2nx_leds[index]; + return 0; +} + +static int snd_audigy2nx_led_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); + int index = kcontrol->private_value; + int value = ucontrol->value.integer.value[0]; + int err, changed; + + if (value > 1) + return -EINVAL; + changed = value != mixer->audigy2nx_leds[index]; + err = snd_usb_ctl_msg(mixer->chip->dev, + usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + value, index + 2, NULL, 0, 100); + if (err < 0) + return err; + mixer->audigy2nx_leds[index] = value; + return changed; +} + +static snd_kcontrol_new_t snd_audigy2nx_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "CMSS LED Switch", + .info = snd_audigy2nx_led_info, + .get = snd_audigy2nx_led_get, + .put = snd_audigy2nx_led_put, + .private_value = 0, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Power LED Switch", + .info = snd_audigy2nx_led_info, + .get = snd_audigy2nx_led_get, + .put = snd_audigy2nx_led_put, + .private_value = 1, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Dolby Digital LED Switch", + .info = snd_audigy2nx_led_info, + .get = snd_audigy2nx_led_get, + .put = snd_audigy2nx_led_put, + .private_value = 2, + }, +}; + +static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) +{ + int i, err; + + for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) { + err = snd_ctl_add(mixer->chip->card, + snd_ctl_new1(&snd_audigy2nx_controls[i], mixer)); + if (err < 0) + return err; + } + mixer->audigy2nx_leds[1] = 1; /* Power LED is on by default */ + return 0; +} + int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) { static snd_device_ops_t dev_ops = { @@ -1871,23 +1952,26 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) } if ((err = snd_usb_mixer_controls(mixer)) < 0 || - (err = snd_usb_mixer_status_create(mixer)) < 0) { - snd_usb_mixer_free(mixer); - return err; - } + (err = snd_usb_mixer_status_create(mixer)) < 0) + goto _error; - if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) { - snd_usb_mixer_free(mixer); - return err; + if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) + goto _error; + + if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) { + if ((err = snd_audigy2nx_controls_create(mixer)) < 0) + goto _error; } err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); - if (err < 0) { - snd_usb_mixer_free(mixer); - return err; - } + if (err < 0) + goto _error; list_add(&mixer->list, &chip->mixer_list); return 0; + +_error: + snd_usb_mixer_free(mixer); + return err; } void snd_usb_mixer_disconnect(struct list_head *p) -- cgit From c3f9329716df9965cbaf74ce313a12fe889c1a62 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 4 May 2005 14:56:04 +0200 Subject: [ALSA] usb-audio - set sample rate attribute on Audigy 2 NX endpoints USB generic driver The SB Audigy 2 NX does not advertise the sample rate attribute in its endpoint descriptors although it supports it. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a5e97d081c3..da1fe0f0bca 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2499,32 +2499,31 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) /* some quirks for attributes here */ - /* workaround for AudioTrak Optoplay */ - if (chip->usb_id == USB_ID(0x0a92, 0x0053)) { + switch (chip->usb_id) { + case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */ /* Optoplay sets the sample rate attribute although * it seems not supporting it in fact. */ fp->attributes &= ~EP_CS_ATTR_SAMPLE_RATE; - } - - /* workaround for M-Audio Audiophile USB */ - if (chip->usb_id == USB_ID(0x0763, 0x2003)) { + break; + case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ + case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ /* doesn't set the sample rate attribute, but supports it */ fp->attributes |= EP_CS_ATTR_SAMPLE_RATE; - } - + break; + case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ + case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is + an older model 77d:223) */ /* * plantronics headset and Griffin iMic have set adaptive-in * although it's really not... */ - if (chip->usb_id == USB_ID(0x047f, 0x0ca1) || - /* Griffin iMic (note that there is an older model 77d:223) */ - chip->usb_id == USB_ID(0x077d, 0x07af)) { fp->ep_attr &= ~EP_ATTR_MASK; if (stream == SNDRV_PCM_STREAM_PLAYBACK) fp->ep_attr |= EP_ATTR_ADAPTIVE; else fp->ep_attr |= EP_ATTR_SYNC; + break; } /* ok, let's parse further... */ -- cgit From 3714b5344e2da58d18f0b885663226826c22a1b3 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sun, 8 May 2005 22:22:27 +0200 Subject: [ALSA] Fix snd-usb-audio dependency on snd-hwdep. USB Signed-off-by: James Courtier-Dutton --- sound/usb/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/usb') diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 9329e992c84..f05d02f5b69 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -6,6 +6,7 @@ menu "USB devices" config SND_USB_AUDIO tristate "USB Audio/MIDI driver" depends on SND && USB + select SND_HWDEP select SND_RAWMIDI select SND_PCM help -- cgit From 3a2f08560d61e267aacddc63c26bf997d0d85e91 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 9 May 2005 09:20:31 +0200 Subject: [ALSA] usb-audio - enable high speed (not) on Audigy 2 NX USB generic driver The SB Audigy 2 NX needs a special boot-up command before it works in high speed mode. However, we don't actually enable it yet because high speed synchronization doesn't seem to work with this device. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index da1fe0f0bca..34d5f58985b 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2925,6 +2925,25 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac return 0; } +static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev) +{ +#if 0 + /* TODO: enable this when high speed synchronization actually works */ + u8 buf = 1; + + snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, + 0, 0, &buf, 1, 1000); + if (buf == 0) { + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0x29, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + 1, 2000, NULL, 0, 1000); + return -ENODEV; + } +#endif + return 0; +} + /* * audio-interface quirks @@ -3154,6 +3173,11 @@ static void *snd_usb_audio_probe(struct usb_device *dev, goto __err_val; config = dev->actconfig; } + /* SB Audigy 2 NX needs its own boot-up magic, too */ + if (id == USB_ID(0x041e, 0x3020)) { + if (snd_usb_audigy2nx_boot_quirk(dev) < 0) + goto __err_val; + } /* * found a config. now register to ALSA -- cgit From f55a655bf9eeb1431633bd313f47c8e4dadcf47c Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 9 May 2005 09:21:28 +0200 Subject: [ALSA] usb-audio - remove superfluous LIRC ioctls USB generic driver The ioctls for LIRC compatibility can be removed because the infrastructure and detection stuff is better done in user space. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 33 --------------------------------- 1 file changed, 33 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index ec880ff5262..4a49e1930a1 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -39,19 +39,6 @@ #include "usbaudio.h" -#if 0 -#include -#else -/* only those symbols from lirc.h we actually need: */ -#include -#define LIRC_MODE2REC(x) ((x) << 16) -#define LIRC_MODE_CODE 0x00000008 -#define LIRC_CAN_REC_CODE LIRC_MODE2REC(LIRC_MODE_CODE) -#define LIRC_GET_FEATURES _IOR('i', 0x00000000, __u32) -#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, __u32) -#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, __u32) -#endif - /* */ @@ -1775,25 +1762,6 @@ static unsigned int snd_usb_sbrc_hwdep_poll(snd_hwdep_t *hw, struct file *file, return mixer->rc_code ? POLLIN | POLLRDNORM : 0; } -static int snd_usb_sbrc_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, - unsigned int cmd, unsigned long arg) -{ - u32 __user *argp = (u32 __user *)arg; - u32 mode; - - switch (cmd) { - case LIRC_GET_FEATURES: - return put_user(LIRC_CAN_REC_CODE, argp); - case LIRC_GET_REC_MODE: - return put_user(LIRC_MODE_CODE, argp); - case LIRC_SET_REC_MODE: - if (get_user(mode, argp)) - return -EFAULT; - return mode == LIRC_MODE_CODE ? 0 : -ENOSYS; - } - return -ENOTTY; -} - static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) { snd_hwdep_t *hwdep; @@ -1824,7 +1792,6 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) hwdep->ops.open = snd_usb_sbrc_hwdep_open; hwdep->ops.release = snd_usb_sbrc_hwdep_release; hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; - hwdep->ops.ioctl = snd_usb_sbrc_hwdep_ioctl; mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); if (!mixer->rc_urb) -- cgit From aafad5629a949d0ad41180f8a746b6cd7654e317 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 10 May 2005 14:47:38 +0200 Subject: [ALSA] usb-audio - add a proc file for Audigy 2 NX jack status USB generic driver This patch adds a proc file for the SB Audigy 2 NX which shows the connection status of the various jacks. Unfortunately, no SPDIF input frequency (yet). Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 4a49e1930a1..83ba665e5c6 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "usbaudio.h" @@ -1622,11 +1623,22 @@ static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, int unitid) { - /* SB remote control */ - if (mixer->rc_type != RC_NONE && unitid == 0) { - /* read control code from device memory */ + if (mixer->rc_type == RC_NONE) + return; + /* unit ids specific to Extigy/Audigy 2 NX: */ + switch (unitid) { + case 0: /* remote control */ mixer->rc_urb->dev = mixer->chip->dev; usb_submit_urb(mixer->rc_urb, GFP_ATOMIC); + break; + case 4: /* digital in jack */ + case 7: /* line in jacks */ + case 19: /* speaker out jacks */ + case 20: /* headphones out jack */ + break; + default: + snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid); + break; } } @@ -1894,6 +1906,37 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) return 0; } +static void snd_audigy2nx_proc_read(snd_info_entry_t *entry, + snd_info_buffer_t *buffer) +{ + static const struct { + int unitid; + const char *name; + } jacks[] = { + {4, "dig in "}, + {7, "line in"}, + {19, "spk out"}, + {20, "hph out"}, + }; + struct usb_mixer_interface *mixer = entry->private_data; + int i, err; + u8 buf[3]; + + snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname); + for (i = 0; i < ARRAY_SIZE(jacks); ++i) { + snd_iprintf(buffer, "%s: ", jacks[i].name); + err = snd_usb_ctl_msg(mixer->chip->dev, + usb_rcvctrlpipe(mixer->chip->dev, 0), + GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | + USB_RECIP_INTERFACE, 0, + jacks[i].unitid << 8, buf, 3, 100); + if (err == 3 && buf[0] == 3) + snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); + else + snd_iprintf(buffer, "?\n"); + } +} + int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) { static snd_device_ops_t dev_ops = { @@ -1926,8 +1969,13 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) goto _error; if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) { + snd_info_entry_t *entry; + if ((err = snd_audigy2nx_controls_create(mixer)) < 0) goto _error; + if (!snd_card_proc_new(chip->card, "audigy2nx", &entry)) + snd_info_set_text_ops(entry, mixer, 1024, + snd_audigy2nx_proc_read); } err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); -- cgit From 1dcd3ec4728f9568ee204ceb46b0851be324a7f9 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 10 May 2005 14:51:40 +0200 Subject: [ALSA] usb-audio - bind to control interface instead of usb_device USB generic driver Bind the device files to the (first) audio control interface instead of the entire USB device. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 34d5f58985b..c360ab9783d 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -3129,8 +3129,6 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, snd_usb_audio_create_proc(chip); - snd_card_set_dev(card, &dev->dev); - *rchip = chip; return 0; } @@ -3212,6 +3210,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev, if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) { goto __error; } + snd_card_set_dev(chip->card, &intf->dev); break; } if (! chip) { -- cgit From 50cdbf1519a891bec4ce306c7bae397a0d8e7246 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 13 May 2005 07:44:13 +0200 Subject: [ALSA] usb-audio - sanity-check sync feedback frequency values USB generic driver Check that the synchronization feedback frequency values returned by the device are more or less near the nominal frequency. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index c360ab9783d..a6ed0d08337 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -452,17 +452,11 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs, if (urb->iso_frame_desc[0].status == 0 && urb->iso_frame_desc[0].actual_length == 3) { f = combine_triple((u8*)urb->transfer_buffer) << 2; -#if 0 - if (f < subs->freqn - (subs->freqn>>3) || f > subs->freqmax) { - snd_printd(KERN_WARNING "requested frequency %d (%u,%03uHz) out of range (current nominal %d (%u,%03uHz))\n", - f, f >> 14, (f & ((1 << 14) - 1) * 1000) / ((1 << 14) - 1), - subs->freqn, subs->freqn >> 14, (subs->freqn & ((1 << 14) - 1) * 1000) / ((1 << 14) - 1)); - continue; + if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { + spin_lock_irqsave(&subs->lock, flags); + subs->freqm = f; + spin_unlock_irqrestore(&subs->lock, flags); } -#endif - spin_lock_irqsave(&subs->lock, flags); - subs->freqm = f; - spin_unlock_irqrestore(&subs->lock, flags); } return 0; @@ -484,9 +478,11 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs, if (urb->iso_frame_desc[0].status == 0 && urb->iso_frame_desc[0].actual_length == 4) { f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff; - spin_lock_irqsave(&subs->lock, flags); - subs->freqm = f; - spin_unlock_irqrestore(&subs->lock, flags); + if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { + spin_lock_irqsave(&subs->lock, flags); + subs->freqm = f; + spin_unlock_irqrestore(&subs->lock, flags); + } } return 0; -- cgit From 29b16931f936fdbcd78995e66d0f5626f3afbda8 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 13 May 2005 07:50:28 +0200 Subject: [ALSA] usb-audio - avoid unnecessary double buffering USB generic driver When a USB packet boundary falls exactly on a buffer boundary, hwptr remains at the end of the buffer which causes an overflow in the next iteration and triggers double buffering although the next packet would actually be contiguous. This patch ensures that hwptr is always smaller than buffer_size. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a6ed0d08337..076da19a9e2 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -565,6 +565,8 @@ static int prepare_playback_urb(snd_usb_substream_t *subs, /* set the buffer pointer */ urb->transfer_buffer = runtime->dma_area + subs->hwptr * stride; subs->hwptr += offs; + if (subs->hwptr == runtime->buffer_size) + subs->hwptr = 0; } spin_unlock_irqrestore(&subs->lock, flags); urb->transfer_buffer_length = offs * stride; -- cgit From d3ff42fd2b4fddb5d779e9e03a2ea44147aa8048 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 17 May 2005 09:14:27 +0200 Subject: [ALSA] usb-audio - claim all interfaces for Roland USB MIDI devices USB generic driver Many Roland USB MIDI devices have two interfaces that are currently not used by the driver; claim them anyway. Signed-off-by: Clemens Ladisch --- sound/usb/usbquirks.h | 270 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 220 insertions(+), 50 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 00781fea211..f5135641b3e 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -203,11 +203,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", .product_name = "UM-4", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x000f, - .in_cables = 0x000f + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x000f, + .in_cables = 0x000f + } + }, + { + .ifnum = -1 + } } } }, @@ -216,11 +233,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "SC-8850", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x003f, - .in_cables = 0x003f + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x003f, + .in_cables = 0x003f + } + }, + { + .ifnum = -1 + } } } }, @@ -229,11 +263,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "U-8", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0005, - .in_cables = 0x0005 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0005, + .in_cables = 0x0005 + } + }, + { + .ifnum = -1 + } } } }, @@ -242,11 +293,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", .product_name = "UM-2", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0003, - .in_cables = 0x0003 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0003, + .in_cables = 0x0003 + } + }, + { + .ifnum = -1 + } } } }, @@ -255,11 +323,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "SC-8820", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0013, - .in_cables = 0x0013 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0013, + .in_cables = 0x0013 + } + }, + { + .ifnum = -1 + } } } }, @@ -268,11 +353,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "PC-300", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0001, - .in_cables = 0x0001 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } } } }, @@ -281,11 +383,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", .product_name = "UM-1", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0001, - .in_cables = 0x0001 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } } } }, @@ -294,11 +413,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "SK-500", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0013, - .in_cables = 0x0013 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0013, + .in_cables = 0x0013 + } + }, + { + .ifnum = -1 + } } } }, @@ -421,11 +557,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", .product_name = "SD-90", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x000f, - .in_cables = 0x000f + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x000f, + .in_cables = 0x000f + } + }, + { + .ifnum = -1 + } } } }, @@ -434,11 +587,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "MMP-2", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0001, - .in_cables = 0x0001 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } } } }, -- cgit From 604cf499256af85703bd4858da56e777ec71714d Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 17 May 2005 09:15:27 +0200 Subject: [ALSA] usb-audio - fix synchronization packet interval with Audigy 2 NX USB generic driver When a device does not provide the bRefresh field in its audio endpoint descriptors, use the bInterval field instead. Furthermore, increase the number of sync URBs for better queueing. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 076da19a9e2..a82412b8790 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -98,7 +98,7 @@ MODULE_PARM_DESC(async_unlink, "Use async unlink mode."); #define MAX_PACKS 10 #define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */ #define MAX_URBS 5 /* max. 20ms long packets */ -#define SYNC_URBS 2 /* always two urbs for sync */ +#define SYNC_URBS 4 /* always four urbs for sync */ #define MIN_PACKS_URB 1 /* minimum 1 packet per urb */ typedef struct snd_usb_substream snd_usb_substream_t; @@ -1240,8 +1240,13 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt) get_endpoint(alts, 1)->bRefresh >= 1 && get_endpoint(alts, 1)->bRefresh <= 9) subs->syncinterval = get_endpoint(alts, 1)->bRefresh; - else + else if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) subs->syncinterval = 1; + else if (get_endpoint(alts, 1)->bInterval >= 1 && + get_endpoint(alts, 1)->bInterval <= 16) + subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1; + else + subs->syncinterval = 3; } /* always fill max packet size */ -- cgit From 4d572776d4dfa2d5385a2ec3acec3cc059149e13 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 30 May 2005 17:30:32 +0200 Subject: [ALSA] Remove redundant NULL checks before kfree Timer Midlevel,ALSA sequencer,ALSA<-OSS sequencer,Digigram VX core I2C tea6330t,GUS Library,VIA82xx driver,VIA82xx-modem driver CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,YMFPCI driver Digigram VX Pocket driver,Common EMU synth,USB generic driver,USB USX2Y Checking a pointer for NULL before calling kfree() on it is redundant, kfree() deals with NULL pointers just fine. This patch removes such checks from sound/ This patch also makes another, but closely related, change. It avoids casting pointers about to be kfree()'ed. Signed-off-by: Jesper Juhl Signed-off-by: Takashi Iwai --- sound/usb/usbaudio.c | 12 ++++-------- sound/usb/usbmixer.c | 6 ++---- sound/usb/usx2y/usbusx2yaudio.c | 6 ++---- 3 files changed, 8 insertions(+), 16 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a82412b8790..a75695045f2 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -859,10 +859,8 @@ static void release_urb_ctx(snd_urb_ctx_t *u) usb_free_urb(u->urb); u->urb = NULL; } - if (u->buf) { - kfree(u->buf); - u->buf = NULL; - } + kfree(u->buf); + u->buf = NULL; } /* @@ -880,10 +878,8 @@ static void release_substream_urbs(snd_usb_substream_t *subs, int force) release_urb_ctx(&subs->dataurb[i]); for (i = 0; i < SYNC_URBS; i++) release_urb_ctx(&subs->syncurb[i]); - if (subs->tmpbuf) { - kfree(subs->tmpbuf); - subs->tmpbuf = NULL; - } + kfree(subs->tmpbuf); + subs->tmpbuf = NULL; subs->nurbs = 0; } diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 83ba665e5c6..e73c1c9d3e7 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -623,10 +623,8 @@ static struct usb_feature_control_info audio_feature_info[] = { /* private_free callback */ static void usb_mixer_elem_free(snd_kcontrol_t *kctl) { - if (kctl->private_data) { - kfree(kctl->private_data); - kctl->private_data = NULL; - } + kfree(kctl->private_data); + kctl->private_data = NULL; } diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 4c292e09006..62dfd28b3b0 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -401,10 +401,8 @@ static void usX2Y_urbs_release(snd_usX2Y_substream_t *subs) for (i = 0; i < NRURBS; i++) usX2Y_urb_release(subs->urb + i, subs != subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]); - if (subs->tmpbuf) { - kfree(subs->tmpbuf); - subs->tmpbuf = NULL; - } + kfree(subs->tmpbuf); + subs->tmpbuf = NULL; } /* * initialize a substream's urbs -- cgit From 77933d7276ee8fa0e2947641941a6f7a100a327b Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Wed, 27 Jul 2005 11:46:09 -0700 Subject: [PATCH] clean up inline static vs static inline `gcc -W' likes to complain if the static keyword is not at the beginning of the declaration. This patch fixes all remaining occurrences of "inline static" up with "static inline" in the entire kernel tree (140 occurrences in 47 files). While making this change I came across a few lines with trailing whitespace that I also fixed up, I have also added or removed a blank line or two here and there, but there are no functional changes in the patch. Signed-off-by: Jesper Juhl Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/usb/usbaudio.c | 8 ++++---- sound/usb/usbmixer.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a75695045f2..b5e734d975e 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -212,7 +212,7 @@ static snd_usb_audio_t *usb_chip[SNDRV_CARDS]; * convert a sampling rate into our full speed format (fs/1000 in Q16.16) * this will overflow at approx 524 kHz */ -inline static unsigned get_usb_full_speed_rate(unsigned int rate) +static inline unsigned get_usb_full_speed_rate(unsigned int rate) { return ((rate << 13) + 62) / 125; } @@ -221,19 +221,19 @@ inline static unsigned get_usb_full_speed_rate(unsigned int rate) * convert a sampling rate into USB high speed format (fs/8000 in Q16.16) * this will overflow at approx 4 MHz */ -inline static unsigned get_usb_high_speed_rate(unsigned int rate) +static inline unsigned get_usb_high_speed_rate(unsigned int rate) { return ((rate << 10) + 62) / 125; } /* convert our full speed USB rate into sampling rate in Hz */ -inline static unsigned get_full_speed_hz(unsigned int usb_rate) +static inline unsigned get_full_speed_hz(unsigned int usb_rate) { return (usb_rate * 125 + (1 << 12)) >> 13; } /* convert our high speed USB rate into sampling rate in Hz */ -inline static unsigned get_high_speed_hz(unsigned int usb_rate) +static inline unsigned get_high_speed_hz(unsigned int usb_rate) { return (usb_rate * 125 + (1 << 9)) >> 10; } diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index e73c1c9d3e7..fa7056f5caa 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -363,7 +363,7 @@ static int get_cur_ctl_value(usb_mixer_elem_info_t *cval, int validx, int *value } /* channel = 0: master, 1 = first channel */ -inline static int get_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int *value) +static inline int get_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int *value) { return get_ctl_value(cval, GET_CUR, (cval->control << 8) | channel, value); } @@ -399,7 +399,7 @@ static int set_cur_ctl_value(usb_mixer_elem_info_t *cval, int validx, int value) return set_ctl_value(cval, SET_CUR, validx, value); } -inline static int set_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int value) +static inline int set_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int value) { return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value); } -- cgit From 573567e07bb4470ff177f17d1adca3f3bd310221 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 27 Jun 2005 08:17:30 +0200 Subject: [ALSA] usb-audio - high speed audio support USB generic driver Add support for endpoints with bInterval > 1, and decoding of the wMaxPacketSize field of high-speed endpoints. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index b5e734d975e..facd9fc11c3 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -153,6 +153,7 @@ struct snd_usb_substream { unsigned int format; /* USB data format */ unsigned int datapipe; /* the data i/o pipe */ unsigned int syncpipe; /* 1 - async out or adaptive in */ + unsigned int datainterval; /* log_2 of data packet interval */ unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */ unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */ unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */ @@ -518,7 +519,8 @@ static int prepare_playback_urb(snd_usb_substream_t *subs, if (subs->fill_max) counts = subs->maxframesize; /* fixed */ else { - subs->phase = (subs->phase & 0xffff) + subs->freqm; + subs->phase = (subs->phase & 0xffff) + + (subs->freqm << subs->datainterval); counts = subs->phase >> 16; if (counts > subs->maxframesize) counts = subs->maxframesize; @@ -899,16 +901,19 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by else subs->freqn = get_usb_high_speed_rate(rate); subs->freqm = subs->freqn; - subs->freqmax = subs->freqn + (subs->freqn >> 2); /* max. allowed frequency */ - subs->phase = 0; - - /* calculate the max. size of packet */ - maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3)) >> 16; - if (subs->maxpacksize && maxsize > subs->maxpacksize) { - //snd_printd(KERN_DEBUG "maxsize %d is greater than defined size %d\n", - // maxsize, subs->maxpacksize); + /* calculate max. frequency */ + if (subs->maxpacksize) { + /* whatever fits into a max. size packet */ maxsize = subs->maxpacksize; + subs->freqmax = (maxsize / (frame_bits >> 3)) + << (16 - subs->datainterval); + } else { + /* no max. packet size: just take 25% higher than nominal */ + subs->freqmax = subs->freqn + (subs->freqn >> 2); + maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3)) + >> (16 - subs->datainterval); } + subs->phase = 0; if (subs->fill_max) subs->curpacksize = subs->maxpacksize; @@ -918,7 +923,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) urb_packs = nrpacks; else - urb_packs = nrpacks * 8; + urb_packs = (nrpacks * 8) >> subs->datainterval; /* allocate a temporary buffer for playback */ if (is_playback) { @@ -991,7 +996,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by u->urb->pipe = subs->datapipe; u->urb->transfer_flags = URB_ISO_ASAP; u->urb->number_of_packets = u->packets; - u->urb->interval = 1; + u->urb->interval = 1 << subs->datainterval; u->urb->context = u; u->urb->complete = snd_usb_complete_callback(snd_complete_urb); } @@ -1195,6 +1200,12 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt) subs->datapipe = usb_sndisocpipe(dev, ep); else subs->datapipe = usb_rcvisocpipe(dev, ep); + if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH && + get_endpoint(alts, 0)->bInterval >= 1 && + get_endpoint(alts, 0)->bInterval <= 4) + subs->datainterval = get_endpoint(alts, 0)->bInterval - 1; + else + subs->datainterval = 0; subs->syncpipe = subs->syncinterval = 0; subs->maxpacksize = fmt->maxpacksize; subs->fill_max = 0; @@ -2492,8 +2503,10 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) fp->altset_idx = i; fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; - /* FIXME: decode wMaxPacketSize of high bandwith endpoints */ fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); + if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) + fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) + * (fp->maxpacksize & 0x7ff); fp->attributes = csep[3]; /* some quirks for attributes here */ -- cgit From b4d3f9d452ec574e0ffb292267427f69bb470631 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 27 Jun 2005 08:18:27 +0200 Subject: [ALSA] usb-audio - fix capture of non-48k sample rates on Audigy 2 NX USB generic driver On the SB Audigy 2 NX, capturing with sample rates that are not a multiple of 48 kHz does not seem to work, so disable it. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index facd9fc11c3..c57b44511b5 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2408,10 +2408,9 @@ static int parse_audio_format(snd_usb_audio_t *chip, struct audioformat *fp, if (chip->usb_id == USB_ID(0x041e, 0x3000) || chip->usb_id == USB_ID(0x041e, 0x3020)) { if (fmt[3] == USB_FORMAT_TYPE_I && - stream == SNDRV_PCM_STREAM_PLAYBACK && fp->rates != SNDRV_PCM_RATE_48000 && fp->rates != SNDRV_PCM_RATE_96000) - return -1; /* use 48k only */ + return -1; } #endif return 0; -- cgit From 0ac2ac0ad7d1e8c84241d1c40b0d196b9b7c8104 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 1 Jul 2005 16:19:39 +0200 Subject: [ALSA] usb-audio: add support for an unknown Yamaha USB MIDI device USB generic driver Add a quirk for the Yamaha USB MIDI device with USB ID 0x103d. Signed-off-by: Clemens Ladisch --- sound/usb/usbquirks.h | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/usb') diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index f5135641b3e..cc2e3c9933e 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -116,6 +116,7 @@ YAMAHA_DEVICE(0x1039, NULL), YAMAHA_DEVICE(0x103a, NULL), YAMAHA_DEVICE(0x103b, NULL), YAMAHA_DEVICE(0x103c, NULL), +YAMAHA_DEVICE(0x103d, NULL), YAMAHA_DEVICE(0x2000, "DGP-7"), YAMAHA_DEVICE(0x2001, "DGP-5"), YAMAHA_DEVICE(0x2002, NULL), -- cgit From b1c6ef52e2623c81c2124801c783a903f6e5437a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 4 Jul 2005 09:18:46 +0200 Subject: [ALSA] usb-audio - enable high speed transfers with Audiy 2 NX USB generic driver This patch enables the boot commands to activate high speed mode (and associated sample formats like 8 channels with 24 bits at 96 kHz) on the SB Audigy 2 NX. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index c57b44511b5..aee3c0f28eb 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2938,8 +2938,6 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev) { -#if 0 - /* TODO: enable this when high speed synchronization actually works */ u8 buf = 1; snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a, @@ -2951,7 +2949,6 @@ static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev) 1, 2000, NULL, 0, 1000); return -ENODEV; } -#endif return 0; } -- cgit From 6155aff84b98b2aa35eaa4384b539dfbab86afcc Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 4 Jul 2005 09:20:42 +0200 Subject: [ALSA] usb-audio - rename QUIRK_MIDI_MOTU to QUIRK_MIDI_RAW USB generic driver Rename the protocol used by the MOTU FastLane to 'raw' because it might be useful with other devices, and there are other MOTU interfaces that do not use this protocol. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 2 +- sound/usb/usbaudio.h | 4 ++-- sound/usb/usbmidi.c | 18 +++++++++--------- sound/usb/usbquirks.h | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index aee3c0f28eb..3eaa08e3e6a 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2970,7 +2970,7 @@ static int snd_usb_create_quirk(snd_usb_audio_t *chip, case QUIRK_MIDI_YAMAHA: case QUIRK_MIDI_MIDIMAN: case QUIRK_MIDI_NOVATION: - case QUIRK_MIDI_MOTU: + case QUIRK_MIDI_RAW: case QUIRK_MIDI_EMAGIC: return snd_usb_create_midi_interface(chip, iface, quirk); case QUIRK_COMPOSITE: diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index aedb42aaa74..a8791220547 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -165,7 +165,7 @@ struct snd_usb_audio { #define QUIRK_AUDIO_EDIROL_UA1000 8 #define QUIRK_IGNORE_INTERFACE 9 #define QUIRK_MIDI_NOVATION 10 -#define QUIRK_MIDI_MOTU 11 +#define QUIRK_MIDI_RAW 11 #define QUIRK_MIDI_EMAGIC 12 typedef struct snd_usb_audio_quirk snd_usb_audio_quirk_t; @@ -205,7 +205,7 @@ struct snd_usb_midi_endpoint_info { /* for QUIRK_IGNORE_INTERFACE, data is NULL */ -/* for QUIRK_MIDI_NOVATION and _MOTU, data is NULL */ +/* for QUIRK_MIDI_NOVATION and _RAW, data is NULL */ /* for QUIRK_MIDI_EMAGIC, data points to a snd_usb_midi_endpoint_info * structure (out_cables and in_cables only) */ diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index bee70068dce..5c754879c2b 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -524,16 +524,16 @@ static struct usb_protocol_ops snd_usbmidi_novation_ops = { }; /* - * Mark of the Unicorn USB MIDI protocol: raw MIDI. + * "raw" protocol: used by the MOTU FastLane. */ -static void snd_usbmidi_motu_input(snd_usb_midi_in_endpoint_t* ep, - uint8_t* buffer, int buffer_length) +static void snd_usbmidi_raw_input(snd_usb_midi_in_endpoint_t* ep, + uint8_t* buffer, int buffer_length) { snd_usbmidi_input_data(ep, 0, buffer, buffer_length); } -static void snd_usbmidi_motu_output(snd_usb_midi_out_endpoint_t* ep) +static void snd_usbmidi_raw_output(snd_usb_midi_out_endpoint_t* ep) { int count; @@ -549,9 +549,9 @@ static void snd_usbmidi_motu_output(snd_usb_midi_out_endpoint_t* ep) ep->urb->transfer_buffer_length = count; } -static struct usb_protocol_ops snd_usbmidi_motu_ops = { - .input = snd_usbmidi_motu_input, - .output = snd_usbmidi_motu_output, +static struct usb_protocol_ops snd_usbmidi_raw_ops = { + .input = snd_usbmidi_raw_input, + .output = snd_usbmidi_raw_output, }; /* @@ -1505,8 +1505,8 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip, umidi->usb_protocol_ops = &snd_usbmidi_novation_ops; err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; - case QUIRK_MIDI_MOTU: - umidi->usb_protocol_ops = &snd_usbmidi_motu_ops; + case QUIRK_MIDI_RAW: + umidi->usb_protocol_ops = &snd_usbmidi_raw_ops; err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; case QUIRK_MIDI_EMAGIC: diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index cc2e3c9933e..ed1eba1ef5c 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -1269,7 +1269,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), .data = & (const snd_usb_audio_quirk_t[]) { { .ifnum = 0, - .type = QUIRK_MIDI_MOTU + .type = QUIRK_MIDI_RAW }, { .ifnum = 1, -- cgit From bbd4615cdb68de943b2814e956ec14899606dc45 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 4 Jul 2005 09:21:45 +0200 Subject: [ALSA] usb-audio - use bDeviceSubClass to detect MOTU FastLane USB generic driver MOTU builds other USB MIDI interfaces with the same product ID as the FastLane, so we have to check the bDeviceSubClass field to differentiate between them. Signed-off-by: Clemens Ladisch --- sound/usb/usbquirks.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sound/usb') diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index ed1eba1ef5c..67796430e58 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -1260,7 +1260,12 @@ YAMAHA_DEVICE(0x7010, "UB99"), /* Mark of the Unicorn devices */ { /* thanks to Robert A. Lerche */ - USB_DEVICE(0x07fd, 0x0001), + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | + USB_DEVICE_ID_MATCH_PRODUCT | + USB_DEVICE_ID_MATCH_DEV_SUBCLASS, + .idVendor = 0x07fd, + .idProduct = 0x0001, + .bDeviceSubClass = 2, .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "MOTU", .product_name = "Fastlane", -- cgit From b27c187f95cd6c9f13f26a5088bea384ac557b45 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Sat, 9 Jul 2005 10:54:37 +0200 Subject: [ALSA] Fix-up sleeping in sound/usb USB generic driver,USB USX2Y Description: Fix-up sleeping in sound/usb. Replace big_mdelay() with msleep() to guarantee the task delays as expected. This also involved replacing/removing custom sleep functions. Patch is compile-tested. Signed-off-by: Nishanth Aravamudan Signed-off-by: Jaroslav Kysela --- sound/usb/usbaudio.c | 4 ++-- sound/usb/usx2y/usX2Yhwdep.c | 3 +-- sound/usb/usx2y/usx2yhwdeppcm.c | 6 ++---- 3 files changed, 5 insertions(+), 8 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 3eaa08e3e6a..f2b760d8d77 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -792,7 +792,7 @@ static int start_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) */ static int wait_clear_urbs(snd_usb_substream_t *subs) { - int timeout = HZ; + unsigned long end_time = jiffies + msecs_to_jiffies(1000); unsigned int i; int alive; @@ -812,7 +812,7 @@ static int wait_clear_urbs(snd_usb_substream_t *subs) break; set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); - } while (--timeout > 0); + } while (time_before(jiffies, end_time)); if (alive) snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); return 0; diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index bef9b0c142c..0281a362857 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -232,8 +232,7 @@ static int snd_usX2Y_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) if (err) return err; if (dsp->index == 1) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/4); // give the device some time + msleep(250); // give the device some time err = usX2Y_AsyncSeq04_init(priv); if (err) { snd_printk("usX2Y_AsyncSeq04_init error \n"); diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index bb2c8e9000c..ef28061287f 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -50,6 +50,7 @@ Currently rawusb dma pcm buffer transport (this file) is only available to snd-usb-usx2y. */ +#include #include "usbusx2yaudio.c" #if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) && USX2Y_NRPACKS == 1) @@ -520,11 +521,8 @@ static int snd_usX2Y_usbpcm_prepare(snd_pcm_substream_t *substream) usX2Y->hwdep_pcm_shm->playback_iso_start = -1; if (atomic_read(&subs->state) < state_PREPARED) { while (usX2Y_iso_frames_per_buffer(runtime, usX2Y) > usX2Y->hwdep_pcm_shm->captured_iso_frames) { - signed long timeout; snd_printd("Wait: iso_frames_per_buffer=%i,captured_iso_frames=%i\n", usX2Y_iso_frames_per_buffer(runtime, usX2Y), usX2Y->hwdep_pcm_shm->captured_iso_frames); - set_current_state(TASK_INTERRUPTIBLE); - timeout = schedule_timeout(HZ/100 + 1); - if (signal_pending(current)) { + if (msleep_interruptible(10)) { err = -ERESTARTSYS; goto up_prepare_mutex; } -- cgit From f38275fe994c333b809796230f4f98090f8d919b Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 25 Jul 2005 16:17:29 +0200 Subject: [ALSA] usb-audio - add support for Miditech USB MIDI keyboards USB generic driver Add support for Miditech Midistart and MidiStudio keyboards (another case of devices using the standard protocol but having no descriptors). Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 1 + sound/usb/usbaudio.h | 3 +++ sound/usb/usbmidi.c | 3 +++ sound/usb/usbquirks.h | 19 +++++++++++++++++++ 4 files changed, 26 insertions(+) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index f2b760d8d77..9a0b0899d15 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2972,6 +2972,7 @@ static int snd_usb_create_quirk(snd_usb_audio_t *chip, case QUIRK_MIDI_NOVATION: case QUIRK_MIDI_RAW: case QUIRK_MIDI_EMAGIC: + case QUIRK_MIDI_MIDITECH: return snd_usb_create_midi_interface(chip, iface, quirk); case QUIRK_COMPOSITE: return create_composite_quirk(chip, iface, quirk); diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index a8791220547..c1415f4b600 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -167,6 +167,7 @@ struct snd_usb_audio { #define QUIRK_MIDI_NOVATION 10 #define QUIRK_MIDI_RAW 11 #define QUIRK_MIDI_EMAGIC 12 +#define QUIRK_MIDI_MIDITECH 13 typedef struct snd_usb_audio_quirk snd_usb_audio_quirk_t; typedef struct snd_usb_midi_endpoint_info snd_usb_midi_endpoint_info_t; @@ -210,6 +211,8 @@ struct snd_usb_midi_endpoint_info { /* for QUIRK_MIDI_EMAGIC, data points to a snd_usb_midi_endpoint_info * structure (out_cables and in_cables only) */ +/* for QUIRK_MIDI_MIDITECH, data is NULL */ + /* */ diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 5c754879c2b..5778a9b725e 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -1515,6 +1515,9 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip, sizeof(snd_usb_midi_endpoint_info_t)); err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1); break; + case QUIRK_MIDI_MIDITECH: + err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); + break; default: snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); err = -ENXIO; diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 67796430e58..f74e652a1e5 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -1378,6 +1378,25 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +{ + USB_DEVICE(0x4752, 0x0011), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "Miditech", + .product_name = "Midistart-2", + .ifnum = 0, + .type = QUIRK_MIDI_MIDITECH + } +}, +{ + USB_DEVICE(0x7104, 0x2202), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "Miditech", + .product_name = "MidiStudio-2", + .ifnum = 0, + .type = QUIRK_MIDI_MIDITECH + } +}, + { /* * Some USB MIDI devices don't have an audio control interface, -- cgit From 854af9578cb84e4ca3cb1551a6be40c4e81bb455 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 25 Jul 2005 16:19:10 +0200 Subject: [ALSA] usb-audio - change quirk type handling USB generic driver Make the quirk type an enum instead of a #defined integer, and use a table for the quirk constructor functions instead of a big switch statement. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 59 ++++++++++++++++++++++++++++++---------------------- sound/usb/usbaudio.h | 35 +++++++++++++++++-------------- 2 files changed, 53 insertions(+), 41 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 9a0b0899d15..8298c462c29 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2735,7 +2735,8 @@ static int create_standard_interface_quirk(snd_usb_audio_t *chip, * to detect the sample rate is by looking at wMaxPacketSize. */ static int create_ua700_ua25_quirk(snd_usb_audio_t *chip, - struct usb_interface *iface) + struct usb_interface *iface, + const snd_usb_audio_quirk_t *quirk) { static const struct audioformat ua_format = { .format = SNDRV_PCM_FORMAT_S24_3LE, @@ -2826,7 +2827,9 @@ static int create_ua700_ua25_quirk(snd_usb_audio_t *chip, /* * Create a stream for an Edirol UA-1000 interface. */ -static int create_ua1000_quirk(snd_usb_audio_t *chip, struct usb_interface *iface) +static int create_ua1000_quirk(snd_usb_audio_t *chip, + struct usb_interface *iface, + const snd_usb_audio_quirk_t *quirk) { static const struct audioformat ua1000_format = { .format = SNDRV_PCM_FORMAT_S32_LE, @@ -2903,6 +2906,13 @@ static int create_composite_quirk(snd_usb_audio_t *chip, return 0; } +static int ignore_interface_quirk(snd_usb_audio_t *chip, + struct usb_interface *iface, + const snd_usb_audio_quirk_t *quirk) +{ + return 0; +} + /* * boot quirks @@ -2965,29 +2975,28 @@ static int snd_usb_create_quirk(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk) { - switch (quirk->type) { - case QUIRK_MIDI_FIXED_ENDPOINT: - case QUIRK_MIDI_YAMAHA: - case QUIRK_MIDI_MIDIMAN: - case QUIRK_MIDI_NOVATION: - case QUIRK_MIDI_RAW: - case QUIRK_MIDI_EMAGIC: - case QUIRK_MIDI_MIDITECH: - return snd_usb_create_midi_interface(chip, iface, quirk); - case QUIRK_COMPOSITE: - return create_composite_quirk(chip, iface, quirk); - case QUIRK_AUDIO_FIXED_ENDPOINT: - return create_fixed_stream_quirk(chip, iface, quirk); - case QUIRK_AUDIO_STANDARD_INTERFACE: - case QUIRK_MIDI_STANDARD_INTERFACE: - return create_standard_interface_quirk(chip, iface, quirk); - case QUIRK_AUDIO_EDIROL_UA700_UA25: - return create_ua700_ua25_quirk(chip, iface); - case QUIRK_AUDIO_EDIROL_UA1000: - return create_ua1000_quirk(chip, iface); - case QUIRK_IGNORE_INTERFACE: - return 0; - default: + typedef int (*quirk_func_t)(snd_usb_audio_t *, struct usb_interface *, + const snd_usb_audio_quirk_t *); + static const quirk_func_t quirk_funcs[] = { + [QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk, + [QUIRK_COMPOSITE] = create_composite_quirk, + [QUIRK_MIDI_STANDARD_INTERFACE] = snd_usb_create_midi_interface, + [QUIRK_MIDI_FIXED_ENDPOINT] = snd_usb_create_midi_interface, + [QUIRK_MIDI_YAMAHA] = snd_usb_create_midi_interface, + [QUIRK_MIDI_MIDIMAN] = snd_usb_create_midi_interface, + [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_AUDIO_STANDARD_INTERFACE] = create_standard_interface_quirk, + [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, + [QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk, + [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, + }; + + if (quirk->type < QUIRK_TYPE_COUNT) { + return quirk_funcs[quirk->type](chip, iface, quirk); + } else { snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); return -ENXIO; } diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index c1415f4b600..ad9eab211d8 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -153,21 +153,24 @@ struct snd_usb_audio { #define QUIRK_NO_INTERFACE -2 #define QUIRK_ANY_INTERFACE -1 -/* quirk type */ -#define QUIRK_MIDI_FIXED_ENDPOINT 0 -#define QUIRK_MIDI_YAMAHA 1 -#define QUIRK_MIDI_MIDIMAN 2 -#define QUIRK_COMPOSITE 3 -#define QUIRK_AUDIO_FIXED_ENDPOINT 4 -#define QUIRK_AUDIO_STANDARD_INTERFACE 5 -#define QUIRK_MIDI_STANDARD_INTERFACE 6 -#define QUIRK_AUDIO_EDIROL_UA700_UA25 7 -#define QUIRK_AUDIO_EDIROL_UA1000 8 -#define QUIRK_IGNORE_INTERFACE 9 -#define QUIRK_MIDI_NOVATION 10 -#define QUIRK_MIDI_RAW 11 -#define QUIRK_MIDI_EMAGIC 12 -#define QUIRK_MIDI_MIDITECH 13 +enum quirk_type { + QUIRK_IGNORE_INTERFACE, + QUIRK_COMPOSITE, + QUIRK_MIDI_STANDARD_INTERFACE, + QUIRK_MIDI_FIXED_ENDPOINT, + QUIRK_MIDI_YAMAHA, + QUIRK_MIDI_MIDIMAN, + QUIRK_MIDI_NOVATION, + QUIRK_MIDI_RAW, + QUIRK_MIDI_EMAGIC, + QUIRK_MIDI_MIDITECH, + QUIRK_AUDIO_STANDARD_INTERFACE, + QUIRK_AUDIO_FIXED_ENDPOINT, + QUIRK_AUDIO_EDIROL_UA700_UA25, + QUIRK_AUDIO_EDIROL_UA1000, + + QUIRK_TYPE_COUNT +}; typedef struct snd_usb_audio_quirk snd_usb_audio_quirk_t; typedef struct snd_usb_midi_endpoint_info snd_usb_midi_endpoint_info_t; @@ -176,7 +179,7 @@ struct snd_usb_audio_quirk { const char *vendor_name; const char *product_name; int16_t ifnum; - int16_t type; + uint16_t type; const void *data; }; -- cgit