aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Wessel <jason.wessel@windriver.com>2009-05-11 16:24:09 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-06-16 00:44:45 -0400
commit98fcb5f78165b8a3d93870ad7afd4d9ebbb8b43a (patch)
treeed64298e8b6bf47ba9c57db298e732429f7f669e
parent87c1edd217a6742e48028db6664d7763de0449f6 (diff)
USB: serial: usb_debug,usb_generic_serial: implement sysrq and serial break
The usb_debug driver was modified to implement serial break handling by using a "magic" data packet comprised of the sequence: 0x00 0xff 0x01 0xfe 0x00 0xfe 0x01 0xff When the tty layer requests a serial break the usb_debug driver sends the magic packet. On the receiving side the magic packet is thrown away or a sysrq is activated depending on what kernel .config options have been set. The generic serial driver was modified as well as the usb serial headers to generically implement sysrq processing in the same way the non usb uart based drivers implement the sysrq handling. This will allow other usb serial devices to implement sysrq handling as desired. The new usb serial functions are named similarly and implemented similarly to the uart functions as follows: usb_serial_handle_break <-> uart_handle_break usb_serial_handle_sysrq_char <-> uart_handle_sysrq_char Signed-off-by: Jason Wessel <jason.wessel@windriver.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/serial/generic.c56
-rw-r--r--drivers/usb/serial/usb_debug.c39
-rw-r--r--include/linux/usb/serial.h8
3 files changed, 91 insertions, 12 deletions
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index c919686521ff..9fccc26235a2 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -339,6 +339,7 @@ int usb_serial_generic_write(struct tty_struct *tty,
339 /* no bulk out, so return 0 bytes written */ 339 /* no bulk out, so return 0 bytes written */
340 return 0; 340 return 0;
341} 341}
342EXPORT_SYMBOL_GPL(usb_serial_generic_write);
342 343
343int usb_serial_generic_write_room(struct tty_struct *tty) 344int usb_serial_generic_write_room(struct tty_struct *tty)
344{ 345{
@@ -351,7 +352,9 @@ int usb_serial_generic_write_room(struct tty_struct *tty)
351 spin_lock_irqsave(&port->lock, flags); 352 spin_lock_irqsave(&port->lock, flags);
352 if (serial->type->max_in_flight_urbs) { 353 if (serial->type->max_in_flight_urbs) {
353 if (port->urbs_in_flight < serial->type->max_in_flight_urbs) 354 if (port->urbs_in_flight < serial->type->max_in_flight_urbs)
354 room = port->bulk_out_size; 355 room = port->bulk_out_size *
356 (serial->type->max_in_flight_urbs -
357 port->urbs_in_flight);
355 } else if (serial->num_bulk_out && !(port->write_urb_busy)) { 358 } else if (serial->num_bulk_out && !(port->write_urb_busy)) {
356 room = port->bulk_out_size; 359 room = port->bulk_out_size;
357 } 360 }
@@ -385,7 +388,8 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
385} 388}
386 389
387 390
388static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags) 391void usb_serial_generic_resubmit_read_urb(struct usb_serial_port *port,
392 gfp_t mem_flags)
389{ 393{
390 struct urb *urb = port->read_urb; 394 struct urb *urb = port->read_urb;
391 struct usb_serial *serial = port->serial; 395 struct usb_serial *serial = port->serial;
@@ -406,25 +410,28 @@ static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
406 "%s - failed resubmitting read urb, error %d\n", 410 "%s - failed resubmitting read urb, error %d\n",
407 __func__, result); 411 __func__, result);
408} 412}
413EXPORT_SYMBOL_GPL(usb_serial_generic_resubmit_read_urb);
409 414
410/* Push data to tty layer and resubmit the bulk read URB */ 415/* Push data to tty layer and resubmit the bulk read URB */
411static void flush_and_resubmit_read_urb(struct usb_serial_port *port) 416static void flush_and_resubmit_read_urb(struct usb_serial_port *port)
412{ 417{
413 struct urb *urb = port->read_urb; 418 struct urb *urb = port->read_urb;
414 struct tty_struct *tty = tty_port_tty_get(&port->port); 419 struct tty_struct *tty = tty_port_tty_get(&port->port);
415 int room; 420 char *ch = (char *)urb->transfer_buffer;
421 int i;
422
423 if (!tty)
424 goto done;
416 425
417 /* Push data to tty */ 426 /* Push data to tty */
418 if (tty && urb->actual_length) { 427 for (i = 0; i < urb->actual_length; i++, ch++) {
419 room = tty_buffer_request_room(tty, urb->actual_length); 428 if (!usb_serial_handle_sysrq_char(port, *ch))
420 if (room) { 429 tty_insert_flip_char(tty, *ch, TTY_NORMAL);
421 tty_insert_flip_string(tty, urb->transfer_buffer, room);
422 tty_flip_buffer_push(tty);
423 }
424 } 430 }
431 tty_flip_buffer_push(tty);
425 tty_kref_put(tty); 432 tty_kref_put(tty);
426 433done:
427 resubmit_read_urb(port, GFP_ATOMIC); 434 usb_serial_generic_resubmit_read_urb(port, GFP_ATOMIC);
428} 435}
429 436
430void usb_serial_generic_read_bulk_callback(struct urb *urb) 437void usb_serial_generic_read_bulk_callback(struct urb *urb)
@@ -515,10 +522,35 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
515 522
516 if (was_throttled) { 523 if (was_throttled) {
517 /* Resume reading from device */ 524 /* Resume reading from device */
518 resubmit_read_urb(port, GFP_KERNEL); 525 usb_serial_generic_resubmit_read_urb(port, GFP_KERNEL);
519 } 526 }
520} 527}
521 528
529int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch)
530{
531 if (port->sysrq) {
532 if (ch && time_before(jiffies, port->sysrq)) {
533 handle_sysrq(ch, tty_port_tty_get(&port->port));
534 port->sysrq = 0;
535 return 1;
536 }
537 port->sysrq = 0;
538 }
539 return 0;
540}
541EXPORT_SYMBOL_GPL(usb_serial_handle_sysrq_char);
542
543int usb_serial_handle_break(struct usb_serial_port *port)
544{
545 if (!port->sysrq) {
546 port->sysrq = jiffies + HZ*5;
547 return 1;
548 }
549 port->sysrq = 0;
550 return 0;
551}
552EXPORT_SYMBOL_GPL(usb_serial_handle_break);
553
522void usb_serial_generic_shutdown(struct usb_serial *serial) 554void usb_serial_generic_shutdown(struct usb_serial *serial)
523{ 555{
524 int i; 556 int i;
diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
index a9427a8b8672..614800972dc3 100644
--- a/drivers/usb/serial/usb_debug.c
+++ b/drivers/usb/serial/usb_debug.c
@@ -17,6 +17,17 @@
17 17
18#define URB_DEBUG_MAX_IN_FLIGHT_URBS 4000 18#define URB_DEBUG_MAX_IN_FLIGHT_URBS 4000
19#define USB_DEBUG_MAX_PACKET_SIZE 8 19#define USB_DEBUG_MAX_PACKET_SIZE 8
20#define USB_DEBUG_BRK_SIZE 8
21static char USB_DEBUG_BRK[USB_DEBUG_BRK_SIZE] = {
22 0x00,
23 0xff,
24 0x01,
25 0xfe,
26 0x00,
27 0xfe,
28 0x01,
29 0xff,
30};
20 31
21static struct usb_device_id id_table [] = { 32static struct usb_device_id id_table [] = {
22 { USB_DEVICE(0x0525, 0x127a) }, 33 { USB_DEVICE(0x0525, 0x127a) },
@@ -39,6 +50,32 @@ static int usb_debug_open(struct tty_struct *tty, struct usb_serial_port *port,
39 return usb_serial_generic_open(tty, port, filp); 50 return usb_serial_generic_open(tty, port, filp);
40} 51}
41 52
53/* This HW really does not support a serial break, so one will be
54 * emulated when ever the break state is set to true.
55 */
56static void usb_debug_break_ctl(struct tty_struct *tty, int break_state)
57{
58 struct usb_serial_port *port = tty->driver_data;
59 if (!break_state)
60 return;
61 usb_serial_generic_write(tty, port, USB_DEBUG_BRK, USB_DEBUG_BRK_SIZE);
62}
63
64static void usb_debug_read_bulk_callback(struct urb *urb)
65{
66 struct usb_serial_port *port = urb->context;
67
68 if (urb->actual_length == USB_DEBUG_BRK_SIZE &&
69 memcmp(urb->transfer_buffer, USB_DEBUG_BRK,
70 USB_DEBUG_BRK_SIZE) == 0) {
71 usb_serial_handle_break(port);
72 usb_serial_generic_resubmit_read_urb(port, GFP_ATOMIC);
73 return;
74 }
75
76 usb_serial_generic_read_bulk_callback(urb);
77}
78
42static struct usb_serial_driver debug_device = { 79static struct usb_serial_driver debug_device = {
43 .driver = { 80 .driver = {
44 .owner = THIS_MODULE, 81 .owner = THIS_MODULE,
@@ -48,6 +85,8 @@ static struct usb_serial_driver debug_device = {
48 .num_ports = 1, 85 .num_ports = 1,
49 .open = usb_debug_open, 86 .open = usb_debug_open,
50 .max_in_flight_urbs = URB_DEBUG_MAX_IN_FLIGHT_URBS, 87 .max_in_flight_urbs = URB_DEBUG_MAX_IN_FLIGHT_URBS,
88 .break_ctl = usb_debug_break_ctl,
89 .read_bulk_callback = usb_debug_read_bulk_callback,
51}; 90};
52 91
53static int __init debug_init(void) 92static int __init debug_init(void)
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index e2938fd179e2..e29ebcf3287b 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -15,6 +15,7 @@
15 15
16#include <linux/kref.h> 16#include <linux/kref.h>
17#include <linux/mutex.h> 17#include <linux/mutex.h>
18#include <linux/sysrq.h>
18 19
19#define SERIAL_TTY_MAJOR 188 /* Nice legal number now */ 20#define SERIAL_TTY_MAJOR 188 /* Nice legal number now */
20#define SERIAL_TTY_MINORS 254 /* loads of devices :) */ 21#define SERIAL_TTY_MINORS 254 /* loads of devices :) */
@@ -99,6 +100,7 @@ struct usb_serial_port {
99 char throttled; 100 char throttled;
100 char throttle_req; 101 char throttle_req;
101 char console; 102 char console;
103 unsigned long sysrq; /* sysrq timeout */
102 struct device dev; 104 struct device dev;
103}; 105};
104#define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev) 106#define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev)
@@ -301,6 +303,12 @@ extern void usb_serial_generic_unthrottle(struct tty_struct *tty);
301extern void usb_serial_generic_shutdown(struct usb_serial *serial); 303extern void usb_serial_generic_shutdown(struct usb_serial *serial);
302extern int usb_serial_generic_register(int debug); 304extern int usb_serial_generic_register(int debug);
303extern void usb_serial_generic_deregister(void); 305extern void usb_serial_generic_deregister(void);
306extern void usb_serial_generic_resubmit_read_urb(struct usb_serial_port *port,
307 gfp_t mem_flags);
308extern int usb_serial_handle_sysrq_char(struct usb_serial_port *port,
309 unsigned int ch);
310extern int usb_serial_handle_break(struct usb_serial_port *port);
311
304 312
305extern int usb_serial_bus_register(struct usb_serial_driver *device); 313extern int usb_serial_bus_register(struct usb_serial_driver *device);
306extern void usb_serial_bus_deregister(struct usb_serial_driver *device); 314extern void usb_serial_bus_deregister(struct usb_serial_driver *device);