aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/usb_wwan.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/usb/serial/usb_wwan.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'drivers/usb/serial/usb_wwan.c')
-rw-r--r--drivers/usb/serial/usb_wwan.c141
1 files changed, 125 insertions, 16 deletions
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 0c70b4a621bb..e4fad5e643d7 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -31,8 +31,10 @@
31#include <linux/tty_flip.h> 31#include <linux/tty_flip.h>
32#include <linux/module.h> 32#include <linux/module.h>
33#include <linux/bitops.h> 33#include <linux/bitops.h>
34#include <linux/uaccess.h>
34#include <linux/usb.h> 35#include <linux/usb.h>
35#include <linux/usb/serial.h> 36#include <linux/usb/serial.h>
37#include <linux/serial.h>
36#include "usb-wwan.h" 38#include "usb-wwan.h"
37 39
38static int debug; 40static int debug;
@@ -77,7 +79,7 @@ void usb_wwan_set_termios(struct tty_struct *tty,
77} 79}
78EXPORT_SYMBOL(usb_wwan_set_termios); 80EXPORT_SYMBOL(usb_wwan_set_termios);
79 81
80int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file) 82int usb_wwan_tiocmget(struct tty_struct *tty)
81{ 83{
82 struct usb_serial_port *port = tty->driver_data; 84 struct usb_serial_port *port = tty->driver_data;
83 unsigned int value; 85 unsigned int value;
@@ -96,7 +98,7 @@ int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file)
96} 98}
97EXPORT_SYMBOL(usb_wwan_tiocmget); 99EXPORT_SYMBOL(usb_wwan_tiocmget);
98 100
99int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file, 101int usb_wwan_tiocmset(struct tty_struct *tty,
100 unsigned int set, unsigned int clear) 102 unsigned int set, unsigned int clear)
101{ 103{
102 struct usb_serial_port *port = tty->driver_data; 104 struct usb_serial_port *port = tty->driver_data;
@@ -123,6 +125,83 @@ int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file,
123} 125}
124EXPORT_SYMBOL(usb_wwan_tiocmset); 126EXPORT_SYMBOL(usb_wwan_tiocmset);
125 127
128static int get_serial_info(struct usb_serial_port *port,
129 struct serial_struct __user *retinfo)
130{
131 struct serial_struct tmp;
132
133 if (!retinfo)
134 return -EFAULT;
135
136 memset(&tmp, 0, sizeof(tmp));
137 tmp.line = port->serial->minor;
138 tmp.port = port->number;
139 tmp.baud_base = tty_get_baud_rate(port->port.tty);
140 tmp.close_delay = port->port.close_delay / 10;
141 tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
142 ASYNC_CLOSING_WAIT_NONE :
143 port->port.closing_wait / 10;
144
145 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
146 return -EFAULT;
147 return 0;
148}
149
150static int set_serial_info(struct usb_serial_port *port,
151 struct serial_struct __user *newinfo)
152{
153 struct serial_struct new_serial;
154 unsigned int closing_wait, close_delay;
155 int retval = 0;
156
157 if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
158 return -EFAULT;
159
160 close_delay = new_serial.close_delay * 10;
161 closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
162 ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
163
164 mutex_lock(&port->port.mutex);
165
166 if (!capable(CAP_SYS_ADMIN)) {
167 if ((close_delay != port->port.close_delay) ||
168 (closing_wait != port->port.closing_wait))
169 retval = -EPERM;
170 else
171 retval = -EOPNOTSUPP;
172 } else {
173 port->port.close_delay = close_delay;
174 port->port.closing_wait = closing_wait;
175 }
176
177 mutex_unlock(&port->port.mutex);
178 return retval;
179}
180
181int usb_wwan_ioctl(struct tty_struct *tty,
182 unsigned int cmd, unsigned long arg)
183{
184 struct usb_serial_port *port = tty->driver_data;
185
186 dbg("%s cmd 0x%04x", __func__, cmd);
187
188 switch (cmd) {
189 case TIOCGSERIAL:
190 return get_serial_info(port,
191 (struct serial_struct __user *) arg);
192 case TIOCSSERIAL:
193 return set_serial_info(port,
194 (struct serial_struct __user *) arg);
195 default:
196 break;
197 }
198
199 dbg("%s arg not supported", __func__);
200
201 return -ENOIOCTLCMD;
202}
203EXPORT_SYMBOL(usb_wwan_ioctl);
204
126/* Write */ 205/* Write */
127int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, 206int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
128 const unsigned char *buf, int count) 207 const unsigned char *buf, int count)
@@ -182,7 +261,8 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
182 intfdata->in_flight--; 261 intfdata->in_flight--;
183 spin_unlock_irqrestore(&intfdata->susp_lock, 262 spin_unlock_irqrestore(&intfdata->susp_lock,
184 flags); 263 flags);
185 continue; 264 usb_autopm_put_interface_async(port->serial->interface);
265 break;
186 } 266 }
187 } 267 }
188 268
@@ -216,25 +296,32 @@ static void usb_wwan_indat_callback(struct urb *urb)
216 __func__, status, endpoint); 296 __func__, status, endpoint);
217 } else { 297 } else {
218 tty = tty_port_tty_get(&port->port); 298 tty = tty_port_tty_get(&port->port);
219 if (urb->actual_length) { 299 if (tty) {
220 tty_insert_flip_string(tty, data, urb->actual_length); 300 if (urb->actual_length) {
221 tty_flip_buffer_push(tty); 301 tty_insert_flip_string(tty, data,
222 } else 302 urb->actual_length);
223 dbg("%s: empty read urb received", __func__); 303 tty_flip_buffer_push(tty);
224 tty_kref_put(tty); 304 } else
305 dbg("%s: empty read urb received", __func__);
306 tty_kref_put(tty);
307 }
225 308
226 /* Resubmit urb so we continue receiving */ 309 /* Resubmit urb so we continue receiving */
227 if (status != -ESHUTDOWN) { 310 if (status != -ESHUTDOWN) {
228 err = usb_submit_urb(urb, GFP_ATOMIC); 311 err = usb_submit_urb(urb, GFP_ATOMIC);
229 if (err && err != -EPERM) 312 if (err) {
230 printk(KERN_ERR "%s: resubmit read urb failed. " 313 if (err != -EPERM) {
231 "(%d)", __func__, err); 314 printk(KERN_ERR "%s: resubmit read urb failed. "
232 else 315 "(%d)", __func__, err);
316 /* busy also in error unless we are killed */
317 usb_mark_last_busy(port->serial->dev);
318 }
319 } else {
233 usb_mark_last_busy(port->serial->dev); 320 usb_mark_last_busy(port->serial->dev);
321 }
234 } 322 }
235 323
236 } 324 }
237 return;
238} 325}
239 326
240static void usb_wwan_outdat_callback(struct urb *urb) 327static void usb_wwan_outdat_callback(struct urb *urb)
@@ -340,6 +427,7 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
340 spin_lock_irq(&intfdata->susp_lock); 427 spin_lock_irq(&intfdata->susp_lock);
341 portdata->opened = 1; 428 portdata->opened = 1;
342 spin_unlock_irq(&intfdata->susp_lock); 429 spin_unlock_irq(&intfdata->susp_lock);
430 /* this balances a get in the generic USB serial code */
343 usb_autopm_put_interface(serial->interface); 431 usb_autopm_put_interface(serial->interface);
344 432
345 return 0; 433 return 0;
@@ -366,7 +454,8 @@ void usb_wwan_close(struct usb_serial_port *port)
366 usb_kill_urb(portdata->in_urbs[i]); 454 usb_kill_urb(portdata->in_urbs[i]);
367 for (i = 0; i < N_OUT_URB; i++) 455 for (i = 0; i < N_OUT_URB; i++)
368 usb_kill_urb(portdata->out_urbs[i]); 456 usb_kill_urb(portdata->out_urbs[i]);
369 usb_autopm_get_interface(serial->interface); 457 /* balancing - important as an error cannot be handled*/
458 usb_autopm_get_interface_no_resume(serial->interface);
370 serial->interface->needs_remote_wakeup = 0; 459 serial->interface->needs_remote_wakeup = 0;
371 } 460 }
372} 461}
@@ -580,6 +669,18 @@ int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
580} 669}
581EXPORT_SYMBOL(usb_wwan_suspend); 670EXPORT_SYMBOL(usb_wwan_suspend);
582 671
672static void unbusy_queued_urb(struct urb *urb, struct usb_wwan_port_private *portdata)
673{
674 int i;
675
676 for (i = 0; i < N_OUT_URB; i++) {
677 if (urb == portdata->out_urbs[i]) {
678 clear_bit(i, &portdata->out_busy);
679 break;
680 }
681 }
682}
683
583static void play_delayed(struct usb_serial_port *port) 684static void play_delayed(struct usb_serial_port *port)
584{ 685{
585 struct usb_wwan_intf_private *data; 686 struct usb_wwan_intf_private *data;
@@ -591,8 +692,16 @@ static void play_delayed(struct usb_serial_port *port)
591 data = port->serial->private; 692 data = port->serial->private;
592 while ((urb = usb_get_from_anchor(&portdata->delayed))) { 693 while ((urb = usb_get_from_anchor(&portdata->delayed))) {
593 err = usb_submit_urb(urb, GFP_ATOMIC); 694 err = usb_submit_urb(urb, GFP_ATOMIC);
594 if (!err) 695 if (!err) {
595 data->in_flight++; 696 data->in_flight++;
697 } else {
698 /* we have to throw away the rest */
699 do {
700 unbusy_queued_urb(urb, portdata);
701 usb_autopm_put_interface_no_suspend(port->serial->interface);
702 } while ((urb = usb_get_from_anchor(&portdata->delayed)));
703 break;
704 }
596 } 705 }
597} 706}
598 707