diff options
author | Kevin Lloyd <linux@sierrawireless.com> | 2008-01-10 14:11:04 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-02-01 17:35:00 -0500 |
commit | 228426edac844a2c9270528e9cd7ab6260ef7628 (patch) | |
tree | 27b91a52a410b98b5854e1d2f248b8a5977e0e22 /drivers/usb | |
parent | 20734345b35a5ff661293fcca1e376522bcf01de (diff) |
USB: sierra driver - add update dtr logic
The following improvements were made:
- Fixed control line issue where asserting DTR on ep5 would close ep2
- Added support for calc_num_ports (will help support future composite
devices)
Signed-off-by: Kevin Lloyd <linux@sierrawireless.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/serial/sierra.c | 221 |
1 files changed, 110 insertions, 111 deletions
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index b4d7ac948533..953bdf8827d2 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | USB Driver for Sierra Wireless | 2 | USB Driver for Sierra Wireless |
3 | 3 | ||
4 | Copyright (C) 2006, 2007 Kevin Lloyd <linux@sierrawireless.com> | 4 | Copyright (C) 2006, 2007, 2008 Kevin Lloyd <linux@sierrawireless.com> |
5 | 5 | ||
6 | IMPORTANT DISCLAIMER: This driver is not commercially supported by | 6 | IMPORTANT DISCLAIMER: This driver is not commercially supported by |
7 | Sierra Wireless. Use at your own risk. | 7 | Sierra Wireless. Use at your own risk. |
@@ -14,7 +14,7 @@ | |||
14 | Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org> | 14 | Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org> |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #define DRIVER_VERSION "v.1.2.5b" | 17 | #define DRIVER_VERSION "v.1.2.7" |
18 | #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>" | 18 | #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>" |
19 | #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" | 19 | #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" |
20 | 20 | ||
@@ -26,10 +26,12 @@ | |||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/usb.h> | 27 | #include <linux/usb.h> |
28 | #include <linux/usb/serial.h> | 28 | #include <linux/usb/serial.h> |
29 | #include <linux/usb/ch9.h> | ||
29 | 30 | ||
31 | #define SWIMS_USB_REQUEST_SetPower 0x00 | ||
32 | #define SWIMS_USB_REQUEST_SetNmea 0x07 | ||
30 | #define SWIMS_USB_REQUEST_SetMode 0x0B | 33 | #define SWIMS_USB_REQUEST_SetMode 0x0B |
31 | #define SWIMS_USB_REQUEST_TYPE_SetMode 0x40 | 34 | #define SWIMS_USB_REQUEST_TYPE_VSC_SET 0x40 |
32 | #define SWIMS_USB_INDEX_SetMode 0x0000 | ||
33 | #define SWIMS_SET_MODE_Modem 0x0001 | 35 | #define SWIMS_SET_MODE_Modem 0x0001 |
34 | 36 | ||
35 | /* per port private data */ | 37 | /* per port private data */ |
@@ -38,6 +40,8 @@ | |||
38 | #define IN_BUFLEN 4096 | 40 | #define IN_BUFLEN 4096 |
39 | 41 | ||
40 | static int debug; | 42 | static int debug; |
43 | static int nmea; | ||
44 | static int truinstall = 1; | ||
41 | 45 | ||
42 | enum devicetype { | 46 | enum devicetype { |
43 | DEVICE_3_PORT = 0, | 47 | DEVICE_3_PORT = 0, |
@@ -50,48 +54,96 @@ static int sierra_set_power_state(struct usb_device *udev, __u16 swiState) | |||
50 | int result; | 54 | int result; |
51 | dev_dbg(&udev->dev, "%s", "SET POWER STATE\n"); | 55 | dev_dbg(&udev->dev, "%s", "SET POWER STATE\n"); |
52 | result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | 56 | result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), |
53 | 0x00, /* __u8 request */ | 57 | SWIMS_USB_REQUEST_SetPower, /* __u8 request */ |
54 | 0x40, /* __u8 request type */ | 58 | SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */ |
55 | swiState, /* __u16 value */ | 59 | swiState, /* __u16 value */ |
56 | 0, /* __u16 index */ | 60 | 0, /* __u16 index */ |
57 | NULL, /* void *data */ | 61 | NULL, /* void *data */ |
58 | 0, /* __u16 size */ | 62 | 0, /* __u16 size */ |
59 | USB_CTRL_SET_TIMEOUT); /* int timeout */ | 63 | USB_CTRL_SET_TIMEOUT); /* int timeout */ |
60 | return result; | 64 | return result; |
61 | } | 65 | } |
62 | 66 | ||
63 | static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSocMode) | 67 | static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode) |
64 | { | 68 | { |
65 | int result; | 69 | int result; |
66 | dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH\n"); | 70 | dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH\n"); |
67 | result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | 71 | result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), |
68 | SWIMS_USB_REQUEST_SetMode, /* __u8 request */ | 72 | SWIMS_USB_REQUEST_SetMode, /* __u8 request */ |
69 | SWIMS_USB_REQUEST_TYPE_SetMode, /* __u8 request type */ | 73 | SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */ |
70 | eSocMode, /* __u16 value */ | 74 | eSWocMode, /* __u16 value */ |
71 | SWIMS_USB_INDEX_SetMode, /* __u16 index */ | 75 | 0x0000, /* __u16 index */ |
72 | NULL, /* void *data */ | 76 | NULL, /* void *data */ |
73 | 0, /* __u16 size */ | 77 | 0, /* __u16 size */ |
74 | USB_CTRL_SET_TIMEOUT); /* int timeout */ | 78 | USB_CTRL_SET_TIMEOUT); /* int timeout */ |
75 | return result; | 79 | return result; |
76 | } | 80 | } |
77 | 81 | ||
78 | static int sierra_probe(struct usb_interface *iface, | 82 | static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable) |
79 | const struct usb_device_id *id) | ||
80 | { | 83 | { |
81 | int result; | 84 | int result; |
85 | dev_dbg(&udev->dev, "%s", "NMEA Enable sent\n"); | ||
86 | result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
87 | SWIMS_USB_REQUEST_SetNmea, /* __u8 request */ | ||
88 | SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */ | ||
89 | enable, /* __u16 value */ | ||
90 | 0x0000, /* __u16 index */ | ||
91 | NULL, /* void *data */ | ||
92 | 0, /* __u16 size */ | ||
93 | USB_CTRL_SET_TIMEOUT); /* int timeout */ | ||
94 | return result; | ||
95 | } | ||
96 | |||
97 | static int sierra_calc_num_ports(struct usb_serial *serial) | ||
98 | { | ||
99 | int result; | ||
100 | int *num_ports = usb_get_serial_data(serial); | ||
101 | |||
102 | result = *num_ports; | ||
103 | |||
104 | if (result) { | ||
105 | kfree(num_ports); | ||
106 | usb_set_serial_data(serial, NULL); | ||
107 | } | ||
108 | |||
109 | return result; | ||
110 | } | ||
111 | |||
112 | static int sierra_probe(struct usb_serial *serial, | ||
113 | const struct usb_device_id *id) | ||
114 | { | ||
115 | int result = 0; | ||
82 | struct usb_device *udev; | 116 | struct usb_device *udev; |
117 | int *num_ports; | ||
118 | u8 ifnum; | ||
83 | 119 | ||
84 | udev = usb_get_dev(interface_to_usbdev(iface)); | 120 | num_ports = kmalloc(sizeof(*num_ports), GFP_KERNEL); |
121 | if (!num_ports) | ||
122 | return -ENOMEM; | ||
123 | |||
124 | ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; | ||
125 | udev = serial->dev; | ||
85 | 126 | ||
86 | /* Check if in installer mode */ | 127 | /* Check if in installer mode */ |
87 | if (id->driver_info == DEVICE_INSTALLER) { | 128 | if (truinstall && id->driver_info == DEVICE_INSTALLER) { |
88 | dev_dbg(&udev->dev, "%s", "FOUND DEVICE(SW)\n"); | 129 | dev_dbg(&udev->dev, "%s", "FOUND TRU-INSTALL DEVICE(SW)\n"); |
89 | result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem); | 130 | result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem); |
90 | /*We do not want to bind to the device when in installer mode*/ | 131 | /* Don't bind to the device when in installer mode */ |
132 | kfree(num_ports); | ||
91 | return -EIO; | 133 | return -EIO; |
92 | } | 134 | } else if (id->driver_info == DEVICE_1_PORT) |
135 | *num_ports = 1; | ||
136 | else if (ifnum == 0x99) | ||
137 | *num_ports = 0; | ||
138 | else | ||
139 | *num_ports = 3; | ||
140 | /* | ||
141 | * save off our num_ports info so that we can use it in the | ||
142 | * calc_num_ports callback | ||
143 | */ | ||
144 | usb_set_serial_data(serial, (void *)num_ports); | ||
93 | 145 | ||
94 | return usb_serial_probe(iface, id); | 146 | return result; |
95 | } | 147 | } |
96 | 148 | ||
97 | static struct usb_device_id id_table [] = { | 149 | static struct usb_device_id id_table [] = { |
@@ -133,53 +185,14 @@ static struct usb_device_id id_table [] = { | |||
133 | }; | 185 | }; |
134 | MODULE_DEVICE_TABLE(usb, id_table); | 186 | MODULE_DEVICE_TABLE(usb, id_table); |
135 | 187 | ||
136 | static struct usb_device_id id_table_1port [] = { | ||
137 | { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ | ||
138 | { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */ | ||
139 | { USB_DEVICE(0x05C6, 0x6613) }, /* Onda H600/ZTE MF330 */ | ||
140 | { } | ||
141 | }; | ||
142 | |||
143 | static struct usb_device_id id_table_3port [] = { | ||
144 | { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ | ||
145 | { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ | ||
146 | { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */ | ||
147 | { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ | ||
148 | { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ | ||
149 | { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */ | ||
150 | { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ | ||
151 | { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ | ||
152 | { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U*/ | ||
153 | { USB_DEVICE(0x1199, 0x0023) }, /* Sierra Wireless AirCard */ | ||
154 | |||
155 | { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ | ||
156 | { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ | ||
157 | { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ | ||
158 | { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */ | ||
159 | { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 (Thinkpad internal) */ | ||
160 | { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ | ||
161 | { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/ | ||
162 | { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/ | ||
163 | { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */ | ||
164 | { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */ | ||
165 | { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880E */ | ||
166 | { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881E */ | ||
167 | { USB_DEVICE(0x1199, 0x6855) }, /* Sierra Wireless AirCard 880 U */ | ||
168 | { USB_DEVICE(0x1199, 0x6856) }, /* Sierra Wireless AirCard 881U */ | ||
169 | { USB_DEVICE(0x1199, 0x6468) }, /* Sierra Wireless MP3G - EVDO */ | ||
170 | { USB_DEVICE(0x1199, 0x6469) }, /* Sierra Wireless MP3G - UMTS/HSPA */ | ||
171 | { } | ||
172 | }; | ||
173 | |||
174 | static struct usb_driver sierra_driver = { | 188 | static struct usb_driver sierra_driver = { |
175 | .name = "sierra", | 189 | .name = "sierra", |
176 | .probe = sierra_probe, | 190 | .probe = usb_serial_probe, |
177 | .disconnect = usb_serial_disconnect, | 191 | .disconnect = usb_serial_disconnect, |
178 | .id_table = id_table, | 192 | .id_table = id_table, |
179 | .no_dynamic_id = 1, | 193 | .no_dynamic_id = 1, |
180 | }; | 194 | }; |
181 | 195 | ||
182 | |||
183 | struct sierra_port_private { | 196 | struct sierra_port_private { |
184 | spinlock_t lock; /* lock the structure */ | 197 | spinlock_t lock; /* lock the structure */ |
185 | int outstanding_urbs; /* number of out urbs in flight */ | 198 | int outstanding_urbs; /* number of out urbs in flight */ |
@@ -201,6 +214,7 @@ static int sierra_send_setup(struct usb_serial_port *port) | |||
201 | { | 214 | { |
202 | struct usb_serial *serial = port->serial; | 215 | struct usb_serial *serial = port->serial; |
203 | struct sierra_port_private *portdata; | 216 | struct sierra_port_private *portdata; |
217 | __u16 interface = 0; | ||
204 | 218 | ||
205 | dbg("%s", __FUNCTION__); | 219 | dbg("%s", __FUNCTION__); |
206 | 220 | ||
@@ -213,9 +227,18 @@ static int sierra_send_setup(struct usb_serial_port *port) | |||
213 | if (portdata->rts_state) | 227 | if (portdata->rts_state) |
214 | val |= 0x02; | 228 | val |= 0x02; |
215 | 229 | ||
230 | /* Determine which port is targeted */ | ||
231 | if (port->bulk_out_endpointAddress == 2) | ||
232 | interface = 0; | ||
233 | else if (port->bulk_out_endpointAddress == 4) | ||
234 | interface = 1; | ||
235 | else if (port->bulk_out_endpointAddress == 5) | ||
236 | interface = 2; | ||
237 | |||
216 | return usb_control_msg(serial->dev, | 238 | return usb_control_msg(serial->dev, |
217 | usb_rcvctrlpipe(serial->dev, 0), | 239 | usb_rcvctrlpipe(serial->dev, 0), |
218 | 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT); | 240 | 0x22, 0x21, val, interface, |
241 | NULL, 0, USB_CTRL_SET_TIMEOUT); | ||
219 | } | 242 | } |
220 | 243 | ||
221 | return 0; | 244 | return 0; |
@@ -596,9 +619,13 @@ static int sierra_startup(struct usb_serial *serial) | |||
596 | 619 | ||
597 | dbg("%s", __FUNCTION__); | 620 | dbg("%s", __FUNCTION__); |
598 | 621 | ||
599 | /*Set Device mode to D0 */ | 622 | /* Set Device mode to D0 */ |
600 | sierra_set_power_state(serial->dev, 0x0000); | 623 | sierra_set_power_state(serial->dev, 0x0000); |
601 | 624 | ||
625 | /* Check NMEA and set */ | ||
626 | if (nmea) | ||
627 | sierra_vsc_set_nmea(serial->dev, 1); | ||
628 | |||
602 | /* Now setup per port private data */ | 629 | /* Now setup per port private data */ |
603 | for (i = 0; i < serial->num_ports; i++) { | 630 | for (i = 0; i < serial->num_ports; i++) { |
604 | port = serial->port[i]; | 631 | port = serial->port[i]; |
@@ -659,47 +686,19 @@ static void sierra_shutdown(struct usb_serial *serial) | |||
659 | } | 686 | } |
660 | } | 687 | } |
661 | 688 | ||
662 | static struct usb_serial_driver sierra_1port_device = { | 689 | static struct usb_serial_driver sierra_device = { |
663 | .driver = { | 690 | .driver = { |
664 | .owner = THIS_MODULE, | 691 | .owner = THIS_MODULE, |
665 | .name = "sierra1", | 692 | .name = "sierra1", |
666 | }, | 693 | }, |
667 | .description = "Sierra USB modem (1 port)", | 694 | .description = "Sierra USB modem", |
668 | .id_table = id_table_1port, | 695 | .id_table = id_table, |
669 | .usb_driver = &sierra_driver, | 696 | .usb_driver = &sierra_driver, |
670 | .num_interrupt_in = NUM_DONT_CARE, | 697 | .num_interrupt_in = NUM_DONT_CARE, |
671 | .num_bulk_in = 1, | 698 | .num_bulk_in = NUM_DONT_CARE, |
672 | .num_bulk_out = 1, | 699 | .num_bulk_out = NUM_DONT_CARE, |
673 | .num_ports = 1, | 700 | .calc_num_ports = sierra_calc_num_ports, |
674 | .open = sierra_open, | 701 | .probe = sierra_probe, |
675 | .close = sierra_close, | ||
676 | .write = sierra_write, | ||
677 | .write_room = sierra_write_room, | ||
678 | .chars_in_buffer = sierra_chars_in_buffer, | ||
679 | .throttle = sierra_rx_throttle, | ||
680 | .unthrottle = sierra_rx_unthrottle, | ||
681 | .ioctl = sierra_ioctl, | ||
682 | .set_termios = sierra_set_termios, | ||
683 | .break_ctl = sierra_break_ctl, | ||
684 | .tiocmget = sierra_tiocmget, | ||
685 | .tiocmset = sierra_tiocmset, | ||
686 | .attach = sierra_startup, | ||
687 | .shutdown = sierra_shutdown, | ||
688 | .read_int_callback = sierra_instat_callback, | ||
689 | }; | ||
690 | |||
691 | static struct usb_serial_driver sierra_3port_device = { | ||
692 | .driver = { | ||
693 | .owner = THIS_MODULE, | ||
694 | .name = "sierra3", | ||
695 | }, | ||
696 | .description = "Sierra USB modem (3 port)", | ||
697 | .id_table = id_table_3port, | ||
698 | .usb_driver = &sierra_driver, | ||
699 | .num_interrupt_in = NUM_DONT_CARE, | ||
700 | .num_bulk_in = 3, | ||
701 | .num_bulk_out = 3, | ||
702 | .num_ports = 3, | ||
703 | .open = sierra_open, | 702 | .open = sierra_open, |
704 | .close = sierra_close, | 703 | .close = sierra_close, |
705 | .write = sierra_write, | 704 | .write = sierra_write, |
@@ -721,12 +720,9 @@ static struct usb_serial_driver sierra_3port_device = { | |||
721 | static int __init sierra_init(void) | 720 | static int __init sierra_init(void) |
722 | { | 721 | { |
723 | int retval; | 722 | int retval; |
724 | retval = usb_serial_register(&sierra_1port_device); | 723 | retval = usb_serial_register(&sierra_device); |
725 | if (retval) | ||
726 | goto failed_1port_device_register; | ||
727 | retval = usb_serial_register(&sierra_3port_device); | ||
728 | if (retval) | 724 | if (retval) |
729 | goto failed_3port_device_register; | 725 | goto failed_device_register; |
730 | 726 | ||
731 | 727 | ||
732 | retval = usb_register(&sierra_driver); | 728 | retval = usb_register(&sierra_driver); |
@@ -738,18 +734,15 @@ static int __init sierra_init(void) | |||
738 | return 0; | 734 | return 0; |
739 | 735 | ||
740 | failed_driver_register: | 736 | failed_driver_register: |
741 | usb_serial_deregister(&sierra_3port_device); | 737 | usb_serial_deregister(&sierra_device); |
742 | failed_3port_device_register: | 738 | failed_device_register: |
743 | usb_serial_deregister(&sierra_1port_device); | ||
744 | failed_1port_device_register: | ||
745 | return retval; | 739 | return retval; |
746 | } | 740 | } |
747 | 741 | ||
748 | static void __exit sierra_exit(void) | 742 | static void __exit sierra_exit(void) |
749 | { | 743 | { |
750 | usb_deregister (&sierra_driver); | 744 | usb_deregister (&sierra_driver); |
751 | usb_serial_deregister(&sierra_1port_device); | 745 | usb_serial_deregister(&sierra_device); |
752 | usb_serial_deregister(&sierra_3port_device); | ||
753 | } | 746 | } |
754 | 747 | ||
755 | module_init(sierra_init); | 748 | module_init(sierra_init); |
@@ -760,6 +753,12 @@ MODULE_DESCRIPTION(DRIVER_DESC); | |||
760 | MODULE_VERSION(DRIVER_VERSION); | 753 | MODULE_VERSION(DRIVER_VERSION); |
761 | MODULE_LICENSE("GPL"); | 754 | MODULE_LICENSE("GPL"); |
762 | 755 | ||
756 | module_param(truinstall, bool, 0); | ||
757 | MODULE_PARM_DESC(truinstall, "TRU-Install support"); | ||
758 | |||
759 | module_param(nmea, bool, 0); | ||
760 | MODULE_PARM_DESC(nmea, "NMEA streaming"); | ||
761 | |||
763 | #ifdef CONFIG_USB_DEBUG | 762 | #ifdef CONFIG_USB_DEBUG |
764 | module_param(debug, bool, S_IRUGO | S_IWUSR); | 763 | module_param(debug, bool, S_IRUGO | S_IWUSR); |
765 | MODULE_PARM_DESC(debug, "Debug messages"); | 764 | MODULE_PARM_DESC(debug, "Debug messages"); |