diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2005-06-27 02:17:30 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-07-28 06:09:25 -0400 |
commit | 573567e07bb4470ff177f17d1adca3f3bd310221 (patch) | |
tree | 7a5853dd8f22f0117a9bee93252bac13ff57bd61 /sound/usb/usbaudio.c | |
parent | b0af0de5cb57c96b0c3d739005172152b7de0ce8 (diff) |
[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 <clemens@ladisch.de>
Diffstat (limited to 'sound/usb/usbaudio.c')
-rw-r--r-- | sound/usb/usbaudio.c | 37 |
1 files changed, 25 insertions, 12 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index b5e734d975e0..facd9fc11c3c 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
@@ -153,6 +153,7 @@ struct snd_usb_substream { | |||
153 | unsigned int format; /* USB data format */ | 153 | unsigned int format; /* USB data format */ |
154 | unsigned int datapipe; /* the data i/o pipe */ | 154 | unsigned int datapipe; /* the data i/o pipe */ |
155 | unsigned int syncpipe; /* 1 - async out or adaptive in */ | 155 | unsigned int syncpipe; /* 1 - async out or adaptive in */ |
156 | unsigned int datainterval; /* log_2 of data packet interval */ | ||
156 | unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */ | 157 | unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */ |
157 | unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */ | 158 | unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */ |
158 | unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */ | 159 | 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, | |||
518 | if (subs->fill_max) | 519 | if (subs->fill_max) |
519 | counts = subs->maxframesize; /* fixed */ | 520 | counts = subs->maxframesize; /* fixed */ |
520 | else { | 521 | else { |
521 | subs->phase = (subs->phase & 0xffff) + subs->freqm; | 522 | subs->phase = (subs->phase & 0xffff) |
523 | + (subs->freqm << subs->datainterval); | ||
522 | counts = subs->phase >> 16; | 524 | counts = subs->phase >> 16; |
523 | if (counts > subs->maxframesize) | 525 | if (counts > subs->maxframesize) |
524 | counts = subs->maxframesize; | 526 | counts = subs->maxframesize; |
@@ -899,16 +901,19 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by | |||
899 | else | 901 | else |
900 | subs->freqn = get_usb_high_speed_rate(rate); | 902 | subs->freqn = get_usb_high_speed_rate(rate); |
901 | subs->freqm = subs->freqn; | 903 | subs->freqm = subs->freqn; |
902 | subs->freqmax = subs->freqn + (subs->freqn >> 2); /* max. allowed frequency */ | 904 | /* calculate max. frequency */ |
903 | subs->phase = 0; | 905 | if (subs->maxpacksize) { |
904 | 906 | /* whatever fits into a max. size packet */ | |
905 | /* calculate the max. size of packet */ | ||
906 | maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3)) >> 16; | ||
907 | if (subs->maxpacksize && maxsize > subs->maxpacksize) { | ||
908 | //snd_printd(KERN_DEBUG "maxsize %d is greater than defined size %d\n", | ||
909 | // maxsize, subs->maxpacksize); | ||
910 | maxsize = subs->maxpacksize; | 907 | maxsize = subs->maxpacksize; |
908 | subs->freqmax = (maxsize / (frame_bits >> 3)) | ||
909 | << (16 - subs->datainterval); | ||
910 | } else { | ||
911 | /* no max. packet size: just take 25% higher than nominal */ | ||
912 | subs->freqmax = subs->freqn + (subs->freqn >> 2); | ||
913 | maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3)) | ||
914 | >> (16 - subs->datainterval); | ||
911 | } | 915 | } |
916 | subs->phase = 0; | ||
912 | 917 | ||
913 | if (subs->fill_max) | 918 | if (subs->fill_max) |
914 | subs->curpacksize = subs->maxpacksize; | 919 | subs->curpacksize = subs->maxpacksize; |
@@ -918,7 +923,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by | |||
918 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) | 923 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) |
919 | urb_packs = nrpacks; | 924 | urb_packs = nrpacks; |
920 | else | 925 | else |
921 | urb_packs = nrpacks * 8; | 926 | urb_packs = (nrpacks * 8) >> subs->datainterval; |
922 | 927 | ||
923 | /* allocate a temporary buffer for playback */ | 928 | /* allocate a temporary buffer for playback */ |
924 | if (is_playback) { | 929 | if (is_playback) { |
@@ -991,7 +996,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by | |||
991 | u->urb->pipe = subs->datapipe; | 996 | u->urb->pipe = subs->datapipe; |
992 | u->urb->transfer_flags = URB_ISO_ASAP; | 997 | u->urb->transfer_flags = URB_ISO_ASAP; |
993 | u->urb->number_of_packets = u->packets; | 998 | u->urb->number_of_packets = u->packets; |
994 | u->urb->interval = 1; | 999 | u->urb->interval = 1 << subs->datainterval; |
995 | u->urb->context = u; | 1000 | u->urb->context = u; |
996 | u->urb->complete = snd_usb_complete_callback(snd_complete_urb); | 1001 | u->urb->complete = snd_usb_complete_callback(snd_complete_urb); |
997 | } | 1002 | } |
@@ -1195,6 +1200,12 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt) | |||
1195 | subs->datapipe = usb_sndisocpipe(dev, ep); | 1200 | subs->datapipe = usb_sndisocpipe(dev, ep); |
1196 | else | 1201 | else |
1197 | subs->datapipe = usb_rcvisocpipe(dev, ep); | 1202 | subs->datapipe = usb_rcvisocpipe(dev, ep); |
1203 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH && | ||
1204 | get_endpoint(alts, 0)->bInterval >= 1 && | ||
1205 | get_endpoint(alts, 0)->bInterval <= 4) | ||
1206 | subs->datainterval = get_endpoint(alts, 0)->bInterval - 1; | ||
1207 | else | ||
1208 | subs->datainterval = 0; | ||
1198 | subs->syncpipe = subs->syncinterval = 0; | 1209 | subs->syncpipe = subs->syncinterval = 0; |
1199 | subs->maxpacksize = fmt->maxpacksize; | 1210 | subs->maxpacksize = fmt->maxpacksize; |
1200 | subs->fill_max = 0; | 1211 | subs->fill_max = 0; |
@@ -2492,8 +2503,10 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) | |||
2492 | fp->altset_idx = i; | 2503 | fp->altset_idx = i; |
2493 | fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; | 2504 | fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; |
2494 | fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; | 2505 | fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; |
2495 | /* FIXME: decode wMaxPacketSize of high bandwith endpoints */ | ||
2496 | fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); | 2506 | fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); |
2507 | if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) | ||
2508 | fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) | ||
2509 | * (fp->maxpacksize & 0x7ff); | ||
2497 | fp->attributes = csep[3]; | 2510 | fp->attributes = csep[3]; |
2498 | 2511 | ||
2499 | /* some quirks for attributes here */ | 2512 | /* some quirks for attributes here */ |