mirror of
https://github.com/adulau/aha.git
synced 2024-12-30 12:46:17 +00:00
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>
This commit is contained in:
parent
546b742968
commit
62d826c8dd
1 changed files with 194 additions and 0 deletions
|
@ -605,6 +605,198 @@ static void ark3116_break_ctl(struct tty_struct *tty, int break_state)
|
||||||
mutex_unlock(&priv->hw_lock);
|
mutex_unlock(&priv->hw_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ark3116_update_msr(struct usb_serial_port *port, __u8 msr)
|
||||||
|
{
|
||||||
|
struct ark3116_private *priv = usb_get_serial_port_data(port);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&priv->status_lock, flags);
|
||||||
|
priv->msr = msr;
|
||||||
|
spin_unlock_irqrestore(&priv->status_lock, flags);
|
||||||
|
|
||||||
|
if (msr & UART_MSR_ANY_DELTA) {
|
||||||
|
/* update input line counters */
|
||||||
|
if (msr & UART_MSR_DCTS)
|
||||||
|
priv->icount.cts++;
|
||||||
|
if (msr & UART_MSR_DDSR)
|
||||||
|
priv->icount.dsr++;
|
||||||
|
if (msr & UART_MSR_DDCD)
|
||||||
|
priv->icount.dcd++;
|
||||||
|
if (msr & UART_MSR_TERI)
|
||||||
|
priv->icount.rng++;
|
||||||
|
wake_up_interruptible(&priv->delta_msr_wait);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ark3116_update_lsr(struct usb_serial_port *port, __u8 lsr)
|
||||||
|
{
|
||||||
|
struct ark3116_private *priv = usb_get_serial_port_data(port);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&priv->status_lock, flags);
|
||||||
|
/* combine bits */
|
||||||
|
priv->lsr |= lsr;
|
||||||
|
spin_unlock_irqrestore(&priv->status_lock, flags);
|
||||||
|
|
||||||
|
if (lsr&UART_LSR_BRK_ERROR_BITS) {
|
||||||
|
if (lsr & UART_LSR_BI)
|
||||||
|
priv->icount.brk++;
|
||||||
|
if (lsr & UART_LSR_FE)
|
||||||
|
priv->icount.frame++;
|
||||||
|
if (lsr & UART_LSR_PE)
|
||||||
|
priv->icount.parity++;
|
||||||
|
if (lsr & UART_LSR_OE)
|
||||||
|
priv->icount.overrun++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ark3116_read_int_callback(struct urb *urb)
|
||||||
|
{
|
||||||
|
struct usb_serial_port *port = urb->context;
|
||||||
|
int status = urb->status;
|
||||||
|
const __u8 *data = urb->transfer_buffer;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case -ECONNRESET:
|
||||||
|
case -ENOENT:
|
||||||
|
case -ESHUTDOWN:
|
||||||
|
/* this urb is terminated, clean up */
|
||||||
|
dbg("%s - urb shutting down with status: %d",
|
||||||
|
__func__, status);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
dbg("%s - nonzero urb status received: %d",
|
||||||
|
__func__, status);
|
||||||
|
break;
|
||||||
|
case 0: /* success */
|
||||||
|
/* discovered this by trail and error... */
|
||||||
|
if ((urb->actual_length == 4) && (data[0] == 0xe8)) {
|
||||||
|
const __u8 id = data[1]&UART_IIR_ID;
|
||||||
|
dbg("%s: iir=%02x", __func__, data[1]);
|
||||||
|
if (id == UART_IIR_MSI) {
|
||||||
|
dbg("%s: msr=%02x", __func__, data[3]);
|
||||||
|
ark3116_update_msr(port, data[3]);
|
||||||
|
break;
|
||||||
|
} else if (id == UART_IIR_RLSI) {
|
||||||
|
dbg("%s: lsr=%02x", __func__, data[2]);
|
||||||
|
ark3116_update_lsr(port, data[2]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Not sure what this data meant...
|
||||||
|
*/
|
||||||
|
usb_serial_debug_data(debug, &port->dev,
|
||||||
|
__func__,
|
||||||
|
urb->actual_length,
|
||||||
|
urb->transfer_buffer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = usb_submit_urb(urb, GFP_ATOMIC);
|
||||||
|
if (result)
|
||||||
|
dev_err(&urb->dev->dev,
|
||||||
|
"%s - Error %d submitting interrupt urb\n",
|
||||||
|
__func__, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Data comes in via the bulk (data) URB, erors/interrupts via the int URB.
|
||||||
|
* This means that we cannot be sure which data byte has an associated error
|
||||||
|
* condition, so we report an error for all data in the next bulk read.
|
||||||
|
*
|
||||||
|
* Actually, there might even be a window between the bulk data leaving the
|
||||||
|
* ark and reading/resetting the lsr in the read_bulk_callback where an
|
||||||
|
* interrupt for the next data block could come in.
|
||||||
|
* Without somekind of ordering on the ark, we would have to report the
|
||||||
|
* error for the next block of data as well...
|
||||||
|
* For now, let's pretend this can't happen.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void send_to_tty(struct tty_struct *tty,
|
||||||
|
const unsigned char *chars,
|
||||||
|
size_t size, char flag)
|
||||||
|
{
|
||||||
|
if (size == 0)
|
||||||
|
return;
|
||||||
|
if (flag == TTY_NORMAL) {
|
||||||
|
tty_insert_flip_string(tty, chars, size);
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < size; ++i)
|
||||||
|
tty_insert_flip_char(tty, chars[i], flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ark3116_read_bulk_callback(struct urb *urb)
|
||||||
|
{
|
||||||
|
struct usb_serial_port *port = urb->context;
|
||||||
|
struct ark3116_private *priv = usb_get_serial_port_data(port);
|
||||||
|
const __u8 *data = urb->transfer_buffer;
|
||||||
|
int status = urb->status;
|
||||||
|
struct tty_struct *tty;
|
||||||
|
unsigned long flags;
|
||||||
|
int result;
|
||||||
|
char flag;
|
||||||
|
__u32 lsr;
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case -ECONNRESET:
|
||||||
|
case -ENOENT:
|
||||||
|
case -ESHUTDOWN:
|
||||||
|
/* this urb is terminated, clean up */
|
||||||
|
dbg("%s - urb shutting down with status: %d",
|
||||||
|
__func__, status);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
dbg("%s - nonzero urb status received: %d",
|
||||||
|
__func__, status);
|
||||||
|
break;
|
||||||
|
case 0: /* success */
|
||||||
|
|
||||||
|
spin_lock_irqsave(&priv->status_lock, flags);
|
||||||
|
lsr = priv->lsr;
|
||||||
|
/* clear error bits */
|
||||||
|
priv->lsr &= ~UART_LSR_BRK_ERROR_BITS;
|
||||||
|
spin_unlock_irqrestore(&priv->status_lock, flags);
|
||||||
|
|
||||||
|
if (unlikely(lsr & UART_LSR_BI))
|
||||||
|
flag = TTY_BREAK;
|
||||||
|
else if (unlikely(lsr & UART_LSR_PE))
|
||||||
|
flag = TTY_PARITY;
|
||||||
|
else if (unlikely(lsr & UART_LSR_FE))
|
||||||
|
flag = TTY_FRAME;
|
||||||
|
else
|
||||||
|
flag = TTY_NORMAL;
|
||||||
|
|
||||||
|
tty = tty_port_tty_get(&port->port);
|
||||||
|
if (tty) {
|
||||||
|
tty_buffer_request_room(tty, urb->actual_length + 1);
|
||||||
|
/* overrun is special, not associated with a char */
|
||||||
|
if (unlikely(lsr & UART_LSR_OE))
|
||||||
|
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||||
|
send_to_tty(tty, data, urb->actual_length, flag);
|
||||||
|
tty_flip_buffer_push(tty);
|
||||||
|
tty_kref_put(tty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Throttle the device if requested by tty */
|
||||||
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
|
port->throttled = port->throttle_req;
|
||||||
|
if (port->throttled) {
|
||||||
|
spin_unlock_irqrestore(&port->lock, flags);
|
||||||
|
return;
|
||||||
|
} else
|
||||||
|
spin_unlock_irqrestore(&port->lock, flags);
|
||||||
|
}
|
||||||
|
/* Continue reading from device */
|
||||||
|
result = usb_submit_urb(urb, GFP_ATOMIC);
|
||||||
|
if (result)
|
||||||
|
dev_err(&urb->dev->dev, "%s - failed resubmitting"
|
||||||
|
" read urb, error %d\n", __func__, result);
|
||||||
|
}
|
||||||
|
|
||||||
static struct usb_driver ark3116_driver = {
|
static struct usb_driver ark3116_driver = {
|
||||||
.name = "ark3116",
|
.name = "ark3116",
|
||||||
.probe = usb_serial_probe,
|
.probe = usb_serial_probe,
|
||||||
|
@ -631,6 +823,8 @@ static struct usb_serial_driver ark3116_device = {
|
||||||
.open = ark3116_open,
|
.open = ark3116_open,
|
||||||
.close = ark3116_close,
|
.close = ark3116_close,
|
||||||
.break_ctl = ark3116_break_ctl,
|
.break_ctl = ark3116_break_ctl,
|
||||||
|
.read_int_callback = ark3116_read_int_callback,
|
||||||
|
.read_bulk_callback = ark3116_read_bulk_callback,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init ark3116_init(void)
|
static int __init ark3116_init(void)
|
||||||
|
|
Loading…
Reference in a new issue