1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun USB Driver layer for GSM modems
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de>
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org>
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun History: see the git log.
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun This driver exists because the "normal" serial driver doesn't work too well
14*4882a593Smuzhiyun with GSM modems. Issues:
15*4882a593Smuzhiyun - data loss -- one single Receive URB is not nearly enough
16*4882a593Smuzhiyun - controlling the baud rate doesn't make sense
17*4882a593Smuzhiyun */
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
20*4882a593Smuzhiyun #define DRIVER_DESC "USB Driver for GSM modems"
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #include <linux/kernel.h>
23*4882a593Smuzhiyun #include <linux/jiffies.h>
24*4882a593Smuzhiyun #include <linux/errno.h>
25*4882a593Smuzhiyun #include <linux/slab.h>
26*4882a593Smuzhiyun #include <linux/tty.h>
27*4882a593Smuzhiyun #include <linux/tty_flip.h>
28*4882a593Smuzhiyun #include <linux/module.h>
29*4882a593Smuzhiyun #include <linux/bitops.h>
30*4882a593Smuzhiyun #include <linux/uaccess.h>
31*4882a593Smuzhiyun #include <linux/usb.h>
32*4882a593Smuzhiyun #include <linux/usb/serial.h>
33*4882a593Smuzhiyun #include <linux/serial.h>
34*4882a593Smuzhiyun #include "usb-wwan.h"
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun /*
37*4882a593Smuzhiyun * Generate DTR/RTS signals on the port using the SET_CONTROL_LINE_STATE request
38*4882a593Smuzhiyun * in CDC ACM.
39*4882a593Smuzhiyun */
usb_wwan_send_setup(struct usb_serial_port * port)40*4882a593Smuzhiyun static int usb_wwan_send_setup(struct usb_serial_port *port)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun struct usb_serial *serial = port->serial;
43*4882a593Smuzhiyun struct usb_wwan_port_private *portdata;
44*4882a593Smuzhiyun int val = 0;
45*4882a593Smuzhiyun int ifnum;
46*4882a593Smuzhiyun int res;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun portdata = usb_get_serial_port_data(port);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun if (portdata->dtr_state)
51*4882a593Smuzhiyun val |= 0x01;
52*4882a593Smuzhiyun if (portdata->rts_state)
53*4882a593Smuzhiyun val |= 0x02;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun res = usb_autopm_get_interface(serial->interface);
58*4882a593Smuzhiyun if (res)
59*4882a593Smuzhiyun return res;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
62*4882a593Smuzhiyun 0x22, 0x21, val, ifnum, NULL, 0,
63*4882a593Smuzhiyun USB_CTRL_SET_TIMEOUT);
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun usb_autopm_put_interface(port->serial->interface);
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun return res;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
usb_wwan_dtr_rts(struct usb_serial_port * port,int on)70*4882a593Smuzhiyun void usb_wwan_dtr_rts(struct usb_serial_port *port, int on)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun struct usb_wwan_port_private *portdata;
73*4882a593Smuzhiyun struct usb_wwan_intf_private *intfdata;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun intfdata = usb_get_serial_data(port->serial);
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun if (!intfdata->use_send_setup)
78*4882a593Smuzhiyun return;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun portdata = usb_get_serial_port_data(port);
81*4882a593Smuzhiyun /* FIXME: locking */
82*4882a593Smuzhiyun portdata->rts_state = on;
83*4882a593Smuzhiyun portdata->dtr_state = on;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun usb_wwan_send_setup(port);
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun EXPORT_SYMBOL(usb_wwan_dtr_rts);
88*4882a593Smuzhiyun
usb_wwan_tiocmget(struct tty_struct * tty)89*4882a593Smuzhiyun int usb_wwan_tiocmget(struct tty_struct *tty)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun struct usb_serial_port *port = tty->driver_data;
92*4882a593Smuzhiyun unsigned int value;
93*4882a593Smuzhiyun struct usb_wwan_port_private *portdata;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun portdata = usb_get_serial_port_data(port);
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
98*4882a593Smuzhiyun ((portdata->dtr_state) ? TIOCM_DTR : 0) |
99*4882a593Smuzhiyun ((portdata->cts_state) ? TIOCM_CTS : 0) |
100*4882a593Smuzhiyun ((portdata->dsr_state) ? TIOCM_DSR : 0) |
101*4882a593Smuzhiyun ((portdata->dcd_state) ? TIOCM_CAR : 0) |
102*4882a593Smuzhiyun ((portdata->ri_state) ? TIOCM_RNG : 0);
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun return value;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun EXPORT_SYMBOL(usb_wwan_tiocmget);
107*4882a593Smuzhiyun
usb_wwan_tiocmset(struct tty_struct * tty,unsigned int set,unsigned int clear)108*4882a593Smuzhiyun int usb_wwan_tiocmset(struct tty_struct *tty,
109*4882a593Smuzhiyun unsigned int set, unsigned int clear)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun struct usb_serial_port *port = tty->driver_data;
112*4882a593Smuzhiyun struct usb_wwan_port_private *portdata;
113*4882a593Smuzhiyun struct usb_wwan_intf_private *intfdata;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun portdata = usb_get_serial_port_data(port);
116*4882a593Smuzhiyun intfdata = usb_get_serial_data(port->serial);
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun if (!intfdata->use_send_setup)
119*4882a593Smuzhiyun return -EINVAL;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /* FIXME: what locks portdata fields ? */
122*4882a593Smuzhiyun if (set & TIOCM_RTS)
123*4882a593Smuzhiyun portdata->rts_state = 1;
124*4882a593Smuzhiyun if (set & TIOCM_DTR)
125*4882a593Smuzhiyun portdata->dtr_state = 1;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun if (clear & TIOCM_RTS)
128*4882a593Smuzhiyun portdata->rts_state = 0;
129*4882a593Smuzhiyun if (clear & TIOCM_DTR)
130*4882a593Smuzhiyun portdata->dtr_state = 0;
131*4882a593Smuzhiyun return usb_wwan_send_setup(port);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun EXPORT_SYMBOL(usb_wwan_tiocmset);
134*4882a593Smuzhiyun
usb_wwan_get_serial_info(struct tty_struct * tty,struct serial_struct * ss)135*4882a593Smuzhiyun int usb_wwan_get_serial_info(struct tty_struct *tty,
136*4882a593Smuzhiyun struct serial_struct *ss)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun struct usb_serial_port *port = tty->driver_data;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun ss->line = port->minor;
141*4882a593Smuzhiyun ss->port = port->port_number;
142*4882a593Smuzhiyun ss->baud_base = tty_get_baud_rate(port->port.tty);
143*4882a593Smuzhiyun ss->close_delay = jiffies_to_msecs(port->port.close_delay) / 10;
144*4882a593Smuzhiyun ss->closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
145*4882a593Smuzhiyun ASYNC_CLOSING_WAIT_NONE :
146*4882a593Smuzhiyun jiffies_to_msecs(port->port.closing_wait) / 10;
147*4882a593Smuzhiyun return 0;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun EXPORT_SYMBOL(usb_wwan_get_serial_info);
150*4882a593Smuzhiyun
usb_wwan_set_serial_info(struct tty_struct * tty,struct serial_struct * ss)151*4882a593Smuzhiyun int usb_wwan_set_serial_info(struct tty_struct *tty,
152*4882a593Smuzhiyun struct serial_struct *ss)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun struct usb_serial_port *port = tty->driver_data;
155*4882a593Smuzhiyun unsigned int closing_wait, close_delay;
156*4882a593Smuzhiyun int retval = 0;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun close_delay = msecs_to_jiffies(ss->close_delay * 10);
159*4882a593Smuzhiyun closing_wait = ss->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
160*4882a593Smuzhiyun ASYNC_CLOSING_WAIT_NONE :
161*4882a593Smuzhiyun msecs_to_jiffies(ss->closing_wait * 10);
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun mutex_lock(&port->port.mutex);
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun if (!capable(CAP_SYS_ADMIN)) {
166*4882a593Smuzhiyun if ((close_delay != port->port.close_delay) ||
167*4882a593Smuzhiyun (closing_wait != port->port.closing_wait))
168*4882a593Smuzhiyun retval = -EPERM;
169*4882a593Smuzhiyun else
170*4882a593Smuzhiyun retval = -EOPNOTSUPP;
171*4882a593Smuzhiyun } else {
172*4882a593Smuzhiyun port->port.close_delay = close_delay;
173*4882a593Smuzhiyun port->port.closing_wait = closing_wait;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun mutex_unlock(&port->port.mutex);
177*4882a593Smuzhiyun return retval;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun EXPORT_SYMBOL(usb_wwan_set_serial_info);
180*4882a593Smuzhiyun
usb_wwan_write(struct tty_struct * tty,struct usb_serial_port * port,const unsigned char * buf,int count)181*4882a593Smuzhiyun int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
182*4882a593Smuzhiyun const unsigned char *buf, int count)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun struct usb_wwan_port_private *portdata;
185*4882a593Smuzhiyun struct usb_wwan_intf_private *intfdata;
186*4882a593Smuzhiyun int i;
187*4882a593Smuzhiyun int left, todo;
188*4882a593Smuzhiyun struct urb *this_urb = NULL; /* spurious */
189*4882a593Smuzhiyun int err;
190*4882a593Smuzhiyun unsigned long flags;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun portdata = usb_get_serial_port_data(port);
193*4882a593Smuzhiyun intfdata = usb_get_serial_data(port->serial);
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun dev_dbg(&port->dev, "%s: write (%d chars)\n", __func__, count);
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun i = 0;
198*4882a593Smuzhiyun left = count;
199*4882a593Smuzhiyun for (i = 0; left > 0 && i < N_OUT_URB; i++) {
200*4882a593Smuzhiyun todo = left;
201*4882a593Smuzhiyun if (todo > OUT_BUFLEN)
202*4882a593Smuzhiyun todo = OUT_BUFLEN;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun this_urb = portdata->out_urbs[i];
205*4882a593Smuzhiyun if (test_and_set_bit(i, &portdata->out_busy)) {
206*4882a593Smuzhiyun if (time_before(jiffies,
207*4882a593Smuzhiyun portdata->tx_start_time[i] + 10 * HZ))
208*4882a593Smuzhiyun continue;
209*4882a593Smuzhiyun usb_unlink_urb(this_urb);
210*4882a593Smuzhiyun continue;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun dev_dbg(&port->dev, "%s: endpoint %d buf %d\n", __func__,
213*4882a593Smuzhiyun usb_pipeendpoint(this_urb->pipe), i);
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun err = usb_autopm_get_interface_async(port->serial->interface);
216*4882a593Smuzhiyun if (err < 0) {
217*4882a593Smuzhiyun clear_bit(i, &portdata->out_busy);
218*4882a593Smuzhiyun break;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun /* send the data */
222*4882a593Smuzhiyun memcpy(this_urb->transfer_buffer, buf, todo);
223*4882a593Smuzhiyun this_urb->transfer_buffer_length = todo;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun spin_lock_irqsave(&intfdata->susp_lock, flags);
226*4882a593Smuzhiyun if (intfdata->suspended) {
227*4882a593Smuzhiyun usb_anchor_urb(this_urb, &portdata->delayed);
228*4882a593Smuzhiyun spin_unlock_irqrestore(&intfdata->susp_lock, flags);
229*4882a593Smuzhiyun } else {
230*4882a593Smuzhiyun intfdata->in_flight++;
231*4882a593Smuzhiyun spin_unlock_irqrestore(&intfdata->susp_lock, flags);
232*4882a593Smuzhiyun err = usb_submit_urb(this_urb, GFP_ATOMIC);
233*4882a593Smuzhiyun if (err) {
234*4882a593Smuzhiyun dev_err(&port->dev,
235*4882a593Smuzhiyun "%s: submit urb %d failed: %d\n",
236*4882a593Smuzhiyun __func__, i, err);
237*4882a593Smuzhiyun clear_bit(i, &portdata->out_busy);
238*4882a593Smuzhiyun spin_lock_irqsave(&intfdata->susp_lock, flags);
239*4882a593Smuzhiyun intfdata->in_flight--;
240*4882a593Smuzhiyun spin_unlock_irqrestore(&intfdata->susp_lock,
241*4882a593Smuzhiyun flags);
242*4882a593Smuzhiyun usb_autopm_put_interface_async(port->serial->interface);
243*4882a593Smuzhiyun break;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun portdata->tx_start_time[i] = jiffies;
248*4882a593Smuzhiyun buf += todo;
249*4882a593Smuzhiyun left -= todo;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun count -= left;
253*4882a593Smuzhiyun dev_dbg(&port->dev, "%s: wrote (did %d)\n", __func__, count);
254*4882a593Smuzhiyun return count;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun EXPORT_SYMBOL(usb_wwan_write);
257*4882a593Smuzhiyun
usb_wwan_indat_callback(struct urb * urb)258*4882a593Smuzhiyun static void usb_wwan_indat_callback(struct urb *urb)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun int err;
261*4882a593Smuzhiyun int endpoint;
262*4882a593Smuzhiyun struct usb_serial_port *port;
263*4882a593Smuzhiyun struct device *dev;
264*4882a593Smuzhiyun unsigned char *data = urb->transfer_buffer;
265*4882a593Smuzhiyun int status = urb->status;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun endpoint = usb_pipeendpoint(urb->pipe);
268*4882a593Smuzhiyun port = urb->context;
269*4882a593Smuzhiyun dev = &port->dev;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun if (status) {
272*4882a593Smuzhiyun dev_dbg(dev, "%s: nonzero status: %d on endpoint %02x.\n",
273*4882a593Smuzhiyun __func__, status, endpoint);
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun /* don't resubmit on fatal errors */
276*4882a593Smuzhiyun if (status == -ESHUTDOWN || status == -ENOENT)
277*4882a593Smuzhiyun return;
278*4882a593Smuzhiyun } else {
279*4882a593Smuzhiyun if (urb->actual_length) {
280*4882a593Smuzhiyun tty_insert_flip_string(&port->port, data,
281*4882a593Smuzhiyun urb->actual_length);
282*4882a593Smuzhiyun tty_flip_buffer_push(&port->port);
283*4882a593Smuzhiyun } else
284*4882a593Smuzhiyun dev_dbg(dev, "%s: empty read urb received\n", __func__);
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun /* Resubmit urb so we continue receiving */
287*4882a593Smuzhiyun err = usb_submit_urb(urb, GFP_ATOMIC);
288*4882a593Smuzhiyun if (err) {
289*4882a593Smuzhiyun if (err != -EPERM && err != -ENODEV) {
290*4882a593Smuzhiyun dev_err(dev, "%s: resubmit read urb failed. (%d)\n",
291*4882a593Smuzhiyun __func__, err);
292*4882a593Smuzhiyun /* busy also in error unless we are killed */
293*4882a593Smuzhiyun usb_mark_last_busy(port->serial->dev);
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun } else {
296*4882a593Smuzhiyun usb_mark_last_busy(port->serial->dev);
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
usb_wwan_outdat_callback(struct urb * urb)300*4882a593Smuzhiyun static void usb_wwan_outdat_callback(struct urb *urb)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun struct usb_serial_port *port;
303*4882a593Smuzhiyun struct usb_wwan_port_private *portdata;
304*4882a593Smuzhiyun struct usb_wwan_intf_private *intfdata;
305*4882a593Smuzhiyun unsigned long flags;
306*4882a593Smuzhiyun int i;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun port = urb->context;
309*4882a593Smuzhiyun intfdata = usb_get_serial_data(port->serial);
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun usb_serial_port_softint(port);
312*4882a593Smuzhiyun usb_autopm_put_interface_async(port->serial->interface);
313*4882a593Smuzhiyun portdata = usb_get_serial_port_data(port);
314*4882a593Smuzhiyun spin_lock_irqsave(&intfdata->susp_lock, flags);
315*4882a593Smuzhiyun intfdata->in_flight--;
316*4882a593Smuzhiyun spin_unlock_irqrestore(&intfdata->susp_lock, flags);
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun for (i = 0; i < N_OUT_URB; ++i) {
319*4882a593Smuzhiyun if (portdata->out_urbs[i] == urb) {
320*4882a593Smuzhiyun smp_mb__before_atomic();
321*4882a593Smuzhiyun clear_bit(i, &portdata->out_busy);
322*4882a593Smuzhiyun break;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
usb_wwan_write_room(struct tty_struct * tty)327*4882a593Smuzhiyun int usb_wwan_write_room(struct tty_struct *tty)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun struct usb_serial_port *port = tty->driver_data;
330*4882a593Smuzhiyun struct usb_wwan_port_private *portdata;
331*4882a593Smuzhiyun int i;
332*4882a593Smuzhiyun int data_len = 0;
333*4882a593Smuzhiyun struct urb *this_urb;
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun portdata = usb_get_serial_port_data(port);
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun for (i = 0; i < N_OUT_URB; i++) {
338*4882a593Smuzhiyun this_urb = portdata->out_urbs[i];
339*4882a593Smuzhiyun if (this_urb && !test_bit(i, &portdata->out_busy))
340*4882a593Smuzhiyun data_len += OUT_BUFLEN;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun dev_dbg(&port->dev, "%s: %d\n", __func__, data_len);
344*4882a593Smuzhiyun return data_len;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun EXPORT_SYMBOL(usb_wwan_write_room);
347*4882a593Smuzhiyun
usb_wwan_chars_in_buffer(struct tty_struct * tty)348*4882a593Smuzhiyun int usb_wwan_chars_in_buffer(struct tty_struct *tty)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun struct usb_serial_port *port = tty->driver_data;
351*4882a593Smuzhiyun struct usb_wwan_port_private *portdata;
352*4882a593Smuzhiyun int i;
353*4882a593Smuzhiyun int data_len = 0;
354*4882a593Smuzhiyun struct urb *this_urb;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun portdata = usb_get_serial_port_data(port);
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun for (i = 0; i < N_OUT_URB; i++) {
359*4882a593Smuzhiyun this_urb = portdata->out_urbs[i];
360*4882a593Smuzhiyun /* FIXME: This locking is insufficient as this_urb may
361*4882a593Smuzhiyun go unused during the test */
362*4882a593Smuzhiyun if (this_urb && test_bit(i, &portdata->out_busy))
363*4882a593Smuzhiyun data_len += this_urb->transfer_buffer_length;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun dev_dbg(&port->dev, "%s: %d\n", __func__, data_len);
366*4882a593Smuzhiyun return data_len;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun EXPORT_SYMBOL(usb_wwan_chars_in_buffer);
369*4882a593Smuzhiyun
usb_wwan_open(struct tty_struct * tty,struct usb_serial_port * port)370*4882a593Smuzhiyun int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun struct usb_wwan_port_private *portdata;
373*4882a593Smuzhiyun struct usb_wwan_intf_private *intfdata;
374*4882a593Smuzhiyun struct usb_serial *serial = port->serial;
375*4882a593Smuzhiyun int i, err;
376*4882a593Smuzhiyun struct urb *urb;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun portdata = usb_get_serial_port_data(port);
379*4882a593Smuzhiyun intfdata = usb_get_serial_data(serial);
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun if (port->interrupt_in_urb) {
382*4882a593Smuzhiyun err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
383*4882a593Smuzhiyun if (err) {
384*4882a593Smuzhiyun dev_err(&port->dev, "%s: submit int urb failed: %d\n",
385*4882a593Smuzhiyun __func__, err);
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun /* Start reading from the IN endpoint */
390*4882a593Smuzhiyun for (i = 0; i < N_IN_URB; i++) {
391*4882a593Smuzhiyun urb = portdata->in_urbs[i];
392*4882a593Smuzhiyun if (!urb)
393*4882a593Smuzhiyun continue;
394*4882a593Smuzhiyun err = usb_submit_urb(urb, GFP_KERNEL);
395*4882a593Smuzhiyun if (err) {
396*4882a593Smuzhiyun dev_err(&port->dev,
397*4882a593Smuzhiyun "%s: submit read urb %d failed: %d\n",
398*4882a593Smuzhiyun __func__, i, err);
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun spin_lock_irq(&intfdata->susp_lock);
403*4882a593Smuzhiyun if (++intfdata->open_ports == 1)
404*4882a593Smuzhiyun serial->interface->needs_remote_wakeup = 1;
405*4882a593Smuzhiyun spin_unlock_irq(&intfdata->susp_lock);
406*4882a593Smuzhiyun /* this balances a get in the generic USB serial code */
407*4882a593Smuzhiyun usb_autopm_put_interface(serial->interface);
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun return 0;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun EXPORT_SYMBOL(usb_wwan_open);
412*4882a593Smuzhiyun
unbusy_queued_urb(struct urb * urb,struct usb_wwan_port_private * portdata)413*4882a593Smuzhiyun static void unbusy_queued_urb(struct urb *urb,
414*4882a593Smuzhiyun struct usb_wwan_port_private *portdata)
415*4882a593Smuzhiyun {
416*4882a593Smuzhiyun int i;
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun for (i = 0; i < N_OUT_URB; i++) {
419*4882a593Smuzhiyun if (urb == portdata->out_urbs[i]) {
420*4882a593Smuzhiyun clear_bit(i, &portdata->out_busy);
421*4882a593Smuzhiyun break;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
usb_wwan_close(struct usb_serial_port * port)426*4882a593Smuzhiyun void usb_wwan_close(struct usb_serial_port *port)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun int i;
429*4882a593Smuzhiyun struct usb_serial *serial = port->serial;
430*4882a593Smuzhiyun struct usb_wwan_port_private *portdata;
431*4882a593Smuzhiyun struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
432*4882a593Smuzhiyun struct urb *urb;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun portdata = usb_get_serial_port_data(port);
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun /*
437*4882a593Smuzhiyun * Need to take susp_lock to make sure port is not already being
438*4882a593Smuzhiyun * resumed, but no need to hold it due to the tty-port initialized
439*4882a593Smuzhiyun * flag.
440*4882a593Smuzhiyun */
441*4882a593Smuzhiyun spin_lock_irq(&intfdata->susp_lock);
442*4882a593Smuzhiyun if (--intfdata->open_ports == 0)
443*4882a593Smuzhiyun serial->interface->needs_remote_wakeup = 0;
444*4882a593Smuzhiyun spin_unlock_irq(&intfdata->susp_lock);
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun for (;;) {
447*4882a593Smuzhiyun urb = usb_get_from_anchor(&portdata->delayed);
448*4882a593Smuzhiyun if (!urb)
449*4882a593Smuzhiyun break;
450*4882a593Smuzhiyun unbusy_queued_urb(urb, portdata);
451*4882a593Smuzhiyun usb_autopm_put_interface_async(serial->interface);
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun for (i = 0; i < N_IN_URB; i++)
455*4882a593Smuzhiyun usb_kill_urb(portdata->in_urbs[i]);
456*4882a593Smuzhiyun for (i = 0; i < N_OUT_URB; i++)
457*4882a593Smuzhiyun usb_kill_urb(portdata->out_urbs[i]);
458*4882a593Smuzhiyun usb_kill_urb(port->interrupt_in_urb);
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun usb_autopm_get_interface_no_resume(serial->interface);
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun EXPORT_SYMBOL(usb_wwan_close);
463*4882a593Smuzhiyun
usb_wwan_setup_urb(struct usb_serial_port * port,int endpoint,int dir,void * ctx,char * buf,int len,void (* callback)(struct urb *))464*4882a593Smuzhiyun static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port,
465*4882a593Smuzhiyun int endpoint,
466*4882a593Smuzhiyun int dir, void *ctx, char *buf, int len,
467*4882a593Smuzhiyun void (*callback) (struct urb *))
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun struct usb_serial *serial = port->serial;
470*4882a593Smuzhiyun struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
471*4882a593Smuzhiyun struct urb *urb;
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
474*4882a593Smuzhiyun if (!urb)
475*4882a593Smuzhiyun return NULL;
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun usb_fill_bulk_urb(urb, serial->dev,
478*4882a593Smuzhiyun usb_sndbulkpipe(serial->dev, endpoint) | dir,
479*4882a593Smuzhiyun buf, len, callback, ctx);
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun if (intfdata->use_zlp && dir == USB_DIR_OUT)
482*4882a593Smuzhiyun urb->transfer_flags |= URB_ZERO_PACKET;
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun if (dir == USB_DIR_OUT) {
485*4882a593Smuzhiyun struct usb_device_descriptor *desc = &serial->dev->descriptor;
486*4882a593Smuzhiyun if (desc->idVendor == cpu_to_le16(0x2C7C))
487*4882a593Smuzhiyun urb->transfer_flags |= URB_ZERO_PACKET;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun return urb;
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun
usb_wwan_port_probe(struct usb_serial_port * port)493*4882a593Smuzhiyun int usb_wwan_port_probe(struct usb_serial_port *port)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun struct usb_wwan_port_private *portdata;
496*4882a593Smuzhiyun struct urb *urb;
497*4882a593Smuzhiyun u8 *buffer;
498*4882a593Smuzhiyun int i;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun if (!port->bulk_in_size || !port->bulk_out_size)
501*4882a593Smuzhiyun return -ENODEV;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
504*4882a593Smuzhiyun if (!portdata)
505*4882a593Smuzhiyun return -ENOMEM;
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun init_usb_anchor(&portdata->delayed);
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun for (i = 0; i < N_IN_URB; i++) {
510*4882a593Smuzhiyun buffer = (u8 *)__get_free_page(GFP_KERNEL);
511*4882a593Smuzhiyun if (!buffer)
512*4882a593Smuzhiyun goto bail_out_error;
513*4882a593Smuzhiyun portdata->in_buffer[i] = buffer;
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun urb = usb_wwan_setup_urb(port, port->bulk_in_endpointAddress,
516*4882a593Smuzhiyun USB_DIR_IN, port,
517*4882a593Smuzhiyun buffer, IN_BUFLEN,
518*4882a593Smuzhiyun usb_wwan_indat_callback);
519*4882a593Smuzhiyun portdata->in_urbs[i] = urb;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun for (i = 0; i < N_OUT_URB; i++) {
523*4882a593Smuzhiyun buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL);
524*4882a593Smuzhiyun if (!buffer)
525*4882a593Smuzhiyun goto bail_out_error2;
526*4882a593Smuzhiyun portdata->out_buffer[i] = buffer;
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun urb = usb_wwan_setup_urb(port, port->bulk_out_endpointAddress,
529*4882a593Smuzhiyun USB_DIR_OUT, port,
530*4882a593Smuzhiyun buffer, OUT_BUFLEN,
531*4882a593Smuzhiyun usb_wwan_outdat_callback);
532*4882a593Smuzhiyun portdata->out_urbs[i] = urb;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun usb_set_serial_port_data(port, portdata);
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun return 0;
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun bail_out_error2:
540*4882a593Smuzhiyun for (i = 0; i < N_OUT_URB; i++) {
541*4882a593Smuzhiyun usb_free_urb(portdata->out_urbs[i]);
542*4882a593Smuzhiyun kfree(portdata->out_buffer[i]);
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun bail_out_error:
545*4882a593Smuzhiyun for (i = 0; i < N_IN_URB; i++) {
546*4882a593Smuzhiyun usb_free_urb(portdata->in_urbs[i]);
547*4882a593Smuzhiyun free_page((unsigned long)portdata->in_buffer[i]);
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun kfree(portdata);
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun return -ENOMEM;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(usb_wwan_port_probe);
554*4882a593Smuzhiyun
usb_wwan_port_remove(struct usb_serial_port * port)555*4882a593Smuzhiyun int usb_wwan_port_remove(struct usb_serial_port *port)
556*4882a593Smuzhiyun {
557*4882a593Smuzhiyun int i;
558*4882a593Smuzhiyun struct usb_wwan_port_private *portdata;
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun portdata = usb_get_serial_port_data(port);
561*4882a593Smuzhiyun usb_set_serial_port_data(port, NULL);
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun for (i = 0; i < N_IN_URB; i++) {
564*4882a593Smuzhiyun usb_free_urb(portdata->in_urbs[i]);
565*4882a593Smuzhiyun free_page((unsigned long)portdata->in_buffer[i]);
566*4882a593Smuzhiyun }
567*4882a593Smuzhiyun for (i = 0; i < N_OUT_URB; i++) {
568*4882a593Smuzhiyun usb_free_urb(portdata->out_urbs[i]);
569*4882a593Smuzhiyun kfree(portdata->out_buffer[i]);
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun kfree(portdata);
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun return 0;
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun EXPORT_SYMBOL(usb_wwan_port_remove);
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun #ifdef CONFIG_PM
stop_urbs(struct usb_serial * serial)579*4882a593Smuzhiyun static void stop_urbs(struct usb_serial *serial)
580*4882a593Smuzhiyun {
581*4882a593Smuzhiyun int i, j;
582*4882a593Smuzhiyun struct usb_serial_port *port;
583*4882a593Smuzhiyun struct usb_wwan_port_private *portdata;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun for (i = 0; i < serial->num_ports; ++i) {
586*4882a593Smuzhiyun port = serial->port[i];
587*4882a593Smuzhiyun portdata = usb_get_serial_port_data(port);
588*4882a593Smuzhiyun if (!portdata)
589*4882a593Smuzhiyun continue;
590*4882a593Smuzhiyun for (j = 0; j < N_IN_URB; j++)
591*4882a593Smuzhiyun usb_kill_urb(portdata->in_urbs[j]);
592*4882a593Smuzhiyun for (j = 0; j < N_OUT_URB; j++)
593*4882a593Smuzhiyun usb_kill_urb(portdata->out_urbs[j]);
594*4882a593Smuzhiyun usb_kill_urb(port->interrupt_in_urb);
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun
usb_wwan_suspend(struct usb_serial * serial,pm_message_t message)598*4882a593Smuzhiyun int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun spin_lock_irq(&intfdata->susp_lock);
603*4882a593Smuzhiyun if (PMSG_IS_AUTO(message)) {
604*4882a593Smuzhiyun if (intfdata->in_flight) {
605*4882a593Smuzhiyun spin_unlock_irq(&intfdata->susp_lock);
606*4882a593Smuzhiyun return -EBUSY;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun intfdata->suspended = 1;
610*4882a593Smuzhiyun spin_unlock_irq(&intfdata->susp_lock);
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun stop_urbs(serial);
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun return 0;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun EXPORT_SYMBOL(usb_wwan_suspend);
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun /* Caller must hold susp_lock. */
usb_wwan_submit_delayed_urbs(struct usb_serial_port * port)619*4882a593Smuzhiyun static int usb_wwan_submit_delayed_urbs(struct usb_serial_port *port)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun struct usb_serial *serial = port->serial;
622*4882a593Smuzhiyun struct usb_wwan_intf_private *data = usb_get_serial_data(serial);
623*4882a593Smuzhiyun struct usb_wwan_port_private *portdata;
624*4882a593Smuzhiyun struct urb *urb;
625*4882a593Smuzhiyun int err_count = 0;
626*4882a593Smuzhiyun int err;
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun portdata = usb_get_serial_port_data(port);
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun for (;;) {
631*4882a593Smuzhiyun urb = usb_get_from_anchor(&portdata->delayed);
632*4882a593Smuzhiyun if (!urb)
633*4882a593Smuzhiyun break;
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun err = usb_submit_urb(urb, GFP_ATOMIC);
636*4882a593Smuzhiyun if (err) {
637*4882a593Smuzhiyun dev_err(&port->dev, "%s: submit urb failed: %d\n",
638*4882a593Smuzhiyun __func__, err);
639*4882a593Smuzhiyun err_count++;
640*4882a593Smuzhiyun unbusy_queued_urb(urb, portdata);
641*4882a593Smuzhiyun usb_autopm_put_interface_async(serial->interface);
642*4882a593Smuzhiyun continue;
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun data->in_flight++;
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun if (err_count)
648*4882a593Smuzhiyun return -EIO;
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun return 0;
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun
usb_wwan_resume(struct usb_serial * serial)653*4882a593Smuzhiyun int usb_wwan_resume(struct usb_serial *serial)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun int i, j;
656*4882a593Smuzhiyun struct usb_serial_port *port;
657*4882a593Smuzhiyun struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
658*4882a593Smuzhiyun struct usb_wwan_port_private *portdata;
659*4882a593Smuzhiyun struct urb *urb;
660*4882a593Smuzhiyun int err;
661*4882a593Smuzhiyun int err_count = 0;
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun spin_lock_irq(&intfdata->susp_lock);
664*4882a593Smuzhiyun for (i = 0; i < serial->num_ports; i++) {
665*4882a593Smuzhiyun port = serial->port[i];
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun if (!tty_port_initialized(&port->port))
668*4882a593Smuzhiyun continue;
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun portdata = usb_get_serial_port_data(port);
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun if (port->interrupt_in_urb) {
673*4882a593Smuzhiyun err = usb_submit_urb(port->interrupt_in_urb,
674*4882a593Smuzhiyun GFP_ATOMIC);
675*4882a593Smuzhiyun if (err) {
676*4882a593Smuzhiyun dev_err(&port->dev,
677*4882a593Smuzhiyun "%s: submit int urb failed: %d\n",
678*4882a593Smuzhiyun __func__, err);
679*4882a593Smuzhiyun err_count++;
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun err = usb_wwan_submit_delayed_urbs(port);
684*4882a593Smuzhiyun if (err)
685*4882a593Smuzhiyun err_count++;
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun for (j = 0; j < N_IN_URB; j++) {
688*4882a593Smuzhiyun urb = portdata->in_urbs[j];
689*4882a593Smuzhiyun err = usb_submit_urb(urb, GFP_ATOMIC);
690*4882a593Smuzhiyun if (err < 0) {
691*4882a593Smuzhiyun dev_err(&port->dev,
692*4882a593Smuzhiyun "%s: submit read urb %d failed: %d\n",
693*4882a593Smuzhiyun __func__, i, err);
694*4882a593Smuzhiyun err_count++;
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun intfdata->suspended = 0;
699*4882a593Smuzhiyun spin_unlock_irq(&intfdata->susp_lock);
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun if (err_count)
702*4882a593Smuzhiyun return -EIO;
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun return 0;
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun EXPORT_SYMBOL(usb_wwan_resume);
707*4882a593Smuzhiyun #endif
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun MODULE_AUTHOR(DRIVER_AUTHOR);
710*4882a593Smuzhiyun MODULE_DESCRIPTION(DRIVER_DESC);
711*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
712