diff options
author | bart.hartgers@gmail.com <bart.hartgers@gmail.com> | 2009-10-28 05:43:29 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-12-11 14:55:21 -0500 |
commit | 62d826c8ddafb0a55eb6c5255779ddb782dc5507 (patch) | |
tree | be3837a935c0731bd98af0fcc4b3c66d35b49140 | |
parent | 546b742968e7789c60efe0eec71896c45eeb6893 (diff) |
USB: ark3116: Callbacks for interrupt and bulk read
Signed-off-by: Bart Hartgers <bart.hartgers@gmail.com>
Cc: Mike McCormack <mikem@ring3k.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/serial/ark3116.c | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index a7c26990ec67..067daf4db646 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c | |||
@@ -605,6 +605,198 @@ static void ark3116_break_ctl(struct tty_struct *tty, int break_state) | |||
605 | mutex_unlock(&priv->hw_lock); | 605 | mutex_unlock(&priv->hw_lock); |
606 | } | 606 | } |
607 | 607 | ||
608 | static void ark3116_update_msr(struct usb_serial_port *port, __u8 msr) | ||
609 | { | ||
610 | struct ark3116_private *priv = usb_get_serial_port_data(port); | ||
611 | unsigned long flags; | ||
612 | |||
613 | spin_lock_irqsave(&priv->status_lock, flags); | ||
614 | priv->msr = msr; | ||
615 | spin_unlock_irqrestore(&priv->status_lock, flags); | ||
616 | |||
617 | if (msr & UART_MSR_ANY_DELTA) { | ||
618 | /* update input line counters */ | ||
619 | if (msr & UART_MSR_DCTS) | ||
620 | priv->icount.cts++; | ||
621 | if (msr & UART_MSR_DDSR) | ||
622 | priv->icount.dsr++; | ||
623 | if (msr & UART_MSR_DDCD) | ||
624 | priv->icount.dcd++; | ||
625 | if (msr & UART_MSR_TERI) | ||
626 | priv->icount.rng++; | ||
627 | wake_up_interruptible(&priv->delta_msr_wait); | ||
628 | } | ||
629 | } | ||
630 | |||
631 | static void ark3116_update_lsr(struct usb_serial_port *port, __u8 lsr) | ||
632 | { | ||
633 | struct ark3116_private *priv = usb_get_serial_port_data(port); | ||
634 | unsigned long flags; | ||
635 | |||
636 | spin_lock_irqsave(&priv->status_lock, flags); | ||
637 | /* combine bits */ | ||
638 | priv->lsr |= lsr; | ||
639 | spin_unlock_irqrestore(&priv->status_lock, flags); | ||
640 | |||
641 | if (lsr&UART_LSR_BRK_ERROR_BITS) { | ||
642 | if (lsr & UART_LSR_BI) | ||
643 | priv->icount.brk++; | ||
644 | if (lsr & UART_LSR_FE) | ||
645 | priv->icount.frame++; | ||
646 | if (lsr & UART_LSR_PE) | ||
647 | priv->icount.parity++; | ||
648 | if (lsr & UART_LSR_OE) | ||
649 | priv->icount.overrun++; | ||
650 | } | ||
651 | } | ||
652 | |||
653 | static void ark3116_read_int_callback(struct urb *urb) | ||
654 | { | ||
655 | struct usb_serial_port *port = urb->context; | ||
656 | int status = urb->status; | ||
657 | const __u8 *data = urb->transfer_buffer; | ||
658 | int result; | ||
659 | |||
660 | switch (status) { | ||
661 | case -ECONNRESET: | ||
662 | case -ENOENT: | ||
663 | case -ESHUTDOWN: | ||
664 | /* this urb is terminated, clean up */ | ||
665 | dbg("%s - urb shutting down with status: %d", | ||
666 | __func__, status); | ||
667 | return; | ||
668 | default: | ||
669 | dbg("%s - nonzero urb status received: %d", | ||
670 | __func__, status); | ||
671 | break; | ||
672 | case 0: /* success */ | ||
673 | /* discovered this by trail and error... */ | ||
674 | if ((urb->actual_length == 4) && (data[0] == 0xe8)) { | ||
675 | const __u8 id = data[1]&UART_IIR_ID; | ||
676 | dbg("%s: iir=%02x", __func__, data[1]); | ||
677 | if (id == UART_IIR_MSI) { | ||
678 | dbg("%s: msr=%02x", __func__, data[3]); | ||
679 | ark3116_update_msr(port, data[3]); | ||
680 | break; | ||
681 | } else if (id == UART_IIR_RLSI) { | ||
682 | dbg("%s: lsr=%02x", __func__, data[2]); | ||
683 | ark3116_update_lsr(port, data[2]); | ||
684 | break; | ||
685 | } | ||
686 | } | ||
687 | /* | ||
688 | * Not sure what this data meant... | ||
689 | */ | ||
690 | usb_serial_debug_data(debug, &port->dev, | ||
691 | __func__, | ||
692 | urb->actual_length, | ||
693 | urb->transfer_buffer); | ||
694 | break; | ||
695 | } | ||
696 | |||
697 | result = usb_submit_urb(urb, GFP_ATOMIC); | ||
698 | if (result) | ||
699 | dev_err(&urb->dev->dev, | ||
700 | "%s - Error %d submitting interrupt urb\n", | ||
701 | __func__, result); | ||
702 | } | ||
703 | |||
704 | |||
705 | /* Data comes in via the bulk (data) URB, erors/interrupts via the int URB. | ||
706 | * This means that we cannot be sure which data byte has an associated error | ||
707 | * condition, so we report an error for all data in the next bulk read. | ||
708 | * | ||
709 | * Actually, there might even be a window between the bulk data leaving the | ||
710 | * ark and reading/resetting the lsr in the read_bulk_callback where an | ||
711 | * interrupt for the next data block could come in. | ||
712 | * Without somekind of ordering on the ark, we would have to report the | ||
713 | * error for the next block of data as well... | ||
714 | * For now, let's pretend this can't happen. | ||
715 | */ | ||
716 | |||
717 | static void send_to_tty(struct tty_struct *tty, | ||
718 | const unsigned char *chars, | ||
719 | size_t size, char flag) | ||
720 | { | ||
721 | if (size == 0) | ||
722 | return; | ||
723 | if (flag == TTY_NORMAL) { | ||
724 | tty_insert_flip_string(tty, chars, size); | ||
725 | } else { | ||
726 | int i; | ||
727 | for (i = 0; i < size; ++i) | ||
728 | tty_insert_flip_char(tty, chars[i], flag); | ||
729 | } | ||
730 | } | ||
731 | |||
732 | static void ark3116_read_bulk_callback(struct urb *urb) | ||
733 | { | ||
734 | struct usb_serial_port *port = urb->context; | ||
735 | struct ark3116_private *priv = usb_get_serial_port_data(port); | ||
736 | const __u8 *data = urb->transfer_buffer; | ||
737 | int status = urb->status; | ||
738 | struct tty_struct *tty; | ||
739 | unsigned long flags; | ||
740 | int result; | ||
741 | char flag; | ||
742 | __u32 lsr; | ||
743 | |||
744 | switch (status) { | ||
745 | case -ECONNRESET: | ||
746 | case -ENOENT: | ||
747 | case -ESHUTDOWN: | ||
748 | /* this urb is terminated, clean up */ | ||
749 | dbg("%s - urb shutting down with status: %d", | ||
750 | __func__, status); | ||
751 | return; | ||
752 | default: | ||
753 | dbg("%s - nonzero urb status received: %d", | ||
754 | __func__, status); | ||
755 | break; | ||
756 | case 0: /* success */ | ||
757 | |||
758 | spin_lock_irqsave(&priv->status_lock, flags); | ||
759 | lsr = priv->lsr; | ||
760 | /* clear error bits */ | ||
761 | priv->lsr &= ~UART_LSR_BRK_ERROR_BITS; | ||
762 | spin_unlock_irqrestore(&priv->status_lock, flags); | ||
763 | |||
764 | if (unlikely(lsr & UART_LSR_BI)) | ||
765 | flag = TTY_BREAK; | ||
766 | else if (unlikely(lsr & UART_LSR_PE)) | ||
767 | flag = TTY_PARITY; | ||
768 | else if (unlikely(lsr & UART_LSR_FE)) | ||
769 | flag = TTY_FRAME; | ||
770 | else | ||
771 | flag = TTY_NORMAL; | ||
772 | |||
773 | tty = tty_port_tty_get(&port->port); | ||
774 | if (tty) { | ||
775 | tty_buffer_request_room(tty, urb->actual_length + 1); | ||
776 | /* overrun is special, not associated with a char */ | ||
777 | if (unlikely(lsr & UART_LSR_OE)) | ||
778 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
779 | send_to_tty(tty, data, urb->actual_length, flag); | ||
780 | tty_flip_buffer_push(tty); | ||
781 | tty_kref_put(tty); | ||
782 | } | ||
783 | |||
784 | /* Throttle the device if requested by tty */ | ||
785 | spin_lock_irqsave(&port->lock, flags); | ||
786 | port->throttled = port->throttle_req; | ||
787 | if (port->throttled) { | ||
788 | spin_unlock_irqrestore(&port->lock, flags); | ||
789 | return; | ||
790 | } else | ||
791 | spin_unlock_irqrestore(&port->lock, flags); | ||
792 | } | ||
793 | /* Continue reading from device */ | ||
794 | result = usb_submit_urb(urb, GFP_ATOMIC); | ||
795 | if (result) | ||
796 | dev_err(&urb->dev->dev, "%s - failed resubmitting" | ||
797 | " read urb, error %d\n", __func__, result); | ||
798 | } | ||
799 | |||
608 | static struct usb_driver ark3116_driver = { | 800 | static struct usb_driver ark3116_driver = { |
609 | .name = "ark3116", | 801 | .name = "ark3116", |
610 | .probe = usb_serial_probe, | 802 | .probe = usb_serial_probe, |
@@ -631,6 +823,8 @@ static struct usb_serial_driver ark3116_device = { | |||
631 | .open = ark3116_open, | 823 | .open = ark3116_open, |
632 | .close = ark3116_close, | 824 | .close = ark3116_close, |
633 | .break_ctl = ark3116_break_ctl, | 825 | .break_ctl = ark3116_break_ctl, |
826 | .read_int_callback = ark3116_read_int_callback, | ||
827 | .read_bulk_callback = ark3116_read_bulk_callback, | ||
634 | }; | 828 | }; |
635 | 829 | ||
636 | static int __init ark3116_init(void) | 830 | static int __init ark3116_init(void) |