aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
authorBill Pemberton <wfp5p@virginia.edu>2010-08-05 17:01:09 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-08-23 23:50:16 -0400
commitf81c83db563334d8377b26ad45585261f604605a (patch)
treec6566eb22756dc8da59da413d3287443dbae5ba0 /drivers/usb/serial
parent556f1a0e9c178193e584209b47cf1cb9f669bd51 (diff)
USB: ssu100: rework logic for TIOCMIWAIT
Rework the logic for TIOCMIWAIT to use wait_event_interruptible. This also adds support for TIOCGICOUNT. Signed-off-by: Bill Pemberton <wfp5p@virginia.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/ssu100.c146
1 files changed, 111 insertions, 35 deletions
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index ad5f9ae4068..e244491b1a0 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -80,6 +80,7 @@ struct ssu100_port_private {
80 u8 shadowMSR; 80 u8 shadowMSR;
81 wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ 81 wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
82 unsigned short max_packet_size; 82 unsigned short max_packet_size;
83 struct async_icount icount;
83}; 84};
84 85
85static void ssu100_release(struct usb_serial *serial) 86static void ssu100_release(struct usb_serial *serial)
@@ -330,11 +331,8 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
330 } 331 }
331 332
332 spin_lock_irqsave(&priv->status_lock, flags); 333 spin_lock_irqsave(&priv->status_lock, flags);
333 priv->shadowLSR = data[0] & (UART_LSR_OE | UART_LSR_PE | 334 priv->shadowLSR = data[0];
334 UART_LSR_FE | UART_LSR_BI); 335 priv->shadowMSR = data[1];
335
336 priv->shadowMSR = data[1] & (UART_MSR_CTS | UART_MSR_DSR |
337 UART_MSR_RI | UART_MSR_DCD);
338 spin_unlock_irqrestore(&priv->status_lock, flags); 336 spin_unlock_irqrestore(&priv->status_lock, flags);
339 337
340 kfree(data); 338 kfree(data);
@@ -379,11 +377,51 @@ static int get_serial_info(struct usb_serial_port *port,
379 return 0; 377 return 0;
380} 378}
381 379
380static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
381{
382 struct ssu100_port_private *priv = usb_get_serial_port_data(port);
383 struct async_icount prev, cur;
384 unsigned long flags;
385
386 spin_lock_irqsave(&priv->status_lock, flags);
387 prev = priv->icount;
388 spin_unlock_irqrestore(&priv->status_lock, flags);
389
390 while (1) {
391 wait_event_interruptible(priv->delta_msr_wait,
392 ((priv->icount.rng != prev.rng) ||
393 (priv->icount.dsr != prev.dsr) ||
394 (priv->icount.dcd != prev.dcd) ||
395 (priv->icount.cts != prev.cts)));
396
397 if (signal_pending(current))
398 return -ERESTARTSYS;
399
400 spin_lock_irqsave(&priv->status_lock, flags);
401 cur = priv->icount;
402 spin_unlock_irqrestore(&priv->status_lock, flags);
403
404 if ((prev.rng == cur.rng) &&
405 (prev.dsr == cur.dsr) &&
406 (prev.dcd == cur.dcd) &&
407 (prev.cts == cur.cts))
408 return -EIO;
409
410 if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) ||
411 (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) ||
412 (arg & TIOCM_CD && (prev.dcd != cur.dcd)) ||
413 (arg & TIOCM_CTS && (prev.cts != cur.cts)))
414 return 0;
415 }
416 return 0;
417}
418
382static int ssu100_ioctl(struct tty_struct *tty, struct file *file, 419static int ssu100_ioctl(struct tty_struct *tty, struct file *file,
383 unsigned int cmd, unsigned long arg) 420 unsigned int cmd, unsigned long arg)
384{ 421{
385 struct usb_serial_port *port = tty->driver_data; 422 struct usb_serial_port *port = tty->driver_data;
386 struct ssu100_port_private *priv = usb_get_serial_port_data(port); 423 struct ssu100_port_private *priv = usb_get_serial_port_data(port);
424 void __user *user_arg = (void __user *)arg;
387 425
388 dbg("%s cmd 0x%04x", __func__, cmd); 426 dbg("%s cmd 0x%04x", __func__, cmd);
389 427
@@ -393,28 +431,28 @@ static int ssu100_ioctl(struct tty_struct *tty, struct file *file,
393 (struct serial_struct __user *) arg); 431 (struct serial_struct __user *) arg);
394 432
395 case TIOCMIWAIT: 433 case TIOCMIWAIT:
396 while (priv != NULL) { 434 return wait_modem_info(port, arg);
397 u8 prevMSR = priv->shadowMSR & SERIAL_MSR_MASK; 435
398 interruptible_sleep_on(&priv->delta_msr_wait); 436 case TIOCGICOUNT:
399 /* see if a signal did it */ 437 {
400 if (signal_pending(current)) 438 struct serial_icounter_struct icount;
401 return -ERESTARTSYS; 439 struct async_icount cnow = priv->icount;
402 else { 440 memset(&icount, 0, sizeof(icount));
403 u8 diff = (priv->shadowMSR & SERIAL_MSR_MASK) ^ prevMSR; 441 icount.cts = cnow.cts;
404 if (!diff) 442 icount.dsr = cnow.dsr;
405 return -EIO; /* no change => error */ 443 icount.rng = cnow.rng;
406 444 icount.dcd = cnow.dcd;
407 /* Return 0 if caller wanted to know about 445 icount.rx = cnow.rx;
408 these bits */ 446 icount.tx = cnow.tx;
409 447 icount.frame = cnow.frame;
410 if (((arg & TIOCM_RNG) && (diff & UART_MSR_RI)) || 448 icount.overrun = cnow.overrun;
411 ((arg & TIOCM_DSR) && (diff & UART_MSR_DSR)) || 449 icount.parity = cnow.parity;
412 ((arg & TIOCM_CD) && (diff & UART_MSR_DCD)) || 450 icount.brk = cnow.brk;
413 ((arg & TIOCM_CTS) && (diff & UART_MSR_CTS))) 451 icount.buf_overrun = cnow.buf_overrun;
414 return 0; 452 if (copy_to_user(user_arg, &icount, sizeof(icount)))
415 } 453 return -EFAULT;
416 }
417 return 0; 454 return 0;
455 }
418 456
419 default: 457 default:
420 break; 458 break;
@@ -541,6 +579,50 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on)
541 mutex_unlock(&port->serial->disc_mutex); 579 mutex_unlock(&port->serial->disc_mutex);
542} 580}
543 581
582static void ssu100_update_msr(struct usb_serial_port *port, u8 msr)
583{
584 struct ssu100_port_private *priv = usb_get_serial_port_data(port);
585 unsigned long flags;
586
587 spin_lock_irqsave(&priv->status_lock, flags);
588 priv->shadowMSR = msr;
589 spin_unlock_irqrestore(&priv->status_lock, flags);
590
591 if (msr & UART_MSR_ANY_DELTA) {
592 /* update input line counters */
593 if (msr & UART_MSR_DCTS)
594 priv->icount.cts++;
595 if (msr & UART_MSR_DDSR)
596 priv->icount.dsr++;
597 if (msr & UART_MSR_DDCD)
598 priv->icount.dcd++;
599 if (msr & UART_MSR_TERI)
600 priv->icount.rng++;
601 wake_up_interruptible(&priv->delta_msr_wait);
602 }
603}
604
605static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr)
606{
607 struct ssu100_port_private *priv = usb_get_serial_port_data(port);
608 unsigned long flags;
609
610 spin_lock_irqsave(&priv->status_lock, flags);
611 priv->shadowLSR = lsr;
612 spin_unlock_irqrestore(&priv->status_lock, flags);
613
614 if (lsr & UART_LSR_BRK_ERROR_BITS) {
615 if (lsr & UART_LSR_BI)
616 priv->icount.brk++;
617 if (lsr & UART_LSR_FE)
618 priv->icount.frame++;
619 if (lsr & UART_LSR_PE)
620 priv->icount.parity++;
621 if (lsr & UART_LSR_OE)
622 priv->icount.overrun++;
623 }
624}
625
544static int ssu100_process_packet(struct tty_struct *tty, 626static int ssu100_process_packet(struct tty_struct *tty,
545 struct usb_serial_port *port, 627 struct usb_serial_port *port,
546 struct ssu100_port_private *priv, 628 struct ssu100_port_private *priv,
@@ -556,15 +638,9 @@ static int ssu100_process_packet(struct tty_struct *tty,
556 (packet[0] == 0x1b) && (packet[1] == 0x1b) && 638 (packet[0] == 0x1b) && (packet[1] == 0x1b) &&
557 ((packet[2] == 0x00) || (packet[2] == 0x01))) { 639 ((packet[2] == 0x00) || (packet[2] == 0x01))) {
558 if (packet[2] == 0x00) 640 if (packet[2] == 0x00)
559 priv->shadowLSR = packet[3] & (UART_LSR_OE | 641 ssu100_update_lsr(port, packet[3]);
560 UART_LSR_PE | 642 if (packet[2] == 0x01)
561 UART_LSR_FE | 643 ssu100_update_msr(port, packet[3]);
562 UART_LSR_BI);
563
564 if (packet[2] == 0x01) {
565 priv->shadowMSR = packet[3];
566 wake_up_interruptible(&priv->delta_msr_wait);
567 }
568 644
569 len -= 4; 645 len -= 4;
570 ch = packet + 4; 646 ch = packet + 4;