/* Line6 device disconnected. */ static void line6_disconnect(struct usb_interface *interface) { struct usb_line6 *line6; struct usb_device *usbdev; int interface_number; if (interface == NULL) return; usbdev = interface_to_usbdev(interface); if (usbdev == NULL) return; /* removal of additional special files should go here */ sysfs_remove_link(&interface->dev.kobj, "usb_device"); interface_number = interface->cur_altsetting->desc.bInterfaceNumber; line6 = usb_get_intfdata(interface); if (line6 != NULL) { if (line6->urb_listen != NULL) line6_stop_listen(line6); if (usbdev != line6->usbdev) dev_err(line6->ifcdev, "driver bug: inconsistent usb device\n"); switch (line6->usbdev->descriptor.idProduct) { case LINE6_DEVID_BASSPODXT: case LINE6_DEVID_BASSPODXTLIVE: case LINE6_DEVID_BASSPODXTPRO: case LINE6_DEVID_POCKETPOD: case LINE6_DEVID_PODX3: case LINE6_DEVID_PODX3LIVE: case LINE6_DEVID_PODXT: case LINE6_DEVID_PODXTPRO: line6_pod_disconnect(interface); break; case LINE6_DEVID_PODHD300: case LINE6_DEVID_PODHD500: line6_podhd_disconnect(interface); break; case LINE6_DEVID_PODXTLIVE: switch (interface_number) { case PODXTLIVE_INTERFACE_POD: line6_pod_disconnect(interface); break; case PODXTLIVE_INTERFACE_VARIAX: line6_variax_disconnect(interface); break; } break; case LINE6_DEVID_VARIAX: line6_variax_disconnect(interface); break; case LINE6_DEVID_PODSTUDIO_GX: case LINE6_DEVID_PODSTUDIO_UX1: case LINE6_DEVID_PODSTUDIO_UX2: case LINE6_DEVID_TONEPORT_GX: case LINE6_DEVID_TONEPORT_UX1: case LINE6_DEVID_TONEPORT_UX2: case LINE6_DEVID_GUITARPORT: line6_toneport_disconnect(interface); break; default: MISSING_CASE; } dev_info(&interface->dev, "Line6 %s now disconnected\n", line6->properties->name); } line6_destruct(interface); /* decrement reference counters: */ usb_put_intf(interface); usb_put_dev(usbdev); }
/* Probe USB device. */ static int line6_probe(struct usb_interface *interface, const struct usb_device_id *id) { int devtype; struct usb_device *usbdev; struct usb_line6 *line6; const struct line6_properties *properties; int interface_number, alternate = 0; int product; int size = 0; int ep_read = 0, ep_write = 0; int ret; if (interface == NULL) return -ENODEV; usbdev = interface_to_usbdev(interface); if (usbdev == NULL) return -ENODEV; /* we don't handle multiple configurations */ if (usbdev->descriptor.bNumConfigurations != 1) { ret = -ENODEV; goto err_put; } /* check vendor and product id */ for (devtype = ARRAY_SIZE(line6_id_table) - 1; devtype--;) { u16 idVendor = le16_to_cpu(usbdev->descriptor.idVendor); u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct); if (idVendor == line6_id_table[devtype].idVendor && idProduct == line6_id_table[devtype].idProduct) break; } if (devtype < 0) { ret = -ENODEV; goto err_put; } /* initialize device info: */ properties = &line6_properties_table[devtype]; dev_info(&interface->dev, "Line6 %s found\n", properties->name); product = le16_to_cpu(usbdev->descriptor.idProduct); /* query interface number */ interface_number = interface->cur_altsetting->desc.bInterfaceNumber; switch (product) { case LINE6_DEVID_BASSPODXTLIVE: case LINE6_DEVID_PODXTLIVE: case LINE6_DEVID_VARIAX: alternate = 1; break; case LINE6_DEVID_POCKETPOD: switch (interface_number) { case 0: return 0; /* this interface has no endpoints */ case 1: alternate = 0; break; default: MISSING_CASE; } break; case LINE6_DEVID_PODHD500: case LINE6_DEVID_PODX3: case LINE6_DEVID_PODX3LIVE: switch (interface_number) { case 0: alternate = 1; break; case 1: alternate = 0; break; default: MISSING_CASE; } break; case LINE6_DEVID_BASSPODXT: case LINE6_DEVID_BASSPODXTPRO: case LINE6_DEVID_PODXT: case LINE6_DEVID_PODXTPRO: case LINE6_DEVID_PODHD300: alternate = 5; break; case LINE6_DEVID_GUITARPORT: case LINE6_DEVID_PODSTUDIO_GX: case LINE6_DEVID_PODSTUDIO_UX1: case LINE6_DEVID_TONEPORT_GX: case LINE6_DEVID_TONEPORT_UX1: alternate = 2; /* 1..4 seem to be ok */ break; case LINE6_DEVID_TONEPORT_UX2: case LINE6_DEVID_PODSTUDIO_UX2: switch (interface_number) { case 0: /* defaults to 44.1kHz, 16-bit */ alternate = 2; break; case 1: /* don't know yet what this is ... alternate = 1; break; */ return -ENODEV; default: MISSING_CASE; } break; default: MISSING_CASE; ret = -ENODEV; goto err_put; } ret = usb_set_interface(usbdev, interface_number, alternate); if (ret < 0) { dev_err(&interface->dev, "set_interface failed\n"); goto err_put; } /* initialize device data based on product id: */ switch (product) { case LINE6_DEVID_BASSPODXT: case LINE6_DEVID_BASSPODXTLIVE: case LINE6_DEVID_BASSPODXTPRO: case LINE6_DEVID_PODXT: case LINE6_DEVID_PODXTPRO: size = sizeof(struct usb_line6_pod); ep_read = 0x84; ep_write = 0x03; break; case LINE6_DEVID_PODHD300: size = sizeof(struct usb_line6_podhd); ep_read = 0x84; ep_write = 0x03; break; case LINE6_DEVID_PODHD500: size = sizeof(struct usb_line6_podhd); ep_read = 0x81; ep_write = 0x01; break; case LINE6_DEVID_POCKETPOD: size = sizeof(struct usb_line6_pod); ep_read = 0x82; ep_write = 0x02; break; case LINE6_DEVID_PODX3: case LINE6_DEVID_PODX3LIVE: /* currently unused! */ size = sizeof(struct usb_line6_pod); ep_read = 0x81; ep_write = 0x01; break; case LINE6_DEVID_PODSTUDIO_GX: case LINE6_DEVID_PODSTUDIO_UX1: case LINE6_DEVID_PODSTUDIO_UX2: case LINE6_DEVID_TONEPORT_GX: case LINE6_DEVID_TONEPORT_UX1: case LINE6_DEVID_TONEPORT_UX2: case LINE6_DEVID_GUITARPORT: size = sizeof(struct usb_line6_toneport); /* these don't have a control channel */ break; case LINE6_DEVID_PODXTLIVE: switch (interface_number) { case PODXTLIVE_INTERFACE_POD: size = sizeof(struct usb_line6_pod); ep_read = 0x84; ep_write = 0x03; break; case PODXTLIVE_INTERFACE_VARIAX: size = sizeof(struct usb_line6_variax); ep_read = 0x86; ep_write = 0x05; break; default: ret = -ENODEV; goto err_put; } break; case LINE6_DEVID_VARIAX: size = sizeof(struct usb_line6_variax); ep_read = 0x82; ep_write = 0x01; break; default: MISSING_CASE; ret = -ENODEV; goto err_put; } if (size == 0) { dev_err(&interface->dev, "driver bug: interface data size not set\n"); ret = -ENODEV; goto err_put; } line6 = kzalloc(size, GFP_KERNEL); if (line6 == NULL) { dev_err(&interface->dev, "Out of memory\n"); ret = -ENODEV; goto err_put; } /* store basic data: */ line6->interface_number = interface_number; line6->properties = properties; line6->usbdev = usbdev; line6->ifcdev = &interface->dev; line6->ep_control_read = ep_read; line6->ep_control_write = ep_write; line6->product = product; /* get data from endpoint descriptor (see usb_maxpacket): */ { struct usb_host_endpoint *ep; unsigned epnum = usb_pipeendpoint(usb_rcvintpipe(usbdev, ep_read)); ep = usbdev->ep_in[epnum]; if (ep != NULL) { line6->interval = ep->desc.bInterval; line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); } else { line6->interval = LINE6_FALLBACK_INTERVAL; line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE; dev_err(line6->ifcdev, "endpoint not available, using fallback values"); } } usb_set_intfdata(interface, line6); if (properties->capabilities & LINE6_BIT_CONTROL) { /* initialize USB buffers: */ line6->buffer_listen = kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL); if (line6->buffer_listen == NULL) { dev_err(&interface->dev, "Out of memory\n"); ret = -ENOMEM; goto err_destruct; } line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL); if (line6->buffer_message == NULL) { dev_err(&interface->dev, "Out of memory\n"); ret = -ENOMEM; goto err_destruct; } line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL); if (line6->urb_listen == NULL) { dev_err(&interface->dev, "Out of memory\n"); line6_destruct(interface); ret = -ENOMEM; goto err_destruct; } ret = line6_start_listen(line6); if (ret < 0) { dev_err(&interface->dev, "%s: usb_submit_urb failed\n", __func__); goto err_destruct; } } /* initialize device data based on product id: */ switch (product) { case LINE6_DEVID_BASSPODXT: case LINE6_DEVID_BASSPODXTLIVE: case LINE6_DEVID_BASSPODXTPRO: case LINE6_DEVID_POCKETPOD: case LINE6_DEVID_PODX3: case LINE6_DEVID_PODX3LIVE: case LINE6_DEVID_PODXT: case LINE6_DEVID_PODXTPRO: ret = line6_pod_init(interface, (struct usb_line6_pod *)line6); break; case LINE6_DEVID_PODHD300: case LINE6_DEVID_PODHD500: ret = line6_podhd_init(interface, (struct usb_line6_podhd *)line6); break; case LINE6_DEVID_PODXTLIVE: switch (interface_number) { case PODXTLIVE_INTERFACE_POD: ret = line6_pod_init(interface, (struct usb_line6_pod *)line6); break; case PODXTLIVE_INTERFACE_VARIAX: ret = line6_variax_init(interface, (struct usb_line6_variax *)line6); break; default: dev_err(&interface->dev, "PODxt Live interface %d not supported\n", interface_number); ret = -ENODEV; } break; case LINE6_DEVID_VARIAX: ret = line6_variax_init(interface, (struct usb_line6_variax *)line6); break; case LINE6_DEVID_PODSTUDIO_GX: case LINE6_DEVID_PODSTUDIO_UX1: case LINE6_DEVID_PODSTUDIO_UX2: case LINE6_DEVID_TONEPORT_GX: case LINE6_DEVID_TONEPORT_UX1: case LINE6_DEVID_TONEPORT_UX2: case LINE6_DEVID_GUITARPORT: ret = line6_toneport_init(interface, (struct usb_line6_toneport *)line6); break; default: MISSING_CASE; ret = -ENODEV; } if (ret < 0) goto err_destruct; ret = sysfs_create_link(&interface->dev.kobj, &usbdev->dev.kobj, "usb_device"); if (ret < 0) goto err_destruct; /* creation of additional special files should go here */ dev_info(&interface->dev, "Line6 %s now attached\n", line6->properties->name); switch (product) { case LINE6_DEVID_PODX3: case LINE6_DEVID_PODX3LIVE: dev_info(&interface->dev, "NOTE: the Line6 %s is detected, but not yet supported\n", line6->properties->name); } /* increment reference counters: */ usb_get_intf(interface); usb_get_dev(usbdev); return 0; err_destruct: line6_destruct(interface); err_put: return ret; }
/* Line6 device disconnected. */ static void line6_disconnect(struct usb_interface *interface) { struct usb_line6 *line6; struct usb_device *usbdev; int interface_number, i; if (interface == NULL) return; usbdev = interface_to_usbdev(interface); if (usbdev == NULL) return; sysfs_remove_link(&interface->dev.kobj, "usb_device"); interface_number = interface->cur_altsetting->desc.bInterfaceNumber; line6 = usb_get_intfdata(interface); if (line6 != NULL) { if (line6->urb_listen != NULL) usb_kill_urb(line6->urb_listen); if (usbdev != line6->usbdev) dev_err(line6->ifcdev, "driver bug: inconsistent usb device\n"); switch (line6->usbdev->descriptor.idProduct) { case LINE6_DEVID_BASSPODXT: case LINE6_DEVID_BASSPODXTLIVE: case LINE6_DEVID_BASSPODXTPRO: case LINE6_DEVID_POCKETPOD: case LINE6_DEVID_PODX3: case LINE6_DEVID_PODX3LIVE: case LINE6_DEVID_PODXT: case LINE6_DEVID_PODXTPRO: pod_disconnect(interface); break; case LINE6_DEVID_PODXTLIVE: switch (interface_number) { case PODXTLIVE_INTERFACE_POD: pod_disconnect(interface); break; case PODXTLIVE_INTERFACE_VARIAX: variax_disconnect(interface); break; } break; case LINE6_DEVID_VARIAX: variax_disconnect(interface); break; case LINE6_DEVID_TONEPORT_GX: case LINE6_DEVID_TONEPORT_UX1: case LINE6_DEVID_TONEPORT_UX2: case LINE6_DEVID_GUITARPORT: toneport_disconnect(interface); break; default: MISSING_CASE; } dev_info(&interface->dev, "Line6 %s now disconnected\n", line6->properties->name); for (i = LINE6_MAX_DEVICES; i--;) if (line6_devices[i] == line6) line6_devices[i] = NULL; } line6_destruct(interface); /* decrement reference counters: */ usb_put_intf(interface); usb_put_dev(usbdev); line6_list_devices(); }