diff options
Diffstat (limited to 'sound/usb/pcm.c')
-rw-r--r-- | sound/usb/pcm.c | 117 |
1 files changed, 22 insertions, 95 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 2bf0d77d1768..456829882f40 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "urb.h" | 31 | #include "urb.h" |
32 | #include "helper.h" | 32 | #include "helper.h" |
33 | #include "pcm.h" | 33 | #include "pcm.h" |
34 | #include "clock.h" | ||
34 | 35 | ||
35 | /* | 36 | /* |
36 | * return the current pcm pointer. just based on the hwptr_done value. | 37 | * return the current pcm pointer. just based on the hwptr_done value. |
@@ -120,10 +121,6 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface, | |||
120 | 121 | ||
121 | ep = get_endpoint(alts, 0)->bEndpointAddress; | 122 | ep = get_endpoint(alts, 0)->bEndpointAddress; |
122 | 123 | ||
123 | /* if endpoint doesn't have pitch control, bail out */ | ||
124 | if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL)) | ||
125 | return 0; | ||
126 | |||
127 | data[0] = 1; | 124 | data[0] = 1; |
128 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, | 125 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, |
129 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, | 126 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, |
@@ -137,119 +134,49 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface, | |||
137 | return 0; | 134 | return 0; |
138 | } | 135 | } |
139 | 136 | ||
140 | /* | 137 | static int init_pitch_v2(struct snd_usb_audio *chip, int iface, |
141 | * initialize the picth control and sample rate | 138 | struct usb_host_interface *alts, |
142 | */ | 139 | struct audioformat *fmt) |
143 | int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, | ||
144 | struct usb_host_interface *alts, | ||
145 | struct audioformat *fmt) | ||
146 | { | ||
147 | struct usb_interface_descriptor *altsd = get_iface_desc(alts); | ||
148 | |||
149 | switch (altsd->bInterfaceProtocol) { | ||
150 | case UAC_VERSION_1: | ||
151 | return init_pitch_v1(chip, iface, alts, fmt); | ||
152 | |||
153 | case UAC_VERSION_2: | ||
154 | /* not implemented yet */ | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | return -EINVAL; | ||
159 | } | ||
160 | |||
161 | static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, | ||
162 | struct usb_host_interface *alts, | ||
163 | struct audioformat *fmt, int rate) | ||
164 | { | 140 | { |
165 | struct usb_device *dev = chip->dev; | 141 | struct usb_device *dev = chip->dev; |
142 | unsigned char data[1]; | ||
166 | unsigned int ep; | 143 | unsigned int ep; |
167 | unsigned char data[3]; | 144 | int err; |
168 | int err, crate; | ||
169 | 145 | ||
170 | ep = get_endpoint(alts, 0)->bEndpointAddress; | 146 | ep = get_endpoint(alts, 0)->bEndpointAddress; |
171 | /* if endpoint doesn't have sampling rate control, bail out */ | ||
172 | if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) { | ||
173 | snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n", | ||
174 | dev->devnum, iface, fmt->altsetting); | ||
175 | return 0; | ||
176 | } | ||
177 | 147 | ||
178 | data[0] = rate; | 148 | data[0] = 1; |
179 | data[1] = rate >> 8; | ||
180 | data[2] = rate >> 16; | ||
181 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, | ||
182 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, | ||
183 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, | ||
184 | data, sizeof(data), 1000)) < 0) { | ||
185 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", | ||
186 | dev->devnum, iface, fmt->altsetting, rate, ep); | ||
187 | return err; | ||
188 | } | ||
189 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, | ||
190 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, | ||
191 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, | ||
192 | data, sizeof(data), 1000)) < 0) { | ||
193 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", | ||
194 | dev->devnum, iface, fmt->altsetting, ep); | ||
195 | return 0; /* some devices don't support reading */ | ||
196 | } | ||
197 | crate = data[0] | (data[1] << 8) | (data[2] << 16); | ||
198 | if (crate != rate) { | ||
199 | snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); | ||
200 | // runtime->rate = crate; | ||
201 | } | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, | ||
207 | struct usb_host_interface *alts, | ||
208 | struct audioformat *fmt, int rate) | ||
209 | { | ||
210 | struct usb_device *dev = chip->dev; | ||
211 | unsigned char data[4]; | ||
212 | int err, crate; | ||
213 | |||
214 | data[0] = rate; | ||
215 | data[1] = rate >> 8; | ||
216 | data[2] = rate >> 16; | ||
217 | data[3] = rate >> 24; | ||
218 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, | 149 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, |
219 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | 150 | USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, |
220 | UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, | 151 | UAC2_EP_CS_PITCH << 8, 0, |
221 | data, sizeof(data), 1000)) < 0) { | ||
222 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n", | ||
223 | dev->devnum, iface, fmt->altsetting, rate); | ||
224 | return err; | ||
225 | } | ||
226 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, | ||
227 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
228 | UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, | ||
229 | data, sizeof(data), 1000)) < 0) { | 152 | data, sizeof(data), 1000)) < 0) { |
230 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", | 153 | snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH (v2)\n", |
231 | dev->devnum, iface, fmt->altsetting); | 154 | dev->devnum, iface, fmt->altsetting); |
232 | return err; | 155 | return err; |
233 | } | 156 | } |
234 | crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); | ||
235 | if (crate != rate) | ||
236 | snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); | ||
237 | 157 | ||
238 | return 0; | 158 | return 0; |
239 | } | 159 | } |
240 | 160 | ||
241 | int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, | 161 | /* |
242 | struct usb_host_interface *alts, | 162 | * initialize the pitch control and sample rate |
243 | struct audioformat *fmt, int rate) | 163 | */ |
164 | int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, | ||
165 | struct usb_host_interface *alts, | ||
166 | struct audioformat *fmt) | ||
244 | { | 167 | { |
245 | struct usb_interface_descriptor *altsd = get_iface_desc(alts); | 168 | struct usb_interface_descriptor *altsd = get_iface_desc(alts); |
246 | 169 | ||
170 | /* if endpoint doesn't have pitch control, bail out */ | ||
171 | if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL)) | ||
172 | return 0; | ||
173 | |||
247 | switch (altsd->bInterfaceProtocol) { | 174 | switch (altsd->bInterfaceProtocol) { |
248 | case UAC_VERSION_1: | 175 | case UAC_VERSION_1: |
249 | return set_sample_rate_v1(chip, iface, alts, fmt, rate); | 176 | return init_pitch_v1(chip, iface, alts, fmt); |
250 | 177 | ||
251 | case UAC_VERSION_2: | 178 | case UAC_VERSION_2: |
252 | return set_sample_rate_v2(chip, iface, alts, fmt, rate); | 179 | return init_pitch_v2(chip, iface, alts, fmt); |
253 | } | 180 | } |
254 | 181 | ||
255 | return -EINVAL; | 182 | return -EINVAL; |