diff options
Diffstat (limited to 'drivers/usb/serial/sierra.c')
-rw-r--r-- | drivers/usb/serial/sierra.c | 91 |
1 files changed, 78 insertions, 13 deletions
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 5019325ba25d..ac1b6449fb6a 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c | |||
@@ -16,8 +16,9 @@ | |||
16 | Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de> | 16 | Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de> |
17 | Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org> | 17 | Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org> |
18 | */ | 18 | */ |
19 | 19 | /* Uncomment to log function calls */ | |
20 | #define DRIVER_VERSION "v.1.3.8" | 20 | /* #define DEBUG */ |
21 | #define DRIVER_VERSION "v.1.7.16" | ||
21 | #define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer" | 22 | #define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer" |
22 | #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" | 23 | #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" |
23 | 24 | ||
@@ -33,8 +34,10 @@ | |||
33 | #define SWIMS_USB_REQUEST_SetPower 0x00 | 34 | #define SWIMS_USB_REQUEST_SetPower 0x00 |
34 | #define SWIMS_USB_REQUEST_SetNmea 0x07 | 35 | #define SWIMS_USB_REQUEST_SetNmea 0x07 |
35 | 36 | ||
36 | #define N_IN_URB 8 | 37 | #define N_IN_URB_HM 8 |
37 | #define N_OUT_URB 64 | 38 | #define N_OUT_URB_HM 64 |
39 | #define N_IN_URB 4 | ||
40 | #define N_OUT_URB 4 | ||
38 | #define IN_BUFLEN 4096 | 41 | #define IN_BUFLEN 4096 |
39 | 42 | ||
40 | #define MAX_TRANSFER (PAGE_SIZE - 512) | 43 | #define MAX_TRANSFER (PAGE_SIZE - 512) |
@@ -124,6 +127,23 @@ static int is_blacklisted(const u8 ifnum, | |||
124 | return 0; | 127 | return 0; |
125 | } | 128 | } |
126 | 129 | ||
130 | static int is_himemory(const u8 ifnum, | ||
131 | const struct sierra_iface_info *himemorylist) | ||
132 | { | ||
133 | const u8 *info; | ||
134 | int i; | ||
135 | |||
136 | if (himemorylist) { | ||
137 | info = himemorylist->ifaceinfo; | ||
138 | |||
139 | for (i=0; i < himemorylist->infolen; i++) { | ||
140 | if (info[i] == ifnum) | ||
141 | return 1; | ||
142 | } | ||
143 | } | ||
144 | return 0; | ||
145 | } | ||
146 | |||
127 | static int sierra_calc_interface(struct usb_serial *serial) | 147 | static int sierra_calc_interface(struct usb_serial *serial) |
128 | { | 148 | { |
129 | int interface; | 149 | int interface; |
@@ -186,6 +206,20 @@ static int sierra_probe(struct usb_serial *serial, | |||
186 | return result; | 206 | return result; |
187 | } | 207 | } |
188 | 208 | ||
209 | /* interfaces with higher memory requirements */ | ||
210 | static const u8 hi_memory_typeA_ifaces[] = { 0, 2 }; | ||
211 | static const struct sierra_iface_info typeA_interface_list = { | ||
212 | .infolen = ARRAY_SIZE(hi_memory_typeA_ifaces), | ||
213 | .ifaceinfo = hi_memory_typeA_ifaces, | ||
214 | }; | ||
215 | |||
216 | static const u8 hi_memory_typeB_ifaces[] = { 3, 4, 5, 6 }; | ||
217 | static const struct sierra_iface_info typeB_interface_list = { | ||
218 | .infolen = ARRAY_SIZE(hi_memory_typeB_ifaces), | ||
219 | .ifaceinfo = hi_memory_typeB_ifaces, | ||
220 | }; | ||
221 | |||
222 | /* 'blacklist' of interfaces not served by this driver */ | ||
189 | static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11 }; | 223 | static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11 }; |
190 | static const struct sierra_iface_info direct_ip_interface_blacklist = { | 224 | static const struct sierra_iface_info direct_ip_interface_blacklist = { |
191 | .infolen = ARRAY_SIZE(direct_ip_non_serial_ifaces), | 225 | .infolen = ARRAY_SIZE(direct_ip_non_serial_ifaces), |
@@ -286,8 +320,10 @@ struct sierra_port_private { | |||
286 | struct usb_anchor active; | 320 | struct usb_anchor active; |
287 | struct usb_anchor delayed; | 321 | struct usb_anchor delayed; |
288 | 322 | ||
323 | int num_out_urbs; | ||
324 | int num_in_urbs; | ||
289 | /* Input endpoints and buffers for this port */ | 325 | /* Input endpoints and buffers for this port */ |
290 | struct urb *in_urbs[N_IN_URB]; | 326 | struct urb *in_urbs[N_IN_URB_HM]; |
291 | 327 | ||
292 | /* Settings for the port */ | 328 | /* Settings for the port */ |
293 | int rts_state; /* Handshaking pins (outputs) */ | 329 | int rts_state; /* Handshaking pins (outputs) */ |
@@ -460,7 +496,7 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port, | |||
460 | spin_lock_irqsave(&portdata->lock, flags); | 496 | spin_lock_irqsave(&portdata->lock, flags); |
461 | dev_dbg(&port->dev, "%s - outstanding_urbs: %d\n", __func__, | 497 | dev_dbg(&port->dev, "%s - outstanding_urbs: %d\n", __func__, |
462 | portdata->outstanding_urbs); | 498 | portdata->outstanding_urbs); |
463 | if (portdata->outstanding_urbs > N_OUT_URB) { | 499 | if (portdata->outstanding_urbs > portdata->num_out_urbs) { |
464 | spin_unlock_irqrestore(&portdata->lock, flags); | 500 | spin_unlock_irqrestore(&portdata->lock, flags); |
465 | dev_dbg(&port->dev, "%s - write limit hit\n", __func__); | 501 | dev_dbg(&port->dev, "%s - write limit hit\n", __func__); |
466 | return 0; | 502 | return 0; |
@@ -665,7 +701,7 @@ static int sierra_write_room(struct tty_struct *tty) | |||
665 | /* try to give a good number back based on if we have any free urbs at | 701 | /* try to give a good number back based on if we have any free urbs at |
666 | * this point in time */ | 702 | * this point in time */ |
667 | spin_lock_irqsave(&portdata->lock, flags); | 703 | spin_lock_irqsave(&portdata->lock, flags); |
668 | if (portdata->outstanding_urbs > N_OUT_URB * 2 / 3) { | 704 | if (portdata->outstanding_urbs > (portdata->num_out_urbs * 2) / 3) { |
669 | spin_unlock_irqrestore(&portdata->lock, flags); | 705 | spin_unlock_irqrestore(&portdata->lock, flags); |
670 | dev_dbg(&port->dev, "%s - write limit hit\n", __func__); | 706 | dev_dbg(&port->dev, "%s - write limit hit\n", __func__); |
671 | return 0; | 707 | return 0; |
@@ -680,7 +716,7 @@ static void sierra_stop_rx_urbs(struct usb_serial_port *port) | |||
680 | int i; | 716 | int i; |
681 | struct sierra_port_private *portdata = usb_get_serial_port_data(port); | 717 | struct sierra_port_private *portdata = usb_get_serial_port_data(port); |
682 | 718 | ||
683 | for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) | 719 | for (i = 0; i < portdata->num_in_urbs; i++) |
684 | usb_kill_urb(portdata->in_urbs[i]); | 720 | usb_kill_urb(portdata->in_urbs[i]); |
685 | 721 | ||
686 | usb_kill_urb(port->interrupt_in_urb); | 722 | usb_kill_urb(port->interrupt_in_urb); |
@@ -695,7 +731,7 @@ static int sierra_submit_rx_urbs(struct usb_serial_port *port, gfp_t mem_flags) | |||
695 | struct sierra_port_private *portdata = usb_get_serial_port_data(port); | 731 | struct sierra_port_private *portdata = usb_get_serial_port_data(port); |
696 | 732 | ||
697 | ok_cnt = 0; | 733 | ok_cnt = 0; |
698 | for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) { | 734 | for (i = 0; i < portdata->num_in_urbs; i++) { |
699 | urb = portdata->in_urbs[i]; | 735 | urb = portdata->in_urbs[i]; |
700 | if (!urb) | 736 | if (!urb) |
701 | continue; | 737 | continue; |
@@ -791,7 +827,7 @@ static void sierra_close(struct usb_serial_port *port) | |||
791 | /* Stop reading urbs */ | 827 | /* Stop reading urbs */ |
792 | sierra_stop_rx_urbs(port); | 828 | sierra_stop_rx_urbs(port); |
793 | /* .. and release them */ | 829 | /* .. and release them */ |
794 | for (i = 0; i < N_IN_URB; i++) { | 830 | for (i = 0; i < portdata->num_in_urbs; i++) { |
795 | sierra_release_urb(portdata->in_urbs[i]); | 831 | sierra_release_urb(portdata->in_urbs[i]); |
796 | portdata->in_urbs[i] = NULL; | 832 | portdata->in_urbs[i] = NULL; |
797 | } | 833 | } |
@@ -818,7 +854,7 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
818 | 854 | ||
819 | 855 | ||
820 | endpoint = port->bulk_in_endpointAddress; | 856 | endpoint = port->bulk_in_endpointAddress; |
821 | for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) { | 857 | for (i = 0; i < portdata->num_in_urbs; i++) { |
822 | urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port, | 858 | urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port, |
823 | IN_BUFLEN, GFP_KERNEL, | 859 | IN_BUFLEN, GFP_KERNEL, |
824 | sierra_indat_callback); | 860 | sierra_indat_callback); |
@@ -869,7 +905,9 @@ static int sierra_startup(struct usb_serial *serial) | |||
869 | { | 905 | { |
870 | struct usb_serial_port *port; | 906 | struct usb_serial_port *port; |
871 | struct sierra_port_private *portdata; | 907 | struct sierra_port_private *portdata; |
908 | struct sierra_iface_info *himemoryp = NULL; | ||
872 | int i; | 909 | int i; |
910 | u8 ifnum; | ||
873 | 911 | ||
874 | dev_dbg(&serial->dev->dev, "%s\n", __func__); | 912 | dev_dbg(&serial->dev->dev, "%s\n", __func__); |
875 | 913 | ||
@@ -886,13 +924,40 @@ static int sierra_startup(struct usb_serial *serial) | |||
886 | portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); | 924 | portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); |
887 | if (!portdata) { | 925 | if (!portdata) { |
888 | dev_dbg(&port->dev, "%s: kmalloc for " | 926 | dev_dbg(&port->dev, "%s: kmalloc for " |
889 | "sierra_port_private (%d) failed!.\n", | 927 | "sierra_port_private (%d) failed!\n", |
890 | __func__, i); | 928 | __func__, i); |
891 | return -ENOMEM; | 929 | return -ENOMEM; |
892 | } | 930 | } |
893 | spin_lock_init(&portdata->lock); | 931 | spin_lock_init(&portdata->lock); |
894 | init_usb_anchor(&portdata->active); | 932 | init_usb_anchor(&portdata->active); |
895 | init_usb_anchor(&portdata->delayed); | 933 | init_usb_anchor(&portdata->delayed); |
934 | ifnum = i; | ||
935 | /* Assume low memory requirements */ | ||
936 | portdata->num_out_urbs = N_OUT_URB; | ||
937 | portdata->num_in_urbs = N_IN_URB; | ||
938 | |||
939 | /* Determine actual memory requirements */ | ||
940 | if (serial->num_ports == 1) { | ||
941 | /* Get interface number for composite device */ | ||
942 | ifnum = sierra_calc_interface(serial); | ||
943 | himemoryp = | ||
944 | (struct sierra_iface_info *)&typeB_interface_list; | ||
945 | if (is_himemory(ifnum, himemoryp)) { | ||
946 | portdata->num_out_urbs = N_OUT_URB_HM; | ||
947 | portdata->num_in_urbs = N_IN_URB_HM; | ||
948 | } | ||
949 | } | ||
950 | else { | ||
951 | himemoryp = | ||
952 | (struct sierra_iface_info *)&typeA_interface_list; | ||
953 | if (is_himemory(i, himemoryp)) { | ||
954 | portdata->num_out_urbs = N_OUT_URB_HM; | ||
955 | portdata->num_in_urbs = N_IN_URB_HM; | ||
956 | } | ||
957 | } | ||
958 | dev_dbg(&serial->dev->dev, | ||
959 | "Memory usage (urbs) interface #%d, in=%d, out=%d\n", | ||
960 | ifnum,portdata->num_in_urbs, portdata->num_out_urbs ); | ||
896 | /* Set the port private data pointer */ | 961 | /* Set the port private data pointer */ |
897 | usb_set_serial_port_data(port, portdata); | 962 | usb_set_serial_port_data(port, portdata); |
898 | } | 963 | } |
@@ -940,7 +1005,7 @@ static int sierra_suspend(struct usb_serial *serial, pm_message_t message) | |||
940 | struct sierra_intf_private *intfdata; | 1005 | struct sierra_intf_private *intfdata; |
941 | int b; | 1006 | int b; |
942 | 1007 | ||
943 | if (serial->dev->auto_pm) { | 1008 | if (message.event & PM_EVENT_AUTO) { |
944 | intfdata = serial->private; | 1009 | intfdata = serial->private; |
945 | spin_lock_irq(&intfdata->susp_lock); | 1010 | spin_lock_irq(&intfdata->susp_lock); |
946 | b = intfdata->in_flight; | 1011 | b = intfdata->in_flight; |