aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/atm/speedtch.c
diff options
context:
space:
mode:
authorDuncan Sands <baldrick@free.fr>2006-01-13 04:59:23 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-01-31 20:23:40 -0500
commit80aae7a17afd21f7ba900dd566fb23a2444021f8 (patch)
tree2193fe416373daddbc2b1da8bca61664081b927b /drivers/usb/atm/speedtch.c
parent6f7494759870ec6fbb066f7202c5585fe36fbe82 (diff)
[PATCH] USBATM: allow isochronous transfer
While the usbatm core has had some support for using isoc urbs for some time, there was no way for users to turn it on. While use of isoc transfer should still be considered experimental, it now works well enough to let users turn it on. Minidrivers signal to the core that they want to use isoc transfer by setting the new UDSL_USE_ISOC flag. The speedtch minidriver gets a new module parameter enable_isoc (defaults to false), plus some logic that checks for the existence of an isoc receive endpoint (not all speedtouch modems have one). Signed-off-by: Duncan Sands <baldrick@free.fr> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/atm/speedtch.c')
-rw-r--r--drivers/usb/atm/speedtch.c82
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
73static int altsetting = DEFAULT_ALTSETTING; 77static unsigned int altsetting = 0; /* zero means: use the default */
74static int dl_512_first = DEFAULT_DL_512_FIRST; 78static int dl_512_first = DEFAULT_DL_512_FIRST;
79static int enable_isoc = DEFAULT_ENABLE_ISOC;
75static int sw_buffering = DEFAULT_SW_BUFFERING; 80static int sw_buffering = DEFAULT_SW_BUFFERING;
76 81
77module_param(altsetting, int, S_IRUGO | S_IWUSR); 82module_param(altsetting, uint, S_IRUGO | S_IWUSR);
78MODULE_PARM_DESC(altsetting, 83MODULE_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
82module_param(dl_512_first, bool, S_IRUGO | S_IWUSR); 88module_param(dl_512_first, bool, S_IRUGO | S_IWUSR);
83MODULE_PARM_DESC(dl_512_first, 89MODULE_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
93module_param(enable_isoc, bool, S_IRUGO | S_IWUSR);
94MODULE_PARM_DESC(enable_isoc,
95 "Use isochronous transfers if available (default: "
96 __MODULE_STRING(DEFAULT_ENABLE_ISOC) ")");
97
87module_param(sw_buffering, bool, S_IRUGO | S_IWUSR); 98module_param(sw_buffering, bool, S_IRUGO | S_IWUSR);
88MODULE_PARM_DESC(sw_buffering, 99MODULE_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
824static int speedtch_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) 874static int speedtch_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)