diff options
Diffstat (limited to 'drivers/usb/atm/speedtch.c')
-rw-r--r-- | drivers/usb/atm/speedtch.c | 82 |
1 files changed, 66 insertions, 16 deletions
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 0e981672f149..8c1c560cf051 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c | |||
@@ -35,6 +35,8 @@ | |||
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/stat.h> | 36 | #include <linux/stat.h> |
37 | #include <linux/timer.h> | 37 | #include <linux/timer.h> |
38 | #include <linux/types.h> | ||
39 | #include <linux/usb_ch9.h> | ||
38 | #include <linux/workqueue.h> | 40 | #include <linux/workqueue.h> |
39 | 41 | ||
40 | #include "usbatm.h" | 42 | #include "usbatm.h" |
@@ -66,24 +68,33 @@ static const char speedtch_driver_name[] = "speedtch"; | |||
66 | 68 | ||
67 | #define RESUBMIT_DELAY 1000 /* milliseconds */ | 69 | #define RESUBMIT_DELAY 1000 /* milliseconds */ |
68 | 70 | ||
69 | #define DEFAULT_ALTSETTING 1 | 71 | #define DEFAULT_BULK_ALTSETTING 1 |
72 | #define DEFAULT_ISOC_ALTSETTING 2 | ||
70 | #define DEFAULT_DL_512_FIRST 0 | 73 | #define DEFAULT_DL_512_FIRST 0 |
74 | #define DEFAULT_ENABLE_ISOC 0 | ||
71 | #define DEFAULT_SW_BUFFERING 0 | 75 | #define DEFAULT_SW_BUFFERING 0 |
72 | 76 | ||
73 | static int altsetting = DEFAULT_ALTSETTING; | 77 | static unsigned int altsetting = 0; /* zero means: use the default */ |
74 | static int dl_512_first = DEFAULT_DL_512_FIRST; | 78 | static int dl_512_first = DEFAULT_DL_512_FIRST; |
79 | static int enable_isoc = DEFAULT_ENABLE_ISOC; | ||
75 | static int sw_buffering = DEFAULT_SW_BUFFERING; | 80 | static int sw_buffering = DEFAULT_SW_BUFFERING; |
76 | 81 | ||
77 | module_param(altsetting, int, S_IRUGO | S_IWUSR); | 82 | module_param(altsetting, uint, S_IRUGO | S_IWUSR); |
78 | MODULE_PARM_DESC(altsetting, | 83 | MODULE_PARM_DESC(altsetting, |
79 | "Alternative setting for data interface (default: " | 84 | "Alternative setting for data interface (bulk_default: " |
80 | __MODULE_STRING(DEFAULT_ALTSETTING) ")"); | 85 | __MODULE_STRING(DEFAULT_BULK_ALTSETTING) "; isoc_default: " |
86 | __MODULE_STRING(DEFAULT_ISOC_ALTSETTING) ")"); | ||
81 | 87 | ||
82 | module_param(dl_512_first, bool, S_IRUGO | S_IWUSR); | 88 | module_param(dl_512_first, bool, S_IRUGO | S_IWUSR); |
83 | MODULE_PARM_DESC(dl_512_first, | 89 | MODULE_PARM_DESC(dl_512_first, |
84 | "Read 512 bytes before sending firmware (default: " | 90 | "Read 512 bytes before sending firmware (default: " |
85 | __MODULE_STRING(DEFAULT_DL_512_FIRST) ")"); | 91 | __MODULE_STRING(DEFAULT_DL_512_FIRST) ")"); |
86 | 92 | ||
93 | module_param(enable_isoc, bool, S_IRUGO | S_IWUSR); | ||
94 | MODULE_PARM_DESC(enable_isoc, | ||
95 | "Use isochronous transfers if available (default: " | ||
96 | __MODULE_STRING(DEFAULT_ENABLE_ISOC) ")"); | ||
97 | |||
87 | module_param(sw_buffering, bool, S_IRUGO | S_IWUSR); | 98 | module_param(sw_buffering, bool, S_IRUGO | S_IWUSR); |
88 | MODULE_PARM_DESC(sw_buffering, | 99 | MODULE_PARM_DESC(sw_buffering, |
89 | "Enable software buffering (default: " | 100 | "Enable software buffering (default: " |
@@ -91,7 +102,8 @@ MODULE_PARM_DESC(sw_buffering, | |||
91 | 102 | ||
92 | #define INTERFACE_DATA 1 | 103 | #define INTERFACE_DATA 1 |
93 | #define ENDPOINT_INT 0x81 | 104 | #define ENDPOINT_INT 0x81 |
94 | #define ENDPOINT_DATA 0x07 | 105 | #define ENDPOINT_BULK_DATA 0x07 |
106 | #define ENDPOINT_ISOC_DATA 0x07 | ||
95 | #define ENDPOINT_FIRMWARE 0x05 | 107 | #define ENDPOINT_FIRMWARE 0x05 |
96 | 108 | ||
97 | #define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) ) | 109 | #define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) ) |
@@ -687,11 +699,12 @@ static int speedtch_bind(struct usbatm_data *usbatm, | |||
687 | const struct usb_device_id *id) | 699 | const struct usb_device_id *id) |
688 | { | 700 | { |
689 | struct usb_device *usb_dev = interface_to_usbdev(intf); | 701 | struct usb_device *usb_dev = interface_to_usbdev(intf); |
690 | struct usb_interface *cur_intf; | 702 | struct usb_interface *cur_intf, *data_intf; |
691 | struct speedtch_instance_data *instance; | 703 | struct speedtch_instance_data *instance; |
692 | int ifnum = intf->altsetting->desc.bInterfaceNumber; | 704 | int ifnum = intf->altsetting->desc.bInterfaceNumber; |
693 | int num_interfaces = usb_dev->actconfig->desc.bNumInterfaces; | 705 | int num_interfaces = usb_dev->actconfig->desc.bNumInterfaces; |
694 | int i, ret; | 706 | int i, ret; |
707 | int use_isoc; | ||
695 | 708 | ||
696 | usb_dbg(usbatm, "%s entered\n", __func__); | 709 | usb_dbg(usbatm, "%s entered\n", __func__); |
697 | 710 | ||
@@ -702,6 +715,11 @@ static int speedtch_bind(struct usbatm_data *usbatm, | |||
702 | return -ENODEV; | 715 | return -ENODEV; |
703 | } | 716 | } |
704 | 717 | ||
718 | if (!(data_intf = usb_ifnum_to_if(usb_dev, INTERFACE_DATA))) { | ||
719 | usb_err(usbatm, "%s: data interface not found!\n", __func__); | ||
720 | return -ENODEV; | ||
721 | } | ||
722 | |||
705 | /* claim all interfaces */ | 723 | /* claim all interfaces */ |
706 | 724 | ||
707 | for (i=0; i < num_interfaces; i++) { | 725 | for (i=0; i < num_interfaces; i++) { |
@@ -728,8 +746,9 @@ static int speedtch_bind(struct usbatm_data *usbatm, | |||
728 | 746 | ||
729 | instance->usbatm = usbatm; | 747 | instance->usbatm = usbatm; |
730 | 748 | ||
731 | /* altsetting may change at any moment, so take a snapshot */ | 749 | /* altsetting and enable_isoc may change at any moment, so take a snapshot */ |
732 | instance->altsetting = altsetting; | 750 | instance->altsetting = altsetting; |
751 | use_isoc = enable_isoc; | ||
733 | 752 | ||
734 | if (instance->altsetting) | 753 | if (instance->altsetting) |
735 | if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) { | 754 | if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) { |
@@ -737,14 +756,44 @@ static int speedtch_bind(struct usbatm_data *usbatm, | |||
737 | instance->altsetting = 0; /* fall back to default */ | 756 | instance->altsetting = 0; /* fall back to default */ |
738 | } | 757 | } |
739 | 758 | ||
740 | if (!instance->altsetting) { | 759 | if (!instance->altsetting && use_isoc) |
741 | if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_ALTSETTING)) < 0) { | 760 | if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_ISOC_ALTSETTING)) < 0) { |
742 | usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_ALTSETTING, ret); | 761 | usb_dbg(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_ISOC_ALTSETTING, ret); |
743 | goto fail_free; | 762 | use_isoc = 0; /* fall back to bulk */ |
744 | } | 763 | } |
745 | instance->altsetting = DEFAULT_ALTSETTING; | 764 | |
765 | if (use_isoc) { | ||
766 | const struct usb_host_interface *desc = data_intf->cur_altsetting; | ||
767 | const __u8 target_address = USB_DIR_IN | usbatm->driver->isoc_in; | ||
768 | int i; | ||
769 | |||
770 | use_isoc = 0; /* fall back to bulk if endpoint not found */ | ||
771 | |||
772 | for (i=0; i<desc->desc.bNumEndpoints; i++) { | ||
773 | const struct usb_endpoint_descriptor *endpoint_desc = &desc->endpoint[i].desc; | ||
774 | |||
775 | if ((endpoint_desc->bEndpointAddress == target_address)) { | ||
776 | use_isoc = (endpoint_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == | ||
777 | USB_ENDPOINT_XFER_ISOC; | ||
778 | break; | ||
779 | } | ||
780 | } | ||
781 | |||
782 | if (!use_isoc) | ||
783 | usb_info(usbatm, "isochronous transfer not supported - using bulk\n"); | ||
746 | } | 784 | } |
747 | 785 | ||
786 | if (!use_isoc && !instance->altsetting) | ||
787 | if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_BULK_ALTSETTING)) < 0) { | ||
788 | usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_BULK_ALTSETTING, ret); | ||
789 | goto fail_free; | ||
790 | } | ||
791 | |||
792 | if (!instance->altsetting) | ||
793 | instance->altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING; | ||
794 | |||
795 | usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0); | ||
796 | |||
748 | INIT_WORK(&instance->status_checker, (void *)speedtch_check_status, instance); | 797 | INIT_WORK(&instance->status_checker, (void *)speedtch_check_status, instance); |
749 | 798 | ||
750 | instance->status_checker.timer.function = speedtch_status_poll; | 799 | instance->status_checker.timer.function = speedtch_status_poll; |
@@ -771,7 +820,7 @@ static int speedtch_bind(struct usbatm_data *usbatm, | |||
771 | 0x12, 0xc0, 0x07, 0x00, | 820 | 0x12, 0xc0, 0x07, 0x00, |
772 | instance->scratch_buffer + OFFSET_7, SIZE_7, 500); | 821 | instance->scratch_buffer + OFFSET_7, SIZE_7, 500); |
773 | 822 | ||
774 | usbatm->flags = (ret == SIZE_7 ? UDSL_SKIP_HEAVY_INIT : 0); | 823 | usbatm->flags |= (ret == SIZE_7 ? UDSL_SKIP_HEAVY_INIT : 0); |
775 | 824 | ||
776 | usb_dbg(usbatm, "%s: firmware %s loaded\n", __func__, usbatm->flags & UDSL_SKIP_HEAVY_INIT ? "already" : "not"); | 825 | usb_dbg(usbatm, "%s: firmware %s loaded\n", __func__, usbatm->flags & UDSL_SKIP_HEAVY_INIT ? "already" : "not"); |
777 | 826 | ||
@@ -817,8 +866,9 @@ static struct usbatm_driver speedtch_usbatm_driver = { | |||
817 | .unbind = speedtch_unbind, | 866 | .unbind = speedtch_unbind, |
818 | .atm_start = speedtch_atm_start, | 867 | .atm_start = speedtch_atm_start, |
819 | .atm_stop = speedtch_atm_stop, | 868 | .atm_stop = speedtch_atm_stop, |
820 | .in = ENDPOINT_DATA, | 869 | .bulk_in = ENDPOINT_BULK_DATA, |
821 | .out = ENDPOINT_DATA | 870 | .bulk_out = ENDPOINT_BULK_DATA, |
871 | .isoc_in = ENDPOINT_ISOC_DATA | ||
822 | }; | 872 | }; |
823 | 873 | ||
824 | static int speedtch_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) | 874 | static int speedtch_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) |