From mboxrd@z Thu Jan 1 00:00:00 1970 From: Takashi Iwai Subject: Re: status of usb audio driver Date: Thu, 13 Jun 2002 12:39:14 +0200 Sender: alsa-devel-admin@lists.sourceforge.net Message-ID: References: <3D06D91D.1080104@boosthardware.com> <3D07564B.4050908@boosthardware.com> <3D0760FC.5060906@boosthardware.com> <3D0772F1.6090009@boosthardware.com> <3D077B61.7030902@boosthardware.com> <3D078560.4030707@boosthardware.com> Mime-Version: 1.0 (generated by SEMI 1.14.3 - "Ushinoya") Content-Type: multipart/mixed; boundary="Multipart_Thu_Jun_13_12:39:14_2002-1" Return-path: In-Reply-To: <3D078560.4030707@boosthardware.com> Errors-To: alsa-devel-admin@lists.sourceforge.net List-Help: List-Post: List-Subscribe: , List-Unsubscribe: , List-Archive: To: Patrick Shirkey Cc: alsa-devel@lists.sourceforge.net List-Id: alsa-devel@alsa-project.org --Multipart_Thu_Jun_13_12:39:14_2002-1 Content-Type: text/plain; charset=US-ASCII At Thu, 13 Jun 2002 02:31:12 +0900, Patrick Shirkey wrote: > > Takashi Iwai wrote: > > At Thu, 13 Jun 2002 01:48:33 +0900, > > Patrick Shirkey wrote: > > > >>Patrick Shirkey wrote: > >> > >>>Patrick Shirkey wrote: > >>> > >>> > >>>>i have been testing the sound and I am getting playback although at > >>>>this point I can get sound out of hw:2,0 and hw:2,2 they are both the > >>>>left channels. The sound is scratchy but it is there :) > >>>> > >>> > >>>The sound is actually coming through output 2 and 4 on the sound card > >>>even though I'm using hw:2,0 or hw:2,2. > >>> > >> > >>When I use the first two pcm devices the sound is sent through output 2 > >>on the card and when I use the third the sound is sent through output 4. actually the endpoints of the first two pcm streams are identical. is the sound only mono? on the description, it's defined as stereo streams. so i guess quattro has two stereo streams, corresponding #0 (or #1) and #2. it seems that the stream #0 has only 16bit 44.1kHz at most, while the stream #1 supports 16/24bit 48kHz (although 24bit-3bytes format is not supported on alsa yet). > > i committed a minor change to cvs. > > now endpoints will be shown in each proc file. > > could you apply and send me the output of each proc file? > > i'd like to know whether really endpoints are parsed correctly. > > > > > > From the looks of things they are not. well, it looks ok. the stream corresponds correctly to the description. > > > > >>I have also tested capture and the card is not working with that yet. > >> > >>It will attempt to record for a few seconds but will not write to a file > >>or produce any noise either with direct monitoring enabled or not. Also > >> recording locks the mouse until either it has finished or is ctrl+c'd. > > > > > > hmm, this sounds bad. > > i'm not sure whether this is a general capture problem on usb audio. > > i'll borrow a usb mic tomorrow and test with it. i've tested usb mic from Labtec, and it works. so the problem is specific to the hardware, or multi-channels... anyway, could you try the attached patch? Takashi --Multipart_Thu_Jun_13_12:39:14_2002-1 Content-Type: application/octet-stream Content-Disposition: attachment; filename="usb-fix2.dif" Content-Transfer-Encoding: 7bit Index: alsa-driver/usb/usbaudio.c =================================================================== RCS file: /suse/tiwai/cvs/alsa/alsa-driver/usb/usbaudio.c,v retrieving revision 1.11 diff -u -r1.11 usbaudio.c --- alsa-driver/usb/usbaudio.c 12 Jun 2002 16:56:40 -0000 1.11 +++ alsa-driver/usb/usbaudio.c 13 Jun 2002 10:36:04 -0000 @@ -42,7 +42,7 @@ #include "usbaudio.h" -EXPORT_NO_SYMBOLS; +EXPORT_NO_SYMBOLS; /* for kernels < 2.5 */ MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("USB Audio"); @@ -84,6 +84,7 @@ unsigned char altset_idx; /* array index of altenate setting */ unsigned char attributes; /* corresponding attributes of cs endpoint */ unsigned char endpoint; /* endpoint */ + unsigned char ep_attr; /* endpoint attributes */ unsigned int rates; /* rate bitmasks */ int rate_min, rate_max; /* min/max rates */ int nr_rates; /* number of rate table entries */ @@ -257,7 +258,7 @@ { unsigned long flags; unsigned char *cp; - int stride, i, len; + int stride, i, len, oldptr; stride = runtime->frame_bits >> 3; @@ -268,20 +269,25 @@ len = urb->iso_frame_desc[i].actual_length / stride; if (! len) continue; + /* update the current pointer */ spin_lock_irqsave(&subs->lock, flags); + oldptr = subs->hwptr_done; + subs->hwptr_done += len; + if (subs->hwptr_done >= runtime->buffer_size) + subs->hwptr_done -= runtime->buffer_size; + subs->transfer_done += len; + spin_unlock_irqrestore(&subs->lock, flags); /* copy a data chunk */ - if (subs->hwptr_done + len >= runtime->buffer_size) { - int cnt = runtime->buffer_size - subs->hwptr_done; + if (oldptr + len >= runtime->buffer_size) { + int cnt = runtime->buffer_size - oldptr; int blen = cnt * stride; - memcpy(runtime->dma_area + subs->hwptr_done * stride, cp, blen); + memcpy(runtime->dma_area + oldptr * stride, cp, blen); memcpy(runtime->dma_area, cp + blen, len * stride - blen); - subs->hwptr_done = len - cnt; } else { memcpy(runtime->dma_area + subs->hwptr_done * stride, cp, len * stride); - subs->hwptr_done += len; } /* update the pointer, call callback if necessary */ - subs->transfer_done += len; + spin_lock_irqsave(&subs->lock, flags); if (subs->transfer_done >= runtime->period_size) { subs->transfer_done -= runtime->period_size; spin_unlock_irqrestore(&subs->lock, flags); @@ -727,8 +733,8 @@ /* calculate the max. size of packet */ maxsize = ((subs->freqmax + 0x3fff) * (runtime->frame_bits >> 3)) >> 14; if (subs->maxpacksize && maxsize > subs->maxpacksize) { - snd_printd(KERN_DEBUG "maxsize %d is greater than defined size %d\n", - maxsize, subs->maxpacksize); + //snd_printd(KERN_DEBUG "maxsize %d is greater than defined size %d\n", + // maxsize, subs->maxpacksize); maxsize = subs->maxpacksize; } @@ -851,6 +857,63 @@ return NULL; } + +/* FIXME: stolen from usb/message.c + * alternate setting value doesn't match always with the array index. + * let's see whether this works... + */ +static void hack_usb_set_maxpacket(struct usb_device *dev) +{ + int i, b; + + for (i=0; iactconfig->bNumInterfaces; i++) { + struct usb_interface *ifp = dev->actconfig->interface + i; + struct usb_interface_descriptor *as = ifp->altsetting + ifp->act_altsetting; + struct usb_endpoint_descriptor *ep = as->endpoint; + int e; + + for (e=0; ebNumEndpoints; e++) { + b = ep[e].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + if (usb_endpoint_out(ep[e].bEndpointAddress)) { + if (ep[e].wMaxPacketSize > dev->epmaxpacketout[b]) + dev->epmaxpacketout[b] = ep[e].wMaxPacketSize; + } + else { + if (ep[e].wMaxPacketSize > dev->epmaxpacketin [b]) + dev->epmaxpacketin [b] = ep[e].wMaxPacketSize; + } + } + } +} + +static int hack_usb_set_interface(struct usb_device *dev, int interface, int alt_idx, int alternate) +{ + struct usb_interface *iface; + struct usb_interface_descriptor *iface_as; + int i, ret; + + iface = usb_ifnum_to_if(dev, interface); + if (!iface) + return -EINVAL; + if (iface->num_altsetting == 1) + return 0; + + if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, + alternate, + interface, NULL, 0, HZ * 5)) < 0) + return ret; + + iface->act_altsetting = alt_idx; + iface_as = &iface->altsetting[alt_idx]; + for (i = 0; i < iface_as->bNumEndpoints; i++) { + u8 ep = iface_as->endpoint[i].bEndpointAddress; + usb_settoggle(dev, ep&USB_ENDPOINT_NUMBER_MASK, usb_endpoint_out(ep), 0); + } + hack_usb_set_maxpacket(dev); + return 0; +} + /* * find a matching format and set up the interface */ @@ -868,8 +931,8 @@ fmt = find_format(subs, runtime); if (! fmt) { - snd_printd(KERN_DEBUG "cannot set format: format = %d, rate = %d, channels = %d\n", - runtime->format, runtime->rate, runtime->channels); + snd_printd(KERN_DEBUG "cannot set format: format = %s, rate = %d, channels = %d\n", + snd_pcm_format_name(runtime->format), runtime->rate, runtime->channels); return -EINVAL; } @@ -916,7 +979,7 @@ } /* set interface */ - if (usb_set_interface(dev, iface->altsetting->bInterfaceNumber, fmt->altset_idx) < 0) { + if (hack_usb_set_interface(dev, subs->interface, fmt->altset_idx, fmt->altsetting) < 0) { snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n", dev->devnum, subs->interface, fmt->altsetting); return -EIO; @@ -926,7 +989,8 @@ /* if endpoint has pitch control, enable it */ if (fmt->attributes & EP_CS_ATTR_PITCH_CONTROL) { data[0] = 1; - if ((err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, + if ((err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, + USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, PITCH_CONTROL << 8, ep, data, 1, HZ)) < 0) { snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n", dev->devnum, subs->interface, ep); @@ -938,16 +1002,18 @@ data[0] = runtime->rate; data[1] = runtime->rate >> 8; data[2] = runtime->rate >> 16; - if ((err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, + if ((err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, + USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) { - snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d\n", - dev->devnum, subs->interface, ep, runtime->rate); + snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep 0x%x\n", + dev->devnum, subs->interface, fmt->altsetting, runtime->rate, ep); return err; } - if ((err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, + if ((err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, + USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) { - snd_printk(KERN_ERR "%d:%d:%d: cannot get freq\n", - dev->devnum, subs->interface, ep); + snd_printk(KERN_ERR "%d:%d:%d: cannot get freq at ep 0x%x\n", + dev->devnum, subs->interface, fmt->altsetting, ep); return err; } runtime->rate = data[0] | (data[1] << 8) | (data[2] << 16); @@ -1091,9 +1157,7 @@ { snd_usb_stream_t *as = snd_pcm_substream_chip(substream); snd_usb_substream_t *subs = &as->substream[direction]; - struct usb_interface *iface; - iface = &subs->dev->actconfig->interface[subs->interface]; - usb_set_interface(subs->dev, iface->altsetting->bInterfaceNumber, 0); + usb_set_interface(subs->dev, subs->interface, 0); release_substream_urbs(subs); subs->pcm_substream = NULL; return 0; @@ -1223,7 +1287,8 @@ static struct usb_device_id usb_audio_ids [] = { { match_flags: (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), - bInterfaceClass: USB_CLASS_AUDIO, bInterfaceSubClass: 1}, + bInterfaceClass: USB_CLASS_AUDIO, + bInterfaceSubClass: USB_SUBCLASS_AUDIO_CONTROL }, { } /* Terminating entry */ }; @@ -1284,7 +1349,7 @@ alts = &iface->altsetting[i]; /* skip invalid one */ if (alts->bInterfaceClass != USB_CLASS_AUDIO || - alts->bInterfaceSubClass != 2 || + alts->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING || alts->bNumEndpoints < 1) continue; /* must be isochronous */ @@ -1460,6 +1525,7 @@ fp->altsetting = altno; fp->altset_idx = i; fp->endpoint = alts->endpoint[0].bEndpointAddress; + fp->ep_attr = alts->endpoint[0].bmAttributes; fp->channels = channels; fp->attributes = csep[3]; @@ -1538,15 +1604,19 @@ static void proc_dump_substream_formats(snd_usb_substream_t *subs, snd_info_buffer_t *buffer) { struct list_head *p; + static char *sync_types[4] = { + "NONE", "ASYNC", "ADAPTIVE", "SYNC" + }; list_for_each(p, &subs->fmt_list) { struct audioformat *fp; fp = list_entry(p, struct audioformat, list); snd_iprintf(buffer, " Format: %s\n", snd_pcm_format_name(fp->format)); snd_iprintf(buffer, " Channels: %d\n", fp->channels); - snd_iprintf(buffer, " Endpoint: %d %s\n", + snd_iprintf(buffer, " Endpoint: %d %s (%s)\n", fp->endpoint & USB_ENDPOINT_NUMBER_MASK, - fp->endpoint & USB_DIR_IN ? "IN" : "OUT"); + fp->endpoint & USB_DIR_IN ? "IN" : "OUT", + sync_types[(fp->ep_attr & EP_ATTR_MASK) >> 2]); if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) { snd_iprintf(buffer, " Rates: %d - %d (continous)\n", fp->rate_min, fp->rate_max); @@ -1724,7 +1794,7 @@ } iface = &config->interface[j]; if (iface->altsetting[0].bInterfaceClass != USB_CLASS_AUDIO || - iface->altsetting[0].bInterfaceSubClass != 2) { + iface->altsetting[0].bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING) { snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n", dev->devnum, ctrlif, j, iface->altsetting[0].bInterfaceClass); /* skip non-supported classes */ continue; @@ -1787,7 +1857,6 @@ static int snd_usb_audio_free(snd_usb_audio_t *chip) { - //snd_usb_proc_done(chip); down(®ister_mutex); usb_chip[chip->index] = NULL; up(®ister_mutex); Index: alsa-driver/usb/usbaudio.h =================================================================== RCS file: /suse/tiwai/cvs/alsa/alsa-driver/usb/usbaudio.h,v retrieving revision 1.6 diff -u -r1.6 usbaudio.h --- alsa-driver/usb/usbaudio.h 12 Jun 2002 12:56:14 -0000 1.6 +++ alsa-driver/usb/usbaudio.h 13 Jun 2002 09:31:24 -0000 @@ -27,6 +27,9 @@ /* */ +#define USB_SUBCLASS_AUDIO_CONTROL 0x01 +#define USB_SUBCLASS_AUDIO_STREAMING 0x02 + #define USB_DT_CS_DEVICE 0x21 #define USB_DT_CS_CONFIG 0x22 #define USB_DT_CS_STRING 0x23 --Multipart_Thu_Jun_13_12:39:14_2002-1-- _______________________________________________________________ Don't miss the 2002 Sprint PCS Application Developer's Conference August 25-28 in Las Vegas - http://devcon.sprintpcs.com/adp/index.cfm?source=osdntextlink