USB: whiteheat: reimplement using generic framework
Kill custom list-based read and write implementations and reimplement using the generic framework. Compile-only tested. Signed-off-by: Johan Hovold <jhovold@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
a6765cbafa
commit
5c0c7582a6
|
@ -95,10 +95,6 @@ static void whiteheat_release(struct usb_serial *serial);
|
|||
static int whiteheat_open(struct tty_struct *tty,
|
||||
struct usb_serial_port *port);
|
||||
static void whiteheat_close(struct usb_serial_port *port);
|
||||
static int whiteheat_write(struct tty_struct *tty,
|
||||
struct usb_serial_port *port,
|
||||
const unsigned char *buf, int count);
|
||||
static int whiteheat_write_room(struct tty_struct *tty);
|
||||
static int whiteheat_ioctl(struct tty_struct *tty,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
static void whiteheat_set_termios(struct tty_struct *tty,
|
||||
|
@ -107,11 +103,6 @@ static int whiteheat_tiocmget(struct tty_struct *tty);
|
|||
static int whiteheat_tiocmset(struct tty_struct *tty,
|
||||
unsigned int set, unsigned int clear);
|
||||
static void whiteheat_break_ctl(struct tty_struct *tty, int break_state);
|
||||
static int whiteheat_chars_in_buffer(struct tty_struct *tty);
|
||||
static void whiteheat_throttle(struct tty_struct *tty);
|
||||
static void whiteheat_unthrottle(struct tty_struct *tty);
|
||||
static void whiteheat_read_callback(struct urb *urb);
|
||||
static void whiteheat_write_callback(struct urb *urb);
|
||||
|
||||
static struct usb_serial_driver whiteheat_fake_device = {
|
||||
.driver = {
|
||||
|
@ -137,18 +128,13 @@ static struct usb_serial_driver whiteheat_device = {
|
|||
.release = whiteheat_release,
|
||||
.open = whiteheat_open,
|
||||
.close = whiteheat_close,
|
||||
.write = whiteheat_write,
|
||||
.write_room = whiteheat_write_room,
|
||||
.ioctl = whiteheat_ioctl,
|
||||
.set_termios = whiteheat_set_termios,
|
||||
.break_ctl = whiteheat_break_ctl,
|
||||
.tiocmget = whiteheat_tiocmget,
|
||||
.tiocmset = whiteheat_tiocmset,
|
||||
.chars_in_buffer = whiteheat_chars_in_buffer,
|
||||
.throttle = whiteheat_throttle,
|
||||
.unthrottle = whiteheat_unthrottle,
|
||||
.read_bulk_callback = whiteheat_read_callback,
|
||||
.write_bulk_callback = whiteheat_write_callback,
|
||||
.throttle = usb_serial_generic_throttle,
|
||||
.unthrottle = usb_serial_generic_unthrottle,
|
||||
};
|
||||
|
||||
static struct usb_serial_driver * const serial_drivers[] = {
|
||||
|
@ -165,29 +151,8 @@ struct whiteheat_command_private {
|
|||
__u8 result_buffer[64];
|
||||
};
|
||||
|
||||
|
||||
#define THROTTLED 0x01
|
||||
#define ACTUALLY_THROTTLED 0x02
|
||||
|
||||
static int urb_pool_size = 8;
|
||||
|
||||
struct whiteheat_urb_wrap {
|
||||
struct list_head list;
|
||||
struct urb *urb;
|
||||
};
|
||||
|
||||
struct whiteheat_private {
|
||||
spinlock_t lock;
|
||||
__u8 flags;
|
||||
__u8 mcr; /* FIXME: no locking on mcr */
|
||||
struct list_head rx_urbs_free;
|
||||
struct list_head rx_urbs_submitted;
|
||||
struct list_head rx_urb_q;
|
||||
struct work_struct rx_work;
|
||||
struct usb_serial_port *port;
|
||||
struct list_head tx_urbs_free;
|
||||
struct list_head tx_urbs_submitted;
|
||||
struct mutex deathwarrant;
|
||||
};
|
||||
|
||||
|
||||
|
@ -197,12 +162,6 @@ static void stop_command_port(struct usb_serial *serial);
|
|||
static void command_port_write_callback(struct urb *urb);
|
||||
static void command_port_read_callback(struct urb *urb);
|
||||
|
||||
static int start_port_read(struct usb_serial_port *port);
|
||||
static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb,
|
||||
struct list_head *head);
|
||||
static struct list_head *list_first(struct list_head *head);
|
||||
static void rx_data_softint(struct work_struct *work);
|
||||
|
||||
static int firm_send_command(struct usb_serial_port *port, __u8 command,
|
||||
__u8 *data, __u8 datasize);
|
||||
static int firm_open(struct usb_serial_port *port);
|
||||
|
@ -348,11 +307,6 @@ static int whiteheat_attach(struct usb_serial *serial)
|
|||
__u8 *command;
|
||||
__u8 *result;
|
||||
int i;
|
||||
int j;
|
||||
struct urb *urb;
|
||||
int buf_size;
|
||||
struct whiteheat_urb_wrap *wrap;
|
||||
struct list_head *tmp;
|
||||
|
||||
command_port = serial->port[COMMAND_PORT];
|
||||
|
||||
|
@ -422,72 +376,7 @@ static int whiteheat_attach(struct usb_serial *serial)
|
|||
goto no_private;
|
||||
}
|
||||
|
||||
spin_lock_init(&info->lock);
|
||||
mutex_init(&info->deathwarrant);
|
||||
info->flags = 0;
|
||||
info->mcr = 0;
|
||||
INIT_WORK(&info->rx_work, rx_data_softint);
|
||||
info->port = port;
|
||||
|
||||
INIT_LIST_HEAD(&info->rx_urbs_free);
|
||||
INIT_LIST_HEAD(&info->rx_urbs_submitted);
|
||||
INIT_LIST_HEAD(&info->rx_urb_q);
|
||||
INIT_LIST_HEAD(&info->tx_urbs_free);
|
||||
INIT_LIST_HEAD(&info->tx_urbs_submitted);
|
||||
|
||||
for (j = 0; j < urb_pool_size; j++) {
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb) {
|
||||
dev_err(&port->dev, "No free urbs available\n");
|
||||
goto no_rx_urb;
|
||||
}
|
||||
buf_size = port->read_urb->transfer_buffer_length;
|
||||
urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL);
|
||||
if (!urb->transfer_buffer) {
|
||||
dev_err(&port->dev,
|
||||
"Couldn't allocate urb buffer\n");
|
||||
goto no_rx_buf;
|
||||
}
|
||||
wrap = kmalloc(sizeof(*wrap), GFP_KERNEL);
|
||||
if (!wrap) {
|
||||
dev_err(&port->dev,
|
||||
"Couldn't allocate urb wrapper\n");
|
||||
goto no_rx_wrap;
|
||||
}
|
||||
usb_fill_bulk_urb(urb, serial->dev,
|
||||
usb_rcvbulkpipe(serial->dev,
|
||||
port->bulk_in_endpointAddress),
|
||||
urb->transfer_buffer, buf_size,
|
||||
whiteheat_read_callback, port);
|
||||
wrap->urb = urb;
|
||||
list_add(&wrap->list, &info->rx_urbs_free);
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb) {
|
||||
dev_err(&port->dev, "No free urbs available\n");
|
||||
goto no_tx_urb;
|
||||
}
|
||||
buf_size = port->write_urb->transfer_buffer_length;
|
||||
urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL);
|
||||
if (!urb->transfer_buffer) {
|
||||
dev_err(&port->dev,
|
||||
"Couldn't allocate urb buffer\n");
|
||||
goto no_tx_buf;
|
||||
}
|
||||
wrap = kmalloc(sizeof(*wrap), GFP_KERNEL);
|
||||
if (!wrap) {
|
||||
dev_err(&port->dev,
|
||||
"Couldn't allocate urb wrapper\n");
|
||||
goto no_tx_wrap;
|
||||
}
|
||||
usb_fill_bulk_urb(urb, serial->dev,
|
||||
usb_sndbulkpipe(serial->dev,
|
||||
port->bulk_out_endpointAddress),
|
||||
urb->transfer_buffer, buf_size,
|
||||
whiteheat_write_callback, port);
|
||||
wrap->urb = urb;
|
||||
list_add(&wrap->list, &info->tx_urbs_free);
|
||||
}
|
||||
|
||||
usb_set_serial_port_data(port, info);
|
||||
}
|
||||
|
@ -530,29 +419,6 @@ no_command_private:
|
|||
for (i = serial->num_ports - 1; i >= 0; i--) {
|
||||
port = serial->port[i];
|
||||
info = usb_get_serial_port_data(port);
|
||||
for (j = urb_pool_size - 1; j >= 0; j--) {
|
||||
tmp = list_first(&info->tx_urbs_free);
|
||||
list_del(tmp);
|
||||
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
|
||||
urb = wrap->urb;
|
||||
kfree(wrap);
|
||||
no_tx_wrap:
|
||||
kfree(urb->transfer_buffer);
|
||||
no_tx_buf:
|
||||
usb_free_urb(urb);
|
||||
no_tx_urb:
|
||||
tmp = list_first(&info->rx_urbs_free);
|
||||
list_del(tmp);
|
||||
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
|
||||
urb = wrap->urb;
|
||||
kfree(wrap);
|
||||
no_rx_wrap:
|
||||
kfree(urb->transfer_buffer);
|
||||
no_rx_buf:
|
||||
usb_free_urb(urb);
|
||||
no_rx_urb:
|
||||
;
|
||||
}
|
||||
kfree(info);
|
||||
no_private:
|
||||
;
|
||||
|
@ -568,12 +434,7 @@ no_command_buffer:
|
|||
static void whiteheat_release(struct usb_serial *serial)
|
||||
{
|
||||
struct usb_serial_port *command_port;
|
||||
struct usb_serial_port *port;
|
||||
struct whiteheat_private *info;
|
||||
struct whiteheat_urb_wrap *wrap;
|
||||
struct urb *urb;
|
||||
struct list_head *tmp;
|
||||
struct list_head *tmp2;
|
||||
int i;
|
||||
|
||||
dbg("%s", __func__);
|
||||
|
@ -583,31 +444,14 @@ static void whiteheat_release(struct usb_serial *serial)
|
|||
kfree(usb_get_serial_port_data(command_port));
|
||||
|
||||
for (i = 0; i < serial->num_ports; i++) {
|
||||
port = serial->port[i];
|
||||
info = usb_get_serial_port_data(port);
|
||||
list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) {
|
||||
list_del(tmp);
|
||||
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
|
||||
urb = wrap->urb;
|
||||
kfree(wrap);
|
||||
kfree(urb->transfer_buffer);
|
||||
usb_free_urb(urb);
|
||||
}
|
||||
list_for_each_safe(tmp, tmp2, &info->tx_urbs_free) {
|
||||
list_del(tmp);
|
||||
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
|
||||
urb = wrap->urb;
|
||||
kfree(wrap);
|
||||
kfree(urb->transfer_buffer);
|
||||
usb_free_urb(urb);
|
||||
}
|
||||
info = usb_get_serial_port_data(serial->port[i]);
|
||||
kfree(info);
|
||||
}
|
||||
}
|
||||
|
||||
static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||||
{
|
||||
int retval = 0;
|
||||
int retval;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
|
@ -615,9 +459,6 @@ static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port)
|
|||
if (retval)
|
||||
goto exit;
|
||||
|
||||
if (tty)
|
||||
tty->low_latency = 1;
|
||||
|
||||
/* send an open port command */
|
||||
retval = firm_open(port);
|
||||
if (retval) {
|
||||
|
@ -639,17 +480,12 @@ static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port)
|
|||
usb_clear_halt(port->serial->dev, port->read_urb->pipe);
|
||||
usb_clear_halt(port->serial->dev, port->write_urb->pipe);
|
||||
|
||||
/* Start reading from the device */
|
||||
retval = start_port_read(port);
|
||||
retval = usb_serial_generic_open(tty, port);
|
||||
if (retval) {
|
||||
dev_err(&port->dev,
|
||||
"%s - failed submitting read urb, error %d\n",
|
||||
__func__, retval);
|
||||
firm_close(port);
|
||||
stop_command_port(port->serial);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
dbg("%s - exit, retval = %d", __func__, retval);
|
||||
return retval;
|
||||
|
@ -658,127 +494,16 @@ exit:
|
|||
|
||||
static void whiteheat_close(struct usb_serial_port *port)
|
||||
{
|
||||
struct whiteheat_private *info = usb_get_serial_port_data(port);
|
||||
struct whiteheat_urb_wrap *wrap;
|
||||
struct urb *urb;
|
||||
struct list_head *tmp;
|
||||
struct list_head *tmp2;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
firm_report_tx_done(port);
|
||||
firm_close(port);
|
||||
|
||||
/* shutdown our bulk reads and writes */
|
||||
mutex_lock(&info->deathwarrant);
|
||||
spin_lock_irq(&info->lock);
|
||||
list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) {
|
||||
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
|
||||
urb = wrap->urb;
|
||||
list_del(tmp);
|
||||
spin_unlock_irq(&info->lock);
|
||||
usb_kill_urb(urb);
|
||||
spin_lock_irq(&info->lock);
|
||||
list_add(tmp, &info->rx_urbs_free);
|
||||
}
|
||||
list_for_each_safe(tmp, tmp2, &info->rx_urb_q)
|
||||
list_move(tmp, &info->rx_urbs_free);
|
||||
list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) {
|
||||
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
|
||||
urb = wrap->urb;
|
||||
list_del(tmp);
|
||||
spin_unlock_irq(&info->lock);
|
||||
usb_kill_urb(urb);
|
||||
spin_lock_irq(&info->lock);
|
||||
list_add(tmp, &info->tx_urbs_free);
|
||||
}
|
||||
spin_unlock_irq(&info->lock);
|
||||
mutex_unlock(&info->deathwarrant);
|
||||
usb_serial_generic_close(port);
|
||||
|
||||
stop_command_port(port->serial);
|
||||
}
|
||||
|
||||
|
||||
static int whiteheat_write(struct tty_struct *tty,
|
||||
struct usb_serial_port *port, const unsigned char *buf, int count)
|
||||
{
|
||||
struct whiteheat_private *info = usb_get_serial_port_data(port);
|
||||
struct whiteheat_urb_wrap *wrap;
|
||||
struct urb *urb;
|
||||
int result;
|
||||
int bytes;
|
||||
int sent = 0;
|
||||
unsigned long flags;
|
||||
struct list_head *tmp;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
if (count == 0) {
|
||||
dbg("%s - write request of 0 bytes", __func__);
|
||||
return (0);
|
||||
}
|
||||
|
||||
while (count) {
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
if (list_empty(&info->tx_urbs_free)) {
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
break;
|
||||
}
|
||||
tmp = list_first(&info->tx_urbs_free);
|
||||
list_del(tmp);
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
|
||||
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
|
||||
urb = wrap->urb;
|
||||
bytes = (count > port->bulk_out_size) ?
|
||||
port->bulk_out_size : count;
|
||||
memcpy(urb->transfer_buffer, buf + sent, bytes);
|
||||
|
||||
usb_serial_debug_data(debug, &port->dev,
|
||||
__func__, bytes, urb->transfer_buffer);
|
||||
|
||||
urb->transfer_buffer_length = bytes;
|
||||
result = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (result) {
|
||||
dev_err_console(port,
|
||||
"%s - failed submitting write urb, error %d\n",
|
||||
__func__, result);
|
||||
sent = result;
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
list_add(tmp, &info->tx_urbs_free);
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
break;
|
||||
} else {
|
||||
sent += bytes;
|
||||
count -= bytes;
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
list_add(tmp, &info->tx_urbs_submitted);
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
static int whiteheat_write_room(struct tty_struct *tty)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct whiteheat_private *info = usb_get_serial_port_data(port);
|
||||
struct list_head *tmp;
|
||||
int room = 0;
|
||||
unsigned long flags;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
list_for_each(tmp, &info->tx_urbs_free)
|
||||
room++;
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
room *= port->bulk_out_size;
|
||||
|
||||
dbg("%s - returns %d", __func__, room);
|
||||
return (room);
|
||||
}
|
||||
|
||||
static int whiteheat_tiocmget(struct tty_struct *tty)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
|
@ -836,7 +561,7 @@ static int whiteheat_ioctl(struct tty_struct *tty,
|
|||
serstruct.line = port->serial->minor;
|
||||
serstruct.port = port->number;
|
||||
serstruct.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
|
||||
serstruct.xmit_fifo_size = port->bulk_out_size;
|
||||
serstruct.xmit_fifo_size = kfifo_size(&port->write_fifo);
|
||||
serstruct.custom_divisor = 0;
|
||||
serstruct.baud_base = 460800;
|
||||
serstruct.close_delay = CLOSING_DELAY;
|
||||
|
@ -866,60 +591,6 @@ static void whiteheat_break_ctl(struct tty_struct *tty, int break_state)
|
|||
}
|
||||
|
||||
|
||||
static int whiteheat_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct whiteheat_private *info = usb_get_serial_port_data(port);
|
||||
struct list_head *tmp;
|
||||
struct whiteheat_urb_wrap *wrap;
|
||||
int chars = 0;
|
||||
unsigned long flags;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
list_for_each(tmp, &info->tx_urbs_submitted) {
|
||||
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
|
||||
chars += wrap->urb->transfer_buffer_length;
|
||||
}
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
|
||||
dbg("%s - returns %d", __func__, chars);
|
||||
return chars;
|
||||
}
|
||||
|
||||
|
||||
static void whiteheat_throttle(struct tty_struct *tty)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct whiteheat_private *info = usb_get_serial_port_data(port);
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock_irq(&info->lock);
|
||||
info->flags |= THROTTLED;
|
||||
spin_unlock_irq(&info->lock);
|
||||
}
|
||||
|
||||
|
||||
static void whiteheat_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct whiteheat_private *info = usb_get_serial_port_data(port);
|
||||
int actually_throttled;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock_irq(&info->lock);
|
||||
actually_throttled = info->flags & ACTUALLY_THROTTLED;
|
||||
info->flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
|
||||
spin_unlock_irq(&info->lock);
|
||||
|
||||
if (actually_throttled)
|
||||
rx_data_softint(&info->rx_work);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Connect Tech's White Heat callback routines
|
||||
*****************************************************************************/
|
||||
|
@ -988,80 +659,6 @@ static void command_port_read_callback(struct urb *urb)
|
|||
}
|
||||
|
||||
|
||||
static void whiteheat_read_callback(struct urb *urb)
|
||||
{
|
||||
struct usb_serial_port *port = urb->context;
|
||||
struct whiteheat_urb_wrap *wrap;
|
||||
unsigned char *data = urb->transfer_buffer;
|
||||
struct whiteheat_private *info = usb_get_serial_port_data(port);
|
||||
int status = urb->status;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock(&info->lock);
|
||||
wrap = urb_to_wrap(urb, &info->rx_urbs_submitted);
|
||||
if (!wrap) {
|
||||
spin_unlock(&info->lock);
|
||||
dev_err(&port->dev, "%s - Not my urb!\n", __func__);
|
||||
return;
|
||||
}
|
||||
list_del(&wrap->list);
|
||||
spin_unlock(&info->lock);
|
||||
|
||||
if (status) {
|
||||
dbg("%s - nonzero read bulk status received: %d",
|
||||
__func__, status);
|
||||
spin_lock(&info->lock);
|
||||
list_add(&wrap->list, &info->rx_urbs_free);
|
||||
spin_unlock(&info->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
usb_serial_debug_data(debug, &port->dev,
|
||||
__func__, urb->actual_length, data);
|
||||
|
||||
spin_lock(&info->lock);
|
||||
list_add_tail(&wrap->list, &info->rx_urb_q);
|
||||
if (info->flags & THROTTLED) {
|
||||
info->flags |= ACTUALLY_THROTTLED;
|
||||
spin_unlock(&info->lock);
|
||||
return;
|
||||
}
|
||||
spin_unlock(&info->lock);
|
||||
|
||||
schedule_work(&info->rx_work);
|
||||
}
|
||||
|
||||
|
||||
static void whiteheat_write_callback(struct urb *urb)
|
||||
{
|
||||
struct usb_serial_port *port = urb->context;
|
||||
struct whiteheat_private *info = usb_get_serial_port_data(port);
|
||||
struct whiteheat_urb_wrap *wrap;
|
||||
int status = urb->status;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock(&info->lock);
|
||||
wrap = urb_to_wrap(urb, &info->tx_urbs_submitted);
|
||||
if (!wrap) {
|
||||
spin_unlock(&info->lock);
|
||||
dev_err(&port->dev, "%s - Not my urb!\n", __func__);
|
||||
return;
|
||||
}
|
||||
list_move(&wrap->list, &info->tx_urbs_free);
|
||||
spin_unlock(&info->lock);
|
||||
|
||||
if (status) {
|
||||
dbg("%s - nonzero write bulk status received: %d",
|
||||
__func__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
usb_serial_port_softint(port);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Connect Tech's White Heat firmware interface
|
||||
*****************************************************************************/
|
||||
|
@ -1336,123 +933,6 @@ static void stop_command_port(struct usb_serial *serial)
|
|||
mutex_unlock(&command_info->mutex);
|
||||
}
|
||||
|
||||
|
||||
static int start_port_read(struct usb_serial_port *port)
|
||||
{
|
||||
struct whiteheat_private *info = usb_get_serial_port_data(port);
|
||||
struct whiteheat_urb_wrap *wrap;
|
||||
struct urb *urb;
|
||||
int retval = 0;
|
||||
unsigned long flags;
|
||||
struct list_head *tmp;
|
||||
struct list_head *tmp2;
|
||||
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
|
||||
list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) {
|
||||
list_del(tmp);
|
||||
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
|
||||
urb = wrap->urb;
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
retval = usb_submit_urb(urb, GFP_KERNEL);
|
||||
if (retval) {
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
list_add(tmp, &info->rx_urbs_free);
|
||||
list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) {
|
||||
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
|
||||
urb = wrap->urb;
|
||||
list_del(tmp);
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
usb_kill_urb(urb);
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
list_add(tmp, &info->rx_urbs_free);
|
||||
}
|
||||
break;
|
||||
}
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
list_add(tmp, &info->rx_urbs_submitted);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct whiteheat_urb_wrap *wrap;
|
||||
struct list_head *tmp;
|
||||
|
||||
list_for_each(tmp, head) {
|
||||
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
|
||||
if (wrap->urb == urb)
|
||||
return wrap;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct list_head *list_first(struct list_head *head)
|
||||
{
|
||||
return head->next;
|
||||
}
|
||||
|
||||
|
||||
static void rx_data_softint(struct work_struct *work)
|
||||
{
|
||||
struct whiteheat_private *info =
|
||||
container_of(work, struct whiteheat_private, rx_work);
|
||||
struct usb_serial_port *port = info->port;
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->port);
|
||||
struct whiteheat_urb_wrap *wrap;
|
||||
struct urb *urb;
|
||||
unsigned long flags;
|
||||
struct list_head *tmp;
|
||||
struct list_head *tmp2;
|
||||
int result;
|
||||
int sent = 0;
|
||||
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
if (info->flags & THROTTLED) {
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
goto out;
|
||||
}
|
||||
|
||||
list_for_each_safe(tmp, tmp2, &info->rx_urb_q) {
|
||||
list_del(tmp);
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
|
||||
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
|
||||
urb = wrap->urb;
|
||||
|
||||
if (tty && urb->actual_length)
|
||||
sent += tty_insert_flip_string(tty,
|
||||
urb->transfer_buffer, urb->actual_length);
|
||||
|
||||
result = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (result) {
|
||||
dev_err(&port->dev,
|
||||
"%s - failed resubmitting read urb, error %d\n",
|
||||
__func__, result);
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
list_add(tmp, &info->rx_urbs_free);
|
||||
continue;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
list_add(tmp, &info->rx_urbs_submitted);
|
||||
}
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
|
||||
if (sent)
|
||||
tty_flip_buffer_push(tty);
|
||||
out:
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
module_usb_serial_driver(whiteheat_driver, serial_drivers);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
|
@ -1462,8 +942,5 @@ MODULE_LICENSE("GPL");
|
|||
MODULE_FIRMWARE("whiteheat.fw");
|
||||
MODULE_FIRMWARE("whiteheat_loader.fw");
|
||||
|
||||
module_param(urb_pool_size, int, 0);
|
||||
MODULE_PARM_DESC(urb_pool_size, "Number of urbs to use for buffering");
|
||||
|
||||
module_param(debug, bool, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(debug, "Debug enabled or not");
|
||||
|
|
Loading…
Reference in New Issue