diff options
| -rw-r--r-- | drivers/usb/serial/sierra.c | 89 |
1 files changed, 77 insertions, 12 deletions
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 5019325ba25d..c5c41aed106d 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 | } |
