15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
269de51fdSKevin Lloyd /*
3033a3fb9SKevin Lloyd USB Driver for Sierra Wireless
4033a3fb9SKevin Lloyd
540d2ff32SElina Pasheva Copyright (C) 2006, 2007, 2008 Kevin Lloyd <klloyd@sierrawireless.com>,
640d2ff32SElina Pasheva
740d2ff32SElina Pasheva Copyright (C) 2008, 2009 Elina Pasheva, Matthew Safar, Rory Filer
840d2ff32SElina Pasheva <linux@sierrawireless.com>
9033a3fb9SKevin Lloyd
10033a3fb9SKevin Lloyd IMPORTANT DISCLAIMER: This driver is not commercially supported by
11033a3fb9SKevin Lloyd Sierra Wireless. Use at your own risk.
12033a3fb9SKevin Lloyd
13033a3fb9SKevin Lloyd Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
14033a3fb9SKevin Lloyd Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
1569de51fdSKevin Lloyd */
163a2b808eSElina Pasheva /* Uncomment to log function calls */
173a2b808eSElina Pasheva /* #define DEBUG */
18bcbec053SJohan Hovold
1940d2ff32SElina Pasheva #define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer"
20033a3fb9SKevin Lloyd #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
21033a3fb9SKevin Lloyd
2269de51fdSKevin Lloyd #include <linux/kernel.h>
23033a3fb9SKevin Lloyd #include <linux/jiffies.h>
24033a3fb9SKevin Lloyd #include <linux/errno.h>
2569de51fdSKevin Lloyd #include <linux/tty.h>
265a0e3ad6STejun Heo #include <linux/slab.h>
27033a3fb9SKevin Lloyd #include <linux/tty_flip.h>
2869de51fdSKevin Lloyd #include <linux/module.h>
2969de51fdSKevin Lloyd #include <linux/usb.h>
30a969888cSGreg Kroah-Hartman #include <linux/usb/serial.h>
3169de51fdSKevin Lloyd
32228426edSKevin Lloyd #define SWIMS_USB_REQUEST_SetPower 0x00
33228426edSKevin Lloyd #define SWIMS_USB_REQUEST_SetNmea 0x07
34112225b1SKevin Lloyd
353a2b808eSElina Pasheva #define N_IN_URB_HM 8
363a2b808eSElina Pasheva #define N_OUT_URB_HM 64
373a2b808eSElina Pasheva #define N_IN_URB 4
383a2b808eSElina Pasheva #define N_OUT_URB 4
39112225b1SKevin Lloyd #define IN_BUFLEN 4096
40112225b1SKevin Lloyd
4140d2ff32SElina Pasheva #define MAX_TRANSFER (PAGE_SIZE - 512)
4240d2ff32SElina Pasheva /* MAX_TRANSFER is chosen so that the VM is not stressed by
4340d2ff32SElina Pasheva allocations > PAGE_SIZE and the number of packets in a page
4440d2ff32SElina Pasheva is an integer 512 is the largest possible packet on EHCI */
4540d2ff32SElina Pasheva
4690ab5ee9SRusty Russell static bool nmea;
47112225b1SKevin Lloyd
48e0439cd9SJohan Hovold struct sierra_iface_list {
49e0439cd9SJohan Hovold const u8 *nums; /* array of interface numbers */
50e0439cd9SJohan Hovold size_t count; /* number of elements in array */
514db2299dSElina Pasheva };
524db2299dSElina Pasheva
53e6929a90SOliver Neukum struct sierra_intf_private {
54e6929a90SOliver Neukum spinlock_t susp_lock;
55e6929a90SOliver Neukum unsigned int suspended:1;
56e6929a90SOliver Neukum int in_flight;
5780cc0fcbSJohan Hovold unsigned int open_ports;
58e6929a90SOliver Neukum };
59e6929a90SOliver Neukum
sierra_set_power_state(struct usb_device * udev,__u16 swiState)6082a24e68SAdrian Bunk static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
61112225b1SKevin Lloyd {
6264318a52SGreg Kroah-Hartman return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
63228426edSKevin Lloyd SWIMS_USB_REQUEST_SetPower, /* __u8 request */
64f3564de4SKevin Lloyd USB_TYPE_VENDOR, /* __u8 request type */
65112225b1SKevin Lloyd swiState, /* __u16 value */
66112225b1SKevin Lloyd 0, /* __u16 index */
67112225b1SKevin Lloyd NULL, /* void *data */
68112225b1SKevin Lloyd 0, /* __u16 size */
69112225b1SKevin Lloyd USB_CTRL_SET_TIMEOUT); /* int timeout */
70112225b1SKevin Lloyd }
71112225b1SKevin Lloyd
sierra_vsc_set_nmea(struct usb_device * udev,__u16 enable)72228426edSKevin Lloyd static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable)
73112225b1SKevin Lloyd {
7464318a52SGreg Kroah-Hartman return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
75228426edSKevin Lloyd SWIMS_USB_REQUEST_SetNmea, /* __u8 request */
76f3564de4SKevin Lloyd USB_TYPE_VENDOR, /* __u8 request type */
77228426edSKevin Lloyd enable, /* __u16 value */
78228426edSKevin Lloyd 0x0000, /* __u16 index */
79228426edSKevin Lloyd NULL, /* void *data */
80228426edSKevin Lloyd 0, /* __u16 size */
81228426edSKevin Lloyd USB_CTRL_SET_TIMEOUT); /* int timeout */
82112225b1SKevin Lloyd }
83112225b1SKevin Lloyd
sierra_calc_num_ports(struct usb_serial * serial,struct usb_serial_endpoints * epds)8407814246SJohan Hovold static int sierra_calc_num_ports(struct usb_serial *serial,
8507814246SJohan Hovold struct usb_serial_endpoints *epds)
86228426edSKevin Lloyd {
879636b683SElina Pasheva int num_ports = 0;
889636b683SElina Pasheva u8 ifnum, numendpoints;
899636b683SElina Pasheva
909636b683SElina Pasheva ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
919636b683SElina Pasheva numendpoints = serial->interface->cur_altsetting->desc.bNumEndpoints;
92228426edSKevin Lloyd
939636b683SElina Pasheva /* Dummy interface present on some SKUs should be ignored */
949636b683SElina Pasheva if (ifnum == 0x99)
959636b683SElina Pasheva num_ports = 0;
969636b683SElina Pasheva else if (numendpoints <= 3)
979636b683SElina Pasheva num_ports = 1;
989636b683SElina Pasheva else
999636b683SElina Pasheva num_ports = (numendpoints-1)/2;
1009636b683SElina Pasheva return num_ports;
101228426edSKevin Lloyd }
102228426edSKevin Lloyd
is_listed(const u8 ifnum,const struct sierra_iface_list * list)103e0439cd9SJohan Hovold static bool is_listed(const u8 ifnum, const struct sierra_iface_list *list)
1044db2299dSElina Pasheva {
1054db2299dSElina Pasheva int i;
1064db2299dSElina Pasheva
107e0439cd9SJohan Hovold if (!list)
108e0439cd9SJohan Hovold return false;
1094db2299dSElina Pasheva
110e0439cd9SJohan Hovold for (i = 0; i < list->count; i++) {
111e0439cd9SJohan Hovold if (list->nums[i] == ifnum)
112e0439cd9SJohan Hovold return true;
1133a2b808eSElina Pasheva }
114e0439cd9SJohan Hovold
115e0439cd9SJohan Hovold return false;
1163a2b808eSElina Pasheva }
1173a2b808eSElina Pasheva
sierra_interface_num(struct usb_serial * serial)11816620b48SJohan Hovold static u8 sierra_interface_num(struct usb_serial *serial)
1197106967eSKevin Lloyd {
12016620b48SJohan Hovold return serial->interface->cur_altsetting->desc.bInterfaceNumber;
1217106967eSKevin Lloyd }
1227106967eSKevin Lloyd
sierra_probe(struct usb_serial * serial,const struct usb_device_id * id)123228426edSKevin Lloyd static int sierra_probe(struct usb_serial *serial,
124228426edSKevin Lloyd const struct usb_device_id *id)
125228426edSKevin Lloyd {
126e0439cd9SJohan Hovold const struct sierra_iface_list *ignore_list;
127228426edSKevin Lloyd int result = 0;
128228426edSKevin Lloyd struct usb_device *udev;
129228426edSKevin Lloyd u8 ifnum;
130e3173b22SKevin Lloyd
131228426edSKevin Lloyd udev = serial->dev;
13216620b48SJohan Hovold ifnum = sierra_interface_num(serial);
13364318a52SGreg Kroah-Hartman
1347106967eSKevin Lloyd /*
1357106967eSKevin Lloyd * If this interface supports more than 1 alternate
1367106967eSKevin Lloyd * select the 2nd one
1377106967eSKevin Lloyd */
1387106967eSKevin Lloyd if (serial->interface->num_altsetting == 2) {
139e3173b22SKevin Lloyd dev_dbg(&udev->dev, "Selecting alt setting for interface %d\n",
1407106967eSKevin Lloyd ifnum);
1417106967eSKevin Lloyd /* We know the alternate setting is 1 for the MC8785 */
1427106967eSKevin Lloyd usb_set_interface(udev, ifnum, 1);
1437106967eSKevin Lloyd }
1447106967eSKevin Lloyd
145e0439cd9SJohan Hovold ignore_list = (const struct sierra_iface_list *)id->driver_info;
146e0439cd9SJohan Hovold
147e0439cd9SJohan Hovold if (is_listed(ifnum, ignore_list)) {
148e0439cd9SJohan Hovold dev_dbg(&serial->dev->dev, "Ignoring interface #%d\n", ifnum);
1494db2299dSElina Pasheva return -ENODEV;
1504db2299dSElina Pasheva }
1514db2299dSElina Pasheva
152228426edSKevin Lloyd return result;
153112225b1SKevin Lloyd }
154033a3fb9SKevin Lloyd
1553a2b808eSElina Pasheva /* interfaces with higher memory requirements */
1563a2b808eSElina Pasheva static const u8 hi_memory_typeA_ifaces[] = { 0, 2 };
157e0439cd9SJohan Hovold static const struct sierra_iface_list typeA_interface_list = {
158e0439cd9SJohan Hovold .nums = hi_memory_typeA_ifaces,
159e0439cd9SJohan Hovold .count = ARRAY_SIZE(hi_memory_typeA_ifaces),
1603a2b808eSElina Pasheva };
1613a2b808eSElina Pasheva
1623a2b808eSElina Pasheva static const u8 hi_memory_typeB_ifaces[] = { 3, 4, 5, 6 };
163e0439cd9SJohan Hovold static const struct sierra_iface_list typeB_interface_list = {
164e0439cd9SJohan Hovold .nums = hi_memory_typeB_ifaces,
165e0439cd9SJohan Hovold .count = ARRAY_SIZE(hi_memory_typeB_ifaces),
1663a2b808eSElina Pasheva };
1673a2b808eSElina Pasheva
16866f092edSGreg Kroah-Hartman /* 'ignorelist' of interfaces not served by this driver */
169749541d1SBjørn Mork static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11, 19, 20 };
170e0439cd9SJohan Hovold static const struct sierra_iface_list direct_ip_interface_ignore = {
171e0439cd9SJohan Hovold .nums = direct_ip_non_serial_ifaces,
172e0439cd9SJohan Hovold .count = ARRAY_SIZE(direct_ip_non_serial_ifaces),
1734db2299dSElina Pasheva };
1744db2299dSElina Pasheva
1757d40d7e8SNémeth Márton static const struct usb_device_id id_table[] = {
176c5f3d87dSElina Pasheva { USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */
177c5f3d87dSElina Pasheva { USB_DEVICE(0x03F0, 0x1B1D) }, /* HP ev2200 a.k.a MC5720 */
178cfbaa393SWilliam Lightning { USB_DEVICE(0x03F0, 0x211D) }, /* HP ev2210 a.k.a MC5725 */
179c5f3d87dSElina Pasheva { USB_DEVICE(0x03F0, 0x1E1D) }, /* HP hs2300 a.k.a MC8775 */
180c5f3d87dSElina Pasheva
18169de51fdSKevin Lloyd { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
182e43062ddSKevin Lloyd { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
18390ac3c81SGreg Kroah-Hartman { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
184e43062ddSKevin Lloyd { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
185b9e13ac3Sagilmore@wirelessbeehive.com { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */
186c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x0022) }, /* Sierra Wireless EM5725 */
187c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x0024) }, /* Sierra Wireless MC5727 */
188c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x0224) }, /* Sierra Wireless MC5727 */
189e43062ddSKevin Lloyd { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
190e43062ddSKevin Lloyd { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
191c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
1929454c46aSKevin Lloyd { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */
1939d72c81dSaugust huber { USB_DEVICE(0x1199, 0x0301) }, /* Sierra Wireless USB Dongle 250U */
1944e0fee82SKevin Lloyd /* Sierra Wireless C597 */
1954e0fee82SKevin Lloyd { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0023, 0xFF, 0xFF, 0xFF) },
196c5f3d87dSElina Pasheva /* Sierra Wireless T598 */
197e3173b22SKevin Lloyd { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0025, 0xFF, 0xFF, 0xFF) },
198c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x0026) }, /* Sierra Wireless T11 */
199c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x0027) }, /* Sierra Wireless AC402 */
200c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x0028) }, /* Sierra Wireless MC5728 */
201c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x0029) }, /* Sierra Wireless Device */
2029454c46aSKevin Lloyd
20369de51fdSKevin Lloyd { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
20469de51fdSKevin Lloyd { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
205c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
206c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x6805) }, /* Sierra Wireless MC8765 */
207c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x6808) }, /* Sierra Wireless MC8755 */
208c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x6809) }, /* Sierra Wireless MC8765 */
2099454c46aSKevin Lloyd { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
210c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 */
2117f170a63SKevin Lloyd { USB_DEVICE(0x1199, 0x6815) }, /* Sierra Wireless MC8775 */
212c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x6816) }, /* Sierra Wireless MC8775 */
21369de51fdSKevin Lloyd { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
2147106967eSKevin Lloyd { USB_DEVICE(0x1199, 0x6821) }, /* Sierra Wireless AirCard 875U */
215c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x6822) }, /* Sierra Wireless AirCard 875E */
2169454c46aSKevin Lloyd { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780 */
2179454c46aSKevin Lloyd { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781 */
218c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x6834) }, /* Sierra Wireless MC8780 */
219c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x6835) }, /* Sierra Wireless MC8781 */
220c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x6838) }, /* Sierra Wireless MC8780 */
221c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x6839) }, /* Sierra Wireless MC8781 */
222b77a5c70SKevin Lloyd { USB_DEVICE(0x1199, 0x683A) }, /* Sierra Wireless MC8785 */
223e3173b22SKevin Lloyd { USB_DEVICE(0x1199, 0x683B) }, /* Sierra Wireless MC8785 Composite */
2244db2299dSElina Pasheva /* Sierra Wireless MC8790, MC8791, MC8792 Composite */
2254db2299dSElina Pasheva { USB_DEVICE(0x1199, 0x683C) },
2264db2299dSElina Pasheva { USB_DEVICE(0x1199, 0x683D) }, /* Sierra Wireless MC8791 Composite */
2274db2299dSElina Pasheva /* Sierra Wireless MC8790, MC8791, MC8792 */
2284db2299dSElina Pasheva { USB_DEVICE(0x1199, 0x683E) },
2299454c46aSKevin Lloyd { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
2309454c46aSKevin Lloyd { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
2319454c46aSKevin Lloyd { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */
2329454c46aSKevin Lloyd { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881 E */
2336835b32cSKevin Lloyd { USB_DEVICE(0x1199, 0x6855) }, /* Sierra Wireless AirCard 880 U */
23462aad3abSJessica L. Blank { USB_DEVICE(0x1199, 0x6856) }, /* Sierra Wireless AirCard 881 U */
235e3173b22SKevin Lloyd { USB_DEVICE(0x1199, 0x6859) }, /* Sierra Wireless AirCard 885 E */
236e3173b22SKevin Lloyd { USB_DEVICE(0x1199, 0x685A) }, /* Sierra Wireless AirCard 885 E */
237e3173b22SKevin Lloyd /* Sierra Wireless C885 */
238e3173b22SKevin Lloyd { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6880, 0xFF, 0xFF, 0xFF)},
239c5f3d87dSElina Pasheva /* Sierra Wireless C888, Air Card 501, USB 303, USB 304 */
240e3173b22SKevin Lloyd { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6890, 0xFF, 0xFF, 0xFF)},
241c5f3d87dSElina Pasheva /* Sierra Wireless C22/C33 */
24273b2c205SKevin Lloyd { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6891, 0xFF, 0xFF, 0xFF)},
243c5f3d87dSElina Pasheva /* Sierra Wireless HSPA Non-Composite Device */
244e3173b22SKevin Lloyd { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6892, 0xFF, 0xFF, 0xFF)},
245c5f3d87dSElina Pasheva { USB_DEVICE(0x1199, 0x6893) }, /* Sierra Wireless Device */
246049255f5SBjørn Mork /* Sierra Wireless Direct IP modems */
247049255f5SBjørn Mork { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68A3, 0xFF, 0xFF, 0xFF),
24866f092edSGreg Kroah-Hartman .driver_info = (kernel_ulong_t)&direct_ip_interface_ignore
2494db2299dSElina Pasheva },
2505b3da692SBjørn Mork { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68AA, 0xFF, 0xFF, 0xFF),
25166f092edSGreg Kroah-Hartman .driver_info = (kernel_ulong_t)&direct_ip_interface_ignore
2525b3da692SBjørn Mork },
25374472233SDirk Behme { USB_DEVICE(0x1199, 0x68AB) }, /* Sierra Wireless AR8550 */
25419a3dd15STom Cassidy /* AT&T Direct IP LTE modems */
25519a3dd15STom Cassidy { USB_DEVICE_AND_INTERFACE_INFO(0x0F3D, 0x68AA, 0xFF, 0xFF, 0xFF),
25666f092edSGreg Kroah-Hartman .driver_info = (kernel_ulong_t)&direct_ip_interface_ignore
25719a3dd15STom Cassidy },
258049255f5SBjørn Mork /* Airprime/Sierra Wireless Direct IP modems */
259049255f5SBjørn Mork { USB_DEVICE_AND_INTERFACE_INFO(0x0F3D, 0x68A3, 0xFF, 0xFF, 0xFF),
26066f092edSGreg Kroah-Hartman .driver_info = (kernel_ulong_t)&direct_ip_interface_ignore
261e1dc5157SJon Thomas },
2624db2299dSElina Pasheva
26369de51fdSKevin Lloyd { }
26469de51fdSKevin Lloyd };
265964ee1deSGreg Kroah-Hartman MODULE_DEVICE_TABLE(usb, id_table);
266033a3fb9SKevin Lloyd
26769de51fdSKevin Lloyd
268033a3fb9SKevin Lloyd struct sierra_port_private {
26917c23274SGreg Kroah-Hartman spinlock_t lock; /* lock the structure */
27017c23274SGreg Kroah-Hartman int outstanding_urbs; /* number of out urbs in flight */
271e6929a90SOliver Neukum struct usb_anchor active;
272e6929a90SOliver Neukum struct usb_anchor delayed;
27317c23274SGreg Kroah-Hartman
2743a2b808eSElina Pasheva int num_out_urbs;
2753a2b808eSElina Pasheva int num_in_urbs;
2764f4f9c53SOliver Neukum /* Input endpoints and buffers for this port */
2773a2b808eSElina Pasheva struct urb *in_urbs[N_IN_URB_HM];
278033a3fb9SKevin Lloyd
279033a3fb9SKevin Lloyd /* Settings for the port */
280033a3fb9SKevin Lloyd int rts_state; /* Handshaking pins (outputs) */
281033a3fb9SKevin Lloyd int dtr_state;
282033a3fb9SKevin Lloyd int cts_state; /* Handshaking pins (inputs) */
283033a3fb9SKevin Lloyd int dsr_state;
284033a3fb9SKevin Lloyd int dcd_state;
285033a3fb9SKevin Lloyd int ri_state;
286033a3fb9SKevin Lloyd };
287033a3fb9SKevin Lloyd
sierra_send_setup(struct usb_serial_port * port)288335f8514SAlan Cox static int sierra_send_setup(struct usb_serial_port *port)
28969de51fdSKevin Lloyd {
290964ee1deSGreg Kroah-Hartman struct usb_serial *serial = port->serial;
291964ee1deSGreg Kroah-Hartman struct sierra_port_private *portdata;
292228426edSKevin Lloyd __u16 interface = 0;
293335f8514SAlan Cox int val = 0;
2943c77d513SElina Pasheva int do_send = 0;
2953c77d513SElina Pasheva int retval;
296033a3fb9SKevin Lloyd
297964ee1deSGreg Kroah-Hartman portdata = usb_get_serial_port_data(port);
298033a3fb9SKevin Lloyd
299964ee1deSGreg Kroah-Hartman if (portdata->dtr_state)
300964ee1deSGreg Kroah-Hartman val |= 0x01;
301964ee1deSGreg Kroah-Hartman if (portdata->rts_state)
302964ee1deSGreg Kroah-Hartman val |= 0x02;
303964ee1deSGreg Kroah-Hartman
304e3173b22SKevin Lloyd /* If composite device then properly report interface */
30500b040deSAlan Cox if (serial->num_ports == 1) {
30616620b48SJohan Hovold interface = sierra_interface_num(serial);
30700b040deSAlan Cox /* Control message is sent only to interfaces with
30800b040deSAlan Cox * interrupt_in endpoints
30900b040deSAlan Cox */
31000b040deSAlan Cox if (port->interrupt_in_urb) {
31100b040deSAlan Cox /* send control message */
3123c77d513SElina Pasheva do_send = 1;
31300b040deSAlan Cox }
31400b040deSAlan Cox }
315e3173b22SKevin Lloyd
316e3173b22SKevin Lloyd /* Otherwise the need to do non-composite mapping */
317e3173b22SKevin Lloyd else {
318228426edSKevin Lloyd if (port->bulk_out_endpointAddress == 2)
319228426edSKevin Lloyd interface = 0;
320228426edSKevin Lloyd else if (port->bulk_out_endpointAddress == 4)
321228426edSKevin Lloyd interface = 1;
322228426edSKevin Lloyd else if (port->bulk_out_endpointAddress == 5)
323228426edSKevin Lloyd interface = 2;
3243c77d513SElina Pasheva
3253c77d513SElina Pasheva do_send = 1;
32600b040deSAlan Cox }
3273c77d513SElina Pasheva if (!do_send)
328033a3fb9SKevin Lloyd return 0;
3293c77d513SElina Pasheva
3305b7c1178SOliver Neukum retval = usb_autopm_get_interface(serial->interface);
3315b7c1178SOliver Neukum if (retval < 0)
3325b7c1178SOliver Neukum return retval;
3335b7c1178SOliver Neukum
334d3048898SJohan Hovold retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
3353c77d513SElina Pasheva 0x22, 0x21, val, interface, NULL, 0, USB_CTRL_SET_TIMEOUT);
3363c77d513SElina Pasheva usb_autopm_put_interface(serial->interface);
3373c77d513SElina Pasheva
3383c77d513SElina Pasheva return retval;
33969de51fdSKevin Lloyd }
34069de51fdSKevin Lloyd
sierra_tiocmget(struct tty_struct * tty)34160b33c13SAlan Cox static int sierra_tiocmget(struct tty_struct *tty)
342033a3fb9SKevin Lloyd {
34395da310eSAlan Cox struct usb_serial_port *port = tty->driver_data;
344033a3fb9SKevin Lloyd unsigned int value;
345033a3fb9SKevin Lloyd struct sierra_port_private *portdata;
346033a3fb9SKevin Lloyd
347033a3fb9SKevin Lloyd portdata = usb_get_serial_port_data(port);
348033a3fb9SKevin Lloyd
349033a3fb9SKevin Lloyd value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
350033a3fb9SKevin Lloyd ((portdata->dtr_state) ? TIOCM_DTR : 0) |
351033a3fb9SKevin Lloyd ((portdata->cts_state) ? TIOCM_CTS : 0) |
352033a3fb9SKevin Lloyd ((portdata->dsr_state) ? TIOCM_DSR : 0) |
353033a3fb9SKevin Lloyd ((portdata->dcd_state) ? TIOCM_CAR : 0) |
354033a3fb9SKevin Lloyd ((portdata->ri_state) ? TIOCM_RNG : 0);
355033a3fb9SKevin Lloyd
356033a3fb9SKevin Lloyd return value;
357033a3fb9SKevin Lloyd }
358033a3fb9SKevin Lloyd
sierra_tiocmset(struct tty_struct * tty,unsigned int set,unsigned int clear)35920b9d177SAlan Cox static int sierra_tiocmset(struct tty_struct *tty,
360033a3fb9SKevin Lloyd unsigned int set, unsigned int clear)
361033a3fb9SKevin Lloyd {
36295da310eSAlan Cox struct usb_serial_port *port = tty->driver_data;
363033a3fb9SKevin Lloyd struct sierra_port_private *portdata;
364033a3fb9SKevin Lloyd
365033a3fb9SKevin Lloyd portdata = usb_get_serial_port_data(port);
366033a3fb9SKevin Lloyd
367033a3fb9SKevin Lloyd if (set & TIOCM_RTS)
368033a3fb9SKevin Lloyd portdata->rts_state = 1;
369033a3fb9SKevin Lloyd if (set & TIOCM_DTR)
370033a3fb9SKevin Lloyd portdata->dtr_state = 1;
371033a3fb9SKevin Lloyd
372033a3fb9SKevin Lloyd if (clear & TIOCM_RTS)
373033a3fb9SKevin Lloyd portdata->rts_state = 0;
374033a3fb9SKevin Lloyd if (clear & TIOCM_DTR)
375033a3fb9SKevin Lloyd portdata->dtr_state = 0;
376335f8514SAlan Cox return sierra_send_setup(port);
377033a3fb9SKevin Lloyd }
378033a3fb9SKevin Lloyd
sierra_release_urb(struct urb * urb)379b9a44bc1SElina Pasheva static void sierra_release_urb(struct urb *urb)
380b9a44bc1SElina Pasheva {
381b9a44bc1SElina Pasheva if (urb) {
382b9a44bc1SElina Pasheva kfree(urb->transfer_buffer);
383b9a44bc1SElina Pasheva usb_free_urb(urb);
384b9a44bc1SElina Pasheva }
385b9a44bc1SElina Pasheva }
386b9a44bc1SElina Pasheva
sierra_outdat_callback(struct urb * urb)38717c23274SGreg Kroah-Hartman static void sierra_outdat_callback(struct urb *urb)
38817c23274SGreg Kroah-Hartman {
38917c23274SGreg Kroah-Hartman struct usb_serial_port *port = urb->context;
39017c23274SGreg Kroah-Hartman struct sierra_port_private *portdata = usb_get_serial_port_data(port);
391e6929a90SOliver Neukum struct sierra_intf_private *intfdata;
39217c23274SGreg Kroah-Hartman int status = urb->status;
393d4bf25b3SJohn Ogness unsigned long flags;
39417c23274SGreg Kroah-Hartman
3957c80782eSJohan Hovold intfdata = usb_get_serial_data(port->serial);
39617c23274SGreg Kroah-Hartman
39717c23274SGreg Kroah-Hartman /* free up the transfer buffer, as usb_free_urb() does not do this */
39817c23274SGreg Kroah-Hartman kfree(urb->transfer_buffer);
399e6929a90SOliver Neukum usb_autopm_put_interface_async(port->serial->interface);
40017c23274SGreg Kroah-Hartman if (status)
4017384a922SKevin Lloyd dev_dbg(&port->dev, "%s - nonzero write bulk status "
4025d44b361SElina Pasheva "received: %d\n", __func__, status);
40317c23274SGreg Kroah-Hartman
404d4bf25b3SJohn Ogness spin_lock_irqsave(&portdata->lock, flags);
40517c23274SGreg Kroah-Hartman --portdata->outstanding_urbs;
406d4bf25b3SJohn Ogness spin_unlock_irqrestore(&portdata->lock, flags);
407d4bf25b3SJohn Ogness spin_lock_irqsave(&intfdata->susp_lock, flags);
408e6929a90SOliver Neukum --intfdata->in_flight;
409d4bf25b3SJohn Ogness spin_unlock_irqrestore(&intfdata->susp_lock, flags);
41017c23274SGreg Kroah-Hartman
41117c23274SGreg Kroah-Hartman usb_serial_port_softint(port);
41217c23274SGreg Kroah-Hartman }
41317c23274SGreg Kroah-Hartman
414033a3fb9SKevin Lloyd /* Write */
sierra_write(struct tty_struct * tty,struct usb_serial_port * port,const unsigned char * buf,int count)41595da310eSAlan Cox static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,
416033a3fb9SKevin Lloyd const unsigned char *buf, int count)
417033a3fb9SKevin Lloyd {
418a45a1e07SJulia Lawall struct sierra_port_private *portdata;
419e6929a90SOliver Neukum struct sierra_intf_private *intfdata;
42017c23274SGreg Kroah-Hartman struct usb_serial *serial = port->serial;
42117c23274SGreg Kroah-Hartman unsigned long flags;
42217c23274SGreg Kroah-Hartman unsigned char *buffer;
42317c23274SGreg Kroah-Hartman struct urb *urb;
42440d2ff32SElina Pasheva size_t writesize = min((size_t)count, (size_t)MAX_TRANSFER);
42540d2ff32SElina Pasheva int retval = 0;
42640d2ff32SElina Pasheva
42740d2ff32SElina Pasheva /* verify that we actually have some data to write */
42840d2ff32SElina Pasheva if (count == 0)
42940d2ff32SElina Pasheva return 0;
430033a3fb9SKevin Lloyd
431033a3fb9SKevin Lloyd portdata = usb_get_serial_port_data(port);
4327c80782eSJohan Hovold intfdata = usb_get_serial_data(serial);
433033a3fb9SKevin Lloyd
4340b10395aSAndrew Morton dev_dbg(&port->dev, "%s: write (%zd bytes)\n", __func__, writesize);
43517c23274SGreg Kroah-Hartman spin_lock_irqsave(&portdata->lock, flags);
43640d2ff32SElina Pasheva dev_dbg(&port->dev, "%s - outstanding_urbs: %d\n", __func__,
43740d2ff32SElina Pasheva portdata->outstanding_urbs);
4383a2b808eSElina Pasheva if (portdata->outstanding_urbs > portdata->num_out_urbs) {
43917c23274SGreg Kroah-Hartman spin_unlock_irqrestore(&portdata->lock, flags);
4407384a922SKevin Lloyd dev_dbg(&port->dev, "%s - write limit hit\n", __func__);
44117c23274SGreg Kroah-Hartman return 0;
442033a3fb9SKevin Lloyd }
44317c23274SGreg Kroah-Hartman portdata->outstanding_urbs++;
44440d2ff32SElina Pasheva dev_dbg(&port->dev, "%s - 1, outstanding_urbs: %d\n", __func__,
44540d2ff32SElina Pasheva portdata->outstanding_urbs);
44617c23274SGreg Kroah-Hartman spin_unlock_irqrestore(&portdata->lock, flags);
447033a3fb9SKevin Lloyd
448e6929a90SOliver Neukum retval = usb_autopm_get_interface_async(serial->interface);
449e6929a90SOliver Neukum if (retval < 0) {
450e6929a90SOliver Neukum spin_lock_irqsave(&portdata->lock, flags);
451e6929a90SOliver Neukum portdata->outstanding_urbs--;
452e6929a90SOliver Neukum spin_unlock_irqrestore(&portdata->lock, flags);
453e6929a90SOliver Neukum goto error_simple;
454e6929a90SOliver Neukum }
455e6929a90SOliver Neukum
4567828466cSSlark Xiao buffer = kmemdup(buf, writesize, GFP_ATOMIC);
45717c23274SGreg Kroah-Hartman if (!buffer) {
45840d2ff32SElina Pasheva retval = -ENOMEM;
45917c23274SGreg Kroah-Hartman goto error_no_buffer;
460033a3fb9SKevin Lloyd }
461033a3fb9SKevin Lloyd
46217c23274SGreg Kroah-Hartman urb = usb_alloc_urb(0, GFP_ATOMIC);
46317c23274SGreg Kroah-Hartman if (!urb) {
46440d2ff32SElina Pasheva retval = -ENOMEM;
46517c23274SGreg Kroah-Hartman goto error_no_urb;
46617c23274SGreg Kroah-Hartman }
46717c23274SGreg Kroah-Hartman
46859d33f2fSGreg Kroah-Hartman usb_serial_debug_data(&port->dev, __func__, writesize, buffer);
46917c23274SGreg Kroah-Hartman
47017c23274SGreg Kroah-Hartman usb_fill_bulk_urb(urb, serial->dev,
47117c23274SGreg Kroah-Hartman usb_sndbulkpipe(serial->dev,
47217c23274SGreg Kroah-Hartman port->bulk_out_endpointAddress),
47340d2ff32SElina Pasheva buffer, writesize, sierra_outdat_callback, port);
47417c23274SGreg Kroah-Hartman
475238ebd13SElina Pasheva /* Handle the need to send a zero length packet */
476238ebd13SElina Pasheva urb->transfer_flags |= URB_ZERO_PACKET;
477238ebd13SElina Pasheva
478e6929a90SOliver Neukum spin_lock_irqsave(&intfdata->susp_lock, flags);
479e6929a90SOliver Neukum
480e6929a90SOliver Neukum if (intfdata->suspended) {
481e6929a90SOliver Neukum usb_anchor_urb(urb, &portdata->delayed);
482e6929a90SOliver Neukum spin_unlock_irqrestore(&intfdata->susp_lock, flags);
483e6929a90SOliver Neukum goto skip_power;
484e6929a90SOliver Neukum } else {
485e6929a90SOliver Neukum usb_anchor_urb(urb, &portdata->active);
486e6929a90SOliver Neukum }
48717c23274SGreg Kroah-Hartman /* send it down the pipe */
48840d2ff32SElina Pasheva retval = usb_submit_urb(urb, GFP_ATOMIC);
48940d2ff32SElina Pasheva if (retval) {
490e6929a90SOliver Neukum usb_unanchor_urb(urb);
491e6929a90SOliver Neukum spin_unlock_irqrestore(&intfdata->susp_lock, flags);
49217c23274SGreg Kroah-Hartman dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
49340d2ff32SElina Pasheva "with status = %d\n", __func__, retval);
49417c23274SGreg Kroah-Hartman goto error;
495e6929a90SOliver Neukum } else {
496e6929a90SOliver Neukum intfdata->in_flight++;
497e6929a90SOliver Neukum spin_unlock_irqrestore(&intfdata->susp_lock, flags);
49817c23274SGreg Kroah-Hartman }
49917c23274SGreg Kroah-Hartman
500e6929a90SOliver Neukum skip_power:
50117c23274SGreg Kroah-Hartman /* we are done with this urb, so let the host driver
50217c23274SGreg Kroah-Hartman * really free it when it is finished with it */
50317c23274SGreg Kroah-Hartman usb_free_urb(urb);
50417c23274SGreg Kroah-Hartman
50540d2ff32SElina Pasheva return writesize;
50617c23274SGreg Kroah-Hartman error:
50717c23274SGreg Kroah-Hartman usb_free_urb(urb);
50817c23274SGreg Kroah-Hartman error_no_urb:
50917c23274SGreg Kroah-Hartman kfree(buffer);
51017c23274SGreg Kroah-Hartman error_no_buffer:
51117c23274SGreg Kroah-Hartman spin_lock_irqsave(&portdata->lock, flags);
51217c23274SGreg Kroah-Hartman --portdata->outstanding_urbs;
51340d2ff32SElina Pasheva dev_dbg(&port->dev, "%s - 2. outstanding_urbs: %d\n", __func__,
51440d2ff32SElina Pasheva portdata->outstanding_urbs);
51517c23274SGreg Kroah-Hartman spin_unlock_irqrestore(&portdata->lock, flags);
516e6929a90SOliver Neukum usb_autopm_put_interface_async(serial->interface);
517e6929a90SOliver Neukum error_simple:
51840d2ff32SElina Pasheva return retval;
519033a3fb9SKevin Lloyd }
520033a3fb9SKevin Lloyd
sierra_indat_callback(struct urb * urb)521033a3fb9SKevin Lloyd static void sierra_indat_callback(struct urb *urb)
522033a3fb9SKevin Lloyd {
523033a3fb9SKevin Lloyd int err;
524033a3fb9SKevin Lloyd int endpoint;
525033a3fb9SKevin Lloyd struct usb_serial_port *port;
526033a3fb9SKevin Lloyd unsigned char *data = urb->transfer_buffer;
52717dd2215SGreg Kroah-Hartman int status = urb->status;
528033a3fb9SKevin Lloyd
529033a3fb9SKevin Lloyd endpoint = usb_pipeendpoint(urb->pipe);
530cdc97792SMing Lei port = urb->context;
531033a3fb9SKevin Lloyd
53217dd2215SGreg Kroah-Hartman if (status) {
5337384a922SKevin Lloyd dev_dbg(&port->dev, "%s: nonzero status: %d on"
5345d44b361SElina Pasheva " endpoint %02x\n", __func__, status, endpoint);
535033a3fb9SKevin Lloyd } else {
536033a3fb9SKevin Lloyd if (urb->actual_length) {
53705c7cd39SJiri Slaby tty_insert_flip_string(&port->port, data,
538b87c6e86SElina Pasheva urb->actual_length);
5392e124b4aSJiri Slaby tty_flip_buffer_push(&port->port);
540b0cda8c5SElina Pasheva
54159d33f2fSGreg Kroah-Hartman usb_serial_debug_data(&port->dev, __func__,
54259d33f2fSGreg Kroah-Hartman urb->actual_length, data);
543b0cda8c5SElina Pasheva } else {
5447384a922SKevin Lloyd dev_dbg(&port->dev, "%s: empty read urb"
5455d44b361SElina Pasheva " received\n", __func__);
546b0cda8c5SElina Pasheva }
547b0cda8c5SElina Pasheva }
548033a3fb9SKevin Lloyd
549033a3fb9SKevin Lloyd /* Resubmit urb so we continue receiving */
5501f87158eSAlan Stern if (status != -ESHUTDOWN && status != -EPERM) {
551e6929a90SOliver Neukum usb_mark_last_busy(port->serial->dev);
552033a3fb9SKevin Lloyd err = usb_submit_urb(urb, GFP_ATOMIC);
5531f87158eSAlan Stern if (err && err != -EPERM)
55417c23274SGreg Kroah-Hartman dev_err(&port->dev, "resubmit read urb failed."
555898eb71cSJoe Perches "(%d)\n", err);
556033a3fb9SKevin Lloyd }
557033a3fb9SKevin Lloyd }
558033a3fb9SKevin Lloyd
sierra_instat_callback(struct urb * urb)559033a3fb9SKevin Lloyd static void sierra_instat_callback(struct urb *urb)
560033a3fb9SKevin Lloyd {
561033a3fb9SKevin Lloyd int err;
56217dd2215SGreg Kroah-Hartman int status = urb->status;
563cdc97792SMing Lei struct usb_serial_port *port = urb->context;
564033a3fb9SKevin Lloyd struct sierra_port_private *portdata = usb_get_serial_port_data(port);
565033a3fb9SKevin Lloyd struct usb_serial *serial = port->serial;
566033a3fb9SKevin Lloyd
5675d44b361SElina Pasheva dev_dbg(&port->dev, "%s: urb %p port %p has data %p\n", __func__,
5687384a922SKevin Lloyd urb, port, portdata);
569033a3fb9SKevin Lloyd
57017dd2215SGreg Kroah-Hartman if (status == 0) {
571eb0c68eaSJohan Hovold struct usb_ctrlrequest *req_pkt = urb->transfer_buffer;
572033a3fb9SKevin Lloyd
573033a3fb9SKevin Lloyd if (!req_pkt) {
5747384a922SKevin Lloyd dev_dbg(&port->dev, "%s: NULL req_pkt\n",
5757384a922SKevin Lloyd __func__);
576033a3fb9SKevin Lloyd return;
577033a3fb9SKevin Lloyd }
578033a3fb9SKevin Lloyd if ((req_pkt->bRequestType == 0xA1) &&
579033a3fb9SKevin Lloyd (req_pkt->bRequest == 0x20)) {
580033a3fb9SKevin Lloyd int old_dcd_state;
581033a3fb9SKevin Lloyd unsigned char signals = *((unsigned char *)
582033a3fb9SKevin Lloyd urb->transfer_buffer +
583033a3fb9SKevin Lloyd sizeof(struct usb_ctrlrequest));
584033a3fb9SKevin Lloyd
5855d44b361SElina Pasheva dev_dbg(&port->dev, "%s: signal x%x\n", __func__,
5867384a922SKevin Lloyd signals);
587033a3fb9SKevin Lloyd
588033a3fb9SKevin Lloyd old_dcd_state = portdata->dcd_state;
589033a3fb9SKevin Lloyd portdata->cts_state = 1;
590033a3fb9SKevin Lloyd portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
591033a3fb9SKevin Lloyd portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
592033a3fb9SKevin Lloyd portdata->ri_state = ((signals & 0x08) ? 1 : 0);
593033a3fb9SKevin Lloyd
594aa27a094SJiri Slaby if (old_dcd_state && !portdata->dcd_state)
595aa27a094SJiri Slaby tty_port_tty_hangup(&port->port, true);
596033a3fb9SKevin Lloyd } else {
5975d44b361SElina Pasheva dev_dbg(&port->dev, "%s: type %x req %x\n",
5987384a922SKevin Lloyd __func__, req_pkt->bRequestType,
5997384a922SKevin Lloyd req_pkt->bRequest);
600033a3fb9SKevin Lloyd }
601033a3fb9SKevin Lloyd } else
6025d44b361SElina Pasheva dev_dbg(&port->dev, "%s: error %d\n", __func__, status);
603033a3fb9SKevin Lloyd
604033a3fb9SKevin Lloyd /* Resubmit urb so we continue receiving IRQ data */
6051f87158eSAlan Stern if (status != -ESHUTDOWN && status != -ENOENT) {
606e6929a90SOliver Neukum usb_mark_last_busy(serial->dev);
607033a3fb9SKevin Lloyd err = usb_submit_urb(urb, GFP_ATOMIC);
6081f87158eSAlan Stern if (err && err != -EPERM)
609c76a23daSElina Pasheva dev_err(&port->dev, "%s: resubmit intr urb "
6105d44b361SElina Pasheva "failed. (%d)\n", __func__, err);
611033a3fb9SKevin Lloyd }
612033a3fb9SKevin Lloyd }
613033a3fb9SKevin Lloyd
sierra_write_room(struct tty_struct * tty)61494cc7aeaSJiri Slaby static unsigned int sierra_write_room(struct tty_struct *tty)
615033a3fb9SKevin Lloyd {
61695da310eSAlan Cox struct usb_serial_port *port = tty->driver_data;
61717c23274SGreg Kroah-Hartman struct sierra_port_private *portdata = usb_get_serial_port_data(port);
61817c23274SGreg Kroah-Hartman unsigned long flags;
619033a3fb9SKevin Lloyd
62017c23274SGreg Kroah-Hartman /* try to give a good number back based on if we have any free urbs at
62117c23274SGreg Kroah-Hartman * this point in time */
62217c23274SGreg Kroah-Hartman spin_lock_irqsave(&portdata->lock, flags);
6233a2b808eSElina Pasheva if (portdata->outstanding_urbs > (portdata->num_out_urbs * 2) / 3) {
62417c23274SGreg Kroah-Hartman spin_unlock_irqrestore(&portdata->lock, flags);
6257384a922SKevin Lloyd dev_dbg(&port->dev, "%s - write limit hit\n", __func__);
62617c23274SGreg Kroah-Hartman return 0;
627033a3fb9SKevin Lloyd }
62817c23274SGreg Kroah-Hartman spin_unlock_irqrestore(&portdata->lock, flags);
629033a3fb9SKevin Lloyd
63017c23274SGreg Kroah-Hartman return 2048;
631033a3fb9SKevin Lloyd }
632033a3fb9SKevin Lloyd
sierra_chars_in_buffer(struct tty_struct * tty)633155591d3SJiri Slaby static unsigned int sierra_chars_in_buffer(struct tty_struct *tty)
63493670599SJohan Hovold {
63593670599SJohan Hovold struct usb_serial_port *port = tty->driver_data;
63693670599SJohan Hovold struct sierra_port_private *portdata = usb_get_serial_port_data(port);
63793670599SJohan Hovold unsigned long flags;
638155591d3SJiri Slaby unsigned int chars;
63993670599SJohan Hovold
64093670599SJohan Hovold /* NOTE: This overcounts somewhat. */
64193670599SJohan Hovold spin_lock_irqsave(&portdata->lock, flags);
64293670599SJohan Hovold chars = portdata->outstanding_urbs * MAX_TRANSFER;
64393670599SJohan Hovold spin_unlock_irqrestore(&portdata->lock, flags);
64493670599SJohan Hovold
645155591d3SJiri Slaby dev_dbg(&port->dev, "%s - %u\n", __func__, chars);
64693670599SJohan Hovold
64793670599SJohan Hovold return chars;
64893670599SJohan Hovold }
64993670599SJohan Hovold
sierra_stop_rx_urbs(struct usb_serial_port * port)650b9a44bc1SElina Pasheva static void sierra_stop_rx_urbs(struct usb_serial_port *port)
651b9a44bc1SElina Pasheva {
652b9a44bc1SElina Pasheva int i;
653b9a44bc1SElina Pasheva struct sierra_port_private *portdata = usb_get_serial_port_data(port);
654b9a44bc1SElina Pasheva
6553a2b808eSElina Pasheva for (i = 0; i < portdata->num_in_urbs; i++)
656b9a44bc1SElina Pasheva usb_kill_urb(portdata->in_urbs[i]);
657b9a44bc1SElina Pasheva
658b9a44bc1SElina Pasheva usb_kill_urb(port->interrupt_in_urb);
659b9a44bc1SElina Pasheva }
660b9a44bc1SElina Pasheva
sierra_submit_rx_urbs(struct usb_serial_port * port,gfp_t mem_flags)661b9a44bc1SElina Pasheva static int sierra_submit_rx_urbs(struct usb_serial_port *port, gfp_t mem_flags)
662b9a44bc1SElina Pasheva {
663b9a44bc1SElina Pasheva int ok_cnt;
664b9a44bc1SElina Pasheva int err = -EINVAL;
665b9a44bc1SElina Pasheva int i;
666b9a44bc1SElina Pasheva struct urb *urb;
667b9a44bc1SElina Pasheva struct sierra_port_private *portdata = usb_get_serial_port_data(port);
668b9a44bc1SElina Pasheva
669b9a44bc1SElina Pasheva ok_cnt = 0;
6703a2b808eSElina Pasheva for (i = 0; i < portdata->num_in_urbs; i++) {
671b9a44bc1SElina Pasheva urb = portdata->in_urbs[i];
672b9a44bc1SElina Pasheva if (!urb)
673b9a44bc1SElina Pasheva continue;
674b9a44bc1SElina Pasheva err = usb_submit_urb(urb, mem_flags);
675b9a44bc1SElina Pasheva if (err) {
676b9a44bc1SElina Pasheva dev_err(&port->dev, "%s: submit urb failed: %d\n",
677b9a44bc1SElina Pasheva __func__, err);
678b9a44bc1SElina Pasheva } else {
679b9a44bc1SElina Pasheva ok_cnt++;
680b9a44bc1SElina Pasheva }
681b9a44bc1SElina Pasheva }
682b9a44bc1SElina Pasheva
683b9a44bc1SElina Pasheva if (ok_cnt && port->interrupt_in_urb) {
684b9a44bc1SElina Pasheva err = usb_submit_urb(port->interrupt_in_urb, mem_flags);
685b9a44bc1SElina Pasheva if (err) {
686b9a44bc1SElina Pasheva dev_err(&port->dev, "%s: submit intr urb failed: %d\n",
687b9a44bc1SElina Pasheva __func__, err);
688b9a44bc1SElina Pasheva }
689b9a44bc1SElina Pasheva }
690b9a44bc1SElina Pasheva
691b9a44bc1SElina Pasheva if (ok_cnt > 0) /* at least one rx urb submitted */
692b9a44bc1SElina Pasheva return 0;
693b9a44bc1SElina Pasheva else
694b9a44bc1SElina Pasheva return err;
695b9a44bc1SElina Pasheva }
696b9a44bc1SElina Pasheva
sierra_setup_urb(struct usb_serial * serial,int endpoint,int dir,void * ctx,int len,gfp_t mem_flags,usb_complete_t callback)697b9a44bc1SElina Pasheva static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint,
698b9a44bc1SElina Pasheva int dir, void *ctx, int len,
699b9a44bc1SElina Pasheva gfp_t mem_flags,
700b9a44bc1SElina Pasheva usb_complete_t callback)
701b9a44bc1SElina Pasheva {
702b9a44bc1SElina Pasheva struct urb *urb;
703b9a44bc1SElina Pasheva u8 *buf;
704b9a44bc1SElina Pasheva
705b9a44bc1SElina Pasheva urb = usb_alloc_urb(0, mem_flags);
70610c642d0SJohan Hovold if (!urb)
707b9a44bc1SElina Pasheva return NULL;
708b9a44bc1SElina Pasheva
709b9a44bc1SElina Pasheva buf = kmalloc(len, mem_flags);
710b9a44bc1SElina Pasheva if (buf) {
711b9a44bc1SElina Pasheva /* Fill URB using supplied data */
712b9a44bc1SElina Pasheva usb_fill_bulk_urb(urb, serial->dev,
713b9a44bc1SElina Pasheva usb_sndbulkpipe(serial->dev, endpoint) | dir,
714b9a44bc1SElina Pasheva buf, len, callback, ctx);
715b9a44bc1SElina Pasheva
716b9a44bc1SElina Pasheva dev_dbg(&serial->dev->dev, "%s %c u : %p d:%p\n", __func__,
717b9a44bc1SElina Pasheva dir == USB_DIR_IN ? 'i' : 'o', urb, buf);
718b9a44bc1SElina Pasheva } else {
719b9a44bc1SElina Pasheva sierra_release_urb(urb);
720b9a44bc1SElina Pasheva urb = NULL;
721b9a44bc1SElina Pasheva }
722b9a44bc1SElina Pasheva
723b9a44bc1SElina Pasheva return urb;
724b9a44bc1SElina Pasheva }
725b9a44bc1SElina Pasheva
sierra_close(struct usb_serial_port * port)726b9a44bc1SElina Pasheva static void sierra_close(struct usb_serial_port *port)
727b9a44bc1SElina Pasheva {
728b9a44bc1SElina Pasheva int i;
729b9a44bc1SElina Pasheva struct usb_serial *serial = port->serial;
730b9a44bc1SElina Pasheva struct sierra_port_private *portdata;
7317c80782eSJohan Hovold struct sierra_intf_private *intfdata = usb_get_serial_data(serial);
732014333f7SJohan Hovold struct urb *urb;
733e6929a90SOliver Neukum
734b9a44bc1SElina Pasheva portdata = usb_get_serial_port_data(port);
735b9a44bc1SElina Pasheva
736c2e45d70SJohan Hovold /*
737c2e45d70SJohan Hovold * Need to take susp_lock to make sure port is not already being
738*688ee1d1SJohan Hovold * resumed, but no need to hold it due to the tty-port initialized
739*688ee1d1SJohan Hovold * flag.
740c2e45d70SJohan Hovold */
741e6929a90SOliver Neukum spin_lock_irq(&intfdata->susp_lock);
74280cc0fcbSJohan Hovold if (--intfdata->open_ports == 0)
74380cc0fcbSJohan Hovold serial->interface->needs_remote_wakeup = 0;
744e6929a90SOliver Neukum spin_unlock_irq(&intfdata->susp_lock);
745e6929a90SOliver Neukum
746014333f7SJohan Hovold for (;;) {
747014333f7SJohan Hovold urb = usb_get_from_anchor(&portdata->delayed);
748014333f7SJohan Hovold if (!urb)
749014333f7SJohan Hovold break;
750014333f7SJohan Hovold kfree(urb->transfer_buffer);
751014333f7SJohan Hovold usb_free_urb(urb);
752014333f7SJohan Hovold usb_autopm_put_interface_async(serial->interface);
753e6087001SJohn Ogness spin_lock_irq(&portdata->lock);
754014333f7SJohan Hovold portdata->outstanding_urbs--;
755e6087001SJohn Ogness spin_unlock_irq(&portdata->lock);
756014333f7SJohan Hovold }
757014333f7SJohan Hovold
758b9a44bc1SElina Pasheva sierra_stop_rx_urbs(port);
759c9d838a8SJohan Hovold usb_kill_anchored_urbs(&portdata->active);
760c9d838a8SJohan Hovold
7613a2b808eSElina Pasheva for (i = 0; i < portdata->num_in_urbs; i++) {
762b9a44bc1SElina Pasheva sierra_release_urb(portdata->in_urbs[i]);
763b9a44bc1SElina Pasheva portdata->in_urbs[i] = NULL;
764b9a44bc1SElina Pasheva }
7650287d5c5SJohan Hovold
7660287d5c5SJohan Hovold usb_autopm_get_interface_no_resume(serial->interface);
767b9a44bc1SElina Pasheva }
768b9a44bc1SElina Pasheva
sierra_open(struct tty_struct * tty,struct usb_serial_port * port)769a509a7e4SAlan Cox static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port)
770033a3fb9SKevin Lloyd {
771033a3fb9SKevin Lloyd struct sierra_port_private *portdata;
772033a3fb9SKevin Lloyd struct usb_serial *serial = port->serial;
7737c80782eSJohan Hovold struct sierra_intf_private *intfdata = usb_get_serial_data(serial);
7749e85c5f6SGreg Kroah-Hartman int i;
775b9a44bc1SElina Pasheva int err;
776b9a44bc1SElina Pasheva int endpoint;
777033a3fb9SKevin Lloyd struct urb *urb;
778033a3fb9SKevin Lloyd
779033a3fb9SKevin Lloyd portdata = usb_get_serial_port_data(port);
780033a3fb9SKevin Lloyd
781b9a44bc1SElina Pasheva endpoint = port->bulk_in_endpointAddress;
7823a2b808eSElina Pasheva for (i = 0; i < portdata->num_in_urbs; i++) {
783b9a44bc1SElina Pasheva urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port,
784b9a44bc1SElina Pasheva IN_BUFLEN, GFP_KERNEL,
785b9a44bc1SElina Pasheva sierra_indat_callback);
786b9a44bc1SElina Pasheva portdata->in_urbs[i] = urb;
787033a3fb9SKevin Lloyd }
788b9a44bc1SElina Pasheva /* clear halt condition */
789b9a44bc1SElina Pasheva usb_clear_halt(serial->dev,
790b9a44bc1SElina Pasheva usb_sndbulkpipe(serial->dev, endpoint) | USB_DIR_IN);
791033a3fb9SKevin Lloyd
792b9a44bc1SElina Pasheva err = sierra_submit_rx_urbs(port, GFP_KERNEL);
793353fe198SJohan Hovold if (err)
794353fe198SJohan Hovold goto err_submit;
795353fe198SJohan Hovold
796e6929a90SOliver Neukum spin_lock_irq(&intfdata->susp_lock);
79780cc0fcbSJohan Hovold if (++intfdata->open_ports == 1)
79880cc0fcbSJohan Hovold serial->interface->needs_remote_wakeup = 1;
799e6929a90SOliver Neukum spin_unlock_irq(&intfdata->susp_lock);
800e6929a90SOliver Neukum usb_autopm_put_interface(serial->interface);
801e6929a90SOliver Neukum
8029e85c5f6SGreg Kroah-Hartman return 0;
803353fe198SJohan Hovold
804353fe198SJohan Hovold err_submit:
805353fe198SJohan Hovold sierra_stop_rx_urbs(port);
806353fe198SJohan Hovold
807353fe198SJohan Hovold for (i = 0; i < portdata->num_in_urbs; i++) {
808353fe198SJohan Hovold sierra_release_urb(portdata->in_urbs[i]);
809353fe198SJohan Hovold portdata->in_urbs[i] = NULL;
810353fe198SJohan Hovold }
811353fe198SJohan Hovold
812353fe198SJohan Hovold return err;
813033a3fb9SKevin Lloyd }
814033a3fb9SKevin Lloyd
815b9a44bc1SElina Pasheva
sierra_dtr_rts(struct usb_serial_port * port,int on)816335f8514SAlan Cox static void sierra_dtr_rts(struct usb_serial_port *port, int on)
817335f8514SAlan Cox {
818335f8514SAlan Cox struct sierra_port_private *portdata;
819335f8514SAlan Cox
820335f8514SAlan Cox portdata = usb_get_serial_port_data(port);
821335f8514SAlan Cox portdata->rts_state = on;
822335f8514SAlan Cox portdata->dtr_state = on;
823335f8514SAlan Cox
824335f8514SAlan Cox sierra_send_setup(port);
825335f8514SAlan Cox }
826335f8514SAlan Cox
sierra_startup(struct usb_serial * serial)827033a3fb9SKevin Lloyd static int sierra_startup(struct usb_serial *serial)
828033a3fb9SKevin Lloyd {
829084817d7SJohan Hovold struct sierra_intf_private *intfdata;
830033a3fb9SKevin Lloyd
831084817d7SJohan Hovold intfdata = kzalloc(sizeof(*intfdata), GFP_KERNEL);
832084817d7SJohan Hovold if (!intfdata)
833084817d7SJohan Hovold return -ENOMEM;
834084817d7SJohan Hovold
835084817d7SJohan Hovold spin_lock_init(&intfdata->susp_lock);
836084817d7SJohan Hovold
837084817d7SJohan Hovold usb_set_serial_data(serial, intfdata);
838084817d7SJohan Hovold
839112225b1SKevin Lloyd /* Set Device mode to D0 */
840112225b1SKevin Lloyd sierra_set_power_state(serial->dev, 0x0000);
841112225b1SKevin Lloyd
842228426edSKevin Lloyd /* Check NMEA and set */
843228426edSKevin Lloyd if (nmea)
844228426edSKevin Lloyd sierra_vsc_set_nmea(serial->dev, 1);
845228426edSKevin Lloyd
846f525c05bSJohan Hovold return 0;
847033a3fb9SKevin Lloyd }
848f525c05bSJohan Hovold
sierra_release(struct usb_serial * serial)849f525c05bSJohan Hovold static void sierra_release(struct usb_serial *serial)
850f525c05bSJohan Hovold {
851f525c05bSJohan Hovold struct sierra_intf_private *intfdata;
852f525c05bSJohan Hovold
853f525c05bSJohan Hovold intfdata = usb_get_serial_data(serial);
854f525c05bSJohan Hovold kfree(intfdata);
855f525c05bSJohan Hovold }
856f525c05bSJohan Hovold
sierra_port_probe(struct usb_serial_port * port)857f525c05bSJohan Hovold static int sierra_port_probe(struct usb_serial_port *port)
858f525c05bSJohan Hovold {
859f525c05bSJohan Hovold struct usb_serial *serial = port->serial;
860f525c05bSJohan Hovold struct sierra_port_private *portdata;
861e0439cd9SJohan Hovold const struct sierra_iface_list *himemory_list;
862f525c05bSJohan Hovold u8 ifnum;
863f525c05bSJohan Hovold
864f525c05bSJohan Hovold portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
865f525c05bSJohan Hovold if (!portdata)
866f525c05bSJohan Hovold return -ENOMEM;
867f525c05bSJohan Hovold
86817c23274SGreg Kroah-Hartman spin_lock_init(&portdata->lock);
869e6929a90SOliver Neukum init_usb_anchor(&portdata->active);
870e6929a90SOliver Neukum init_usb_anchor(&portdata->delayed);
871f525c05bSJohan Hovold
8723a2b808eSElina Pasheva /* Assume low memory requirements */
8733a2b808eSElina Pasheva portdata->num_out_urbs = N_OUT_URB;
8743a2b808eSElina Pasheva portdata->num_in_urbs = N_IN_URB;
8753a2b808eSElina Pasheva
8763a2b808eSElina Pasheva /* Determine actual memory requirements */
8773a2b808eSElina Pasheva if (serial->num_ports == 1) {
8783a2b808eSElina Pasheva /* Get interface number for composite device */
87916620b48SJohan Hovold ifnum = sierra_interface_num(serial);
880e0439cd9SJohan Hovold himemory_list = &typeB_interface_list;
881f525c05bSJohan Hovold } else {
882f525c05bSJohan Hovold /* This is really the usb-serial port number of the interface
883f525c05bSJohan Hovold * rather than the interface number.
884f525c05bSJohan Hovold */
8851143832eSGreg Kroah-Hartman ifnum = port->port_number;
886e0439cd9SJohan Hovold himemory_list = &typeA_interface_list;
887f525c05bSJohan Hovold }
888f525c05bSJohan Hovold
889e0439cd9SJohan Hovold if (is_listed(ifnum, himemory_list)) {
8903a2b808eSElina Pasheva portdata->num_out_urbs = N_OUT_URB_HM;
8913a2b808eSElina Pasheva portdata->num_in_urbs = N_IN_URB_HM;
8923a2b808eSElina Pasheva }
893f525c05bSJohan Hovold
894f525c05bSJohan Hovold dev_dbg(&port->dev,
8953a2b808eSElina Pasheva "Memory usage (urbs) interface #%d, in=%d, out=%d\n",
8963a2b808eSElina Pasheva ifnum, portdata->num_in_urbs, portdata->num_out_urbs);
897f525c05bSJohan Hovold
898033a3fb9SKevin Lloyd usb_set_serial_port_data(port, portdata);
899033a3fb9SKevin Lloyd
90017c23274SGreg Kroah-Hartman return 0;
901033a3fb9SKevin Lloyd }
902033a3fb9SKevin Lloyd
sierra_port_remove(struct usb_serial_port * port)903c5d1448fSUwe Kleine-König static void sierra_port_remove(struct usb_serial_port *port)
904033a3fb9SKevin Lloyd {
905033a3fb9SKevin Lloyd struct sierra_port_private *portdata;
906033a3fb9SKevin Lloyd
907033a3fb9SKevin Lloyd portdata = usb_get_serial_port_data(port);
9088452727dSJohan Hovold usb_set_serial_port_data(port, NULL);
9099e85c5f6SGreg Kroah-Hartman kfree(portdata);
910033a3fb9SKevin Lloyd }
911033a3fb9SKevin Lloyd
912cd604513SAndrew Morton #ifdef CONFIG_PM
stop_read_write_urbs(struct usb_serial * serial)913e6929a90SOliver Neukum static void stop_read_write_urbs(struct usb_serial *serial)
914e6929a90SOliver Neukum {
915b64dc0a5SElina Pasheva int i;
916e6929a90SOliver Neukum struct usb_serial_port *port;
917e6929a90SOliver Neukum struct sierra_port_private *portdata;
918e6929a90SOliver Neukum
919e6929a90SOliver Neukum /* Stop reading/writing urbs */
920e6929a90SOliver Neukum for (i = 0; i < serial->num_ports; ++i) {
921e6929a90SOliver Neukum port = serial->port[i];
922e6929a90SOliver Neukum portdata = usb_get_serial_port_data(port);
9238452727dSJohan Hovold if (!portdata)
9248452727dSJohan Hovold continue;
925b64dc0a5SElina Pasheva sierra_stop_rx_urbs(port);
926e6929a90SOliver Neukum usb_kill_anchored_urbs(&portdata->active);
927e6929a90SOliver Neukum }
928e6929a90SOliver Neukum }
929e6929a90SOliver Neukum
sierra_suspend(struct usb_serial * serial,pm_message_t message)930e6929a90SOliver Neukum static int sierra_suspend(struct usb_serial *serial, pm_message_t message)
931e6929a90SOliver Neukum {
9327d8825beSJohan Hovold struct sierra_intf_private *intfdata = usb_get_serial_data(serial);
933e6929a90SOliver Neukum
934e6929a90SOliver Neukum spin_lock_irq(&intfdata->susp_lock);
9357d8825beSJohan Hovold if (PMSG_IS_AUTO(message)) {
9367d8825beSJohan Hovold if (intfdata->in_flight) {
937e6929a90SOliver Neukum spin_unlock_irq(&intfdata->susp_lock);
938e6929a90SOliver Neukum return -EBUSY;
9397d8825beSJohan Hovold }
9407d8825beSJohan Hovold }
941e6929a90SOliver Neukum intfdata->suspended = 1;
942e6929a90SOliver Neukum spin_unlock_irq(&intfdata->susp_lock);
9437d8825beSJohan Hovold
944e6929a90SOliver Neukum stop_read_write_urbs(serial);
945e6929a90SOliver Neukum
946e6929a90SOliver Neukum return 0;
947e6929a90SOliver Neukum }
948e6929a90SOliver Neukum
94971c149b9SJohan Hovold /* Caller must hold susp_lock. */
sierra_submit_delayed_urbs(struct usb_serial_port * port)95071c149b9SJohan Hovold static int sierra_submit_delayed_urbs(struct usb_serial_port *port)
95171c149b9SJohan Hovold {
95271c149b9SJohan Hovold struct sierra_port_private *portdata = usb_get_serial_port_data(port);
95371c149b9SJohan Hovold struct sierra_intf_private *intfdata;
95471c149b9SJohan Hovold struct urb *urb;
95571c149b9SJohan Hovold int ec = 0;
95671c149b9SJohan Hovold int err;
95771c149b9SJohan Hovold
95871c149b9SJohan Hovold intfdata = usb_get_serial_data(port->serial);
95971c149b9SJohan Hovold
96071c149b9SJohan Hovold for (;;) {
96171c149b9SJohan Hovold urb = usb_get_from_anchor(&portdata->delayed);
96271c149b9SJohan Hovold if (!urb)
96371c149b9SJohan Hovold break;
96471c149b9SJohan Hovold
96571c149b9SJohan Hovold usb_anchor_urb(urb, &portdata->active);
96671c149b9SJohan Hovold intfdata->in_flight++;
96771c149b9SJohan Hovold err = usb_submit_urb(urb, GFP_ATOMIC);
96871c149b9SJohan Hovold if (err) {
96971c149b9SJohan Hovold dev_err(&port->dev, "%s - submit urb failed: %d",
97071c149b9SJohan Hovold __func__, err);
97171c149b9SJohan Hovold ec++;
97271c149b9SJohan Hovold intfdata->in_flight--;
97371c149b9SJohan Hovold usb_unanchor_urb(urb);
97471c149b9SJohan Hovold kfree(urb->transfer_buffer);
97571c149b9SJohan Hovold usb_free_urb(urb);
97671c149b9SJohan Hovold
97771c149b9SJohan Hovold spin_lock(&portdata->lock);
97871c149b9SJohan Hovold portdata->outstanding_urbs--;
97971c149b9SJohan Hovold spin_unlock(&portdata->lock);
98071c149b9SJohan Hovold }
98171c149b9SJohan Hovold }
98271c149b9SJohan Hovold
98371c149b9SJohan Hovold if (ec)
98471c149b9SJohan Hovold return -EIO;
98571c149b9SJohan Hovold
98671c149b9SJohan Hovold return 0;
98771c149b9SJohan Hovold }
98871c149b9SJohan Hovold
sierra_resume(struct usb_serial * serial)989e6929a90SOliver Neukum static int sierra_resume(struct usb_serial *serial)
990e6929a90SOliver Neukum {
991e6929a90SOliver Neukum struct usb_serial_port *port;
9927c80782eSJohan Hovold struct sierra_intf_private *intfdata = usb_get_serial_data(serial);
993e6929a90SOliver Neukum int ec = 0;
994e6929a90SOliver Neukum int i, err;
995e6929a90SOliver Neukum
996e6929a90SOliver Neukum spin_lock_irq(&intfdata->susp_lock);
997e6929a90SOliver Neukum for (i = 0; i < serial->num_ports; i++) {
998e6929a90SOliver Neukum port = serial->port[i];
999e6929a90SOliver Neukum
1000d41861caSPeter Hurley if (!tty_port_initialized(&port->port))
10018452727dSJohan Hovold continue;
10028452727dSJohan Hovold
100371c149b9SJohan Hovold err = sierra_submit_delayed_urbs(port);
100471c149b9SJohan Hovold if (err)
1005f4a2d499SJohan Hovold ec++;
1006e6929a90SOliver Neukum
1007e6929a90SOliver Neukum err = sierra_submit_rx_urbs(port, GFP_ATOMIC);
1008e6929a90SOliver Neukum if (err)
1009e6929a90SOliver Neukum ec++;
1010e6929a90SOliver Neukum }
1011e6929a90SOliver Neukum intfdata->suspended = 0;
1012e6929a90SOliver Neukum spin_unlock_irq(&intfdata->susp_lock);
1013e6929a90SOliver Neukum
1014e6929a90SOliver Neukum return ec ? -EIO : 0;
1015e6929a90SOliver Neukum }
10167650cd96SElina Pasheva
1017cd604513SAndrew Morton #else
1018cd604513SAndrew Morton #define sierra_suspend NULL
1019cd604513SAndrew Morton #define sierra_resume NULL
1020cd604513SAndrew Morton #endif
1021e6929a90SOliver Neukum
1022228426edSKevin Lloyd static struct usb_serial_driver sierra_device = {
1023964ee1deSGreg Kroah-Hartman .driver = {
1024964ee1deSGreg Kroah-Hartman .owner = THIS_MODULE,
10254e0fee82SKevin Lloyd .name = "sierra",
1026964ee1deSGreg Kroah-Hartman },
1027228426edSKevin Lloyd .description = "Sierra USB modem",
1028228426edSKevin Lloyd .id_table = id_table,
1029228426edSKevin Lloyd .calc_num_ports = sierra_calc_num_ports,
1030228426edSKevin Lloyd .probe = sierra_probe,
1031964ee1deSGreg Kroah-Hartman .open = sierra_open,
1032964ee1deSGreg Kroah-Hartman .close = sierra_close,
1033335f8514SAlan Cox .dtr_rts = sierra_dtr_rts,
1034964ee1deSGreg Kroah-Hartman .write = sierra_write,
1035964ee1deSGreg Kroah-Hartman .write_room = sierra_write_room,
103693670599SJohan Hovold .chars_in_buffer = sierra_chars_in_buffer,
1037964ee1deSGreg Kroah-Hartman .tiocmget = sierra_tiocmget,
1038964ee1deSGreg Kroah-Hartman .tiocmset = sierra_tiocmset,
1039964ee1deSGreg Kroah-Hartman .attach = sierra_startup,
10407bae0a07SAlan Stern .release = sierra_release,
1041f525c05bSJohan Hovold .port_probe = sierra_port_probe,
1042f525c05bSJohan Hovold .port_remove = sierra_port_remove,
1043e6929a90SOliver Neukum .suspend = sierra_suspend,
1044e6929a90SOliver Neukum .resume = sierra_resume,
1045964ee1deSGreg Kroah-Hartman .read_int_callback = sierra_instat_callback,
1046964ee1deSGreg Kroah-Hartman };
1047964ee1deSGreg Kroah-Hartman
1048d860322fSAlan Stern static struct usb_serial_driver * const serial_drivers[] = {
1049d860322fSAlan Stern &sierra_device, NULL
1050d860322fSAlan Stern };
1051d860322fSAlan Stern
105268e24113SGreg Kroah-Hartman module_usb_serial_driver(serial_drivers, id_table);
1053964ee1deSGreg Kroah-Hartman
1054033a3fb9SKevin Lloyd MODULE_AUTHOR(DRIVER_AUTHOR);
1055033a3fb9SKevin Lloyd MODULE_DESCRIPTION(DRIVER_DESC);
1056627cfa89SJohan Hovold MODULE_LICENSE("GPL v2");
1057033a3fb9SKevin Lloyd
1058a65ab973SUtkarsh Verma module_param(nmea, bool, 0644);
1059228426edSKevin Lloyd MODULE_PARM_DESC(nmea, "NMEA streaming");
1060