blob: fa9296dd8d1fef1dcdabff6e46447558cb47ccd2 [file] [log] [blame]
/*
* workarounds / hacks for the older kernels follow below
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 24)
/* M-Audio Quattro has weird alternate settings. the altsetting jumps
* from 0 to 4 or 3 insuccessively, and this screws up
* usb_set_interface() (at least on 2.4.18/19 and 2.4.21).
*/
/*
* the following is a stripped version of usb_set_interface() with the fix
* for insuccessive altsetting numbers.
*/
/* stripped version for isochronos only */
static void hack_usb_set_maxpacket(struct usb_device *dev)
{
int i, b;
for (i=0; i<dev->actconfig->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; e<as->bNumEndpoints; 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;
}
}
}
}
/* stripped version */
int snd_hack_usb_set_interface(struct usb_device *dev, int interface, 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;
for (i = 0; i < iface->num_altsetting; ++i)
if (get_iface_desc(&iface->altsetting[i])->bAlternateSetting == alternate)
break;
if (i >= iface->num_altsetting)
return -EINVAL;
iface_as = &iface->altsetting[i];
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 = i;
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;
}
EXPORT_SYMBOL(snd_hack_usb_set_interface);
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 5)
/* map altsetting number to index */
int snd_hack_usb_set_interface(struct usb_device *dev, int interface, int alternate)
{
struct usb_interface *iface;
unsigned int i;
iface = usb_ifnum_to_if(dev, interface);
if (!iface)
return -EINVAL;
for (i = 0; i < iface->num_altsetting; ++i) {
if (get_iface_desc(&iface->altsetting[i])->bAlternateSetting == alternate)
return real_usb_set_interface(dev, interface, i);
}
return -EINVAL;
}
EXPORT_SYMBOL(snd_hack_usb_set_interface);
#endif /* LINUX_VERSION < 2.6.5 */
// vim: ft=c