|
@@ -45,7 +45,6 @@ static bool debug;
|
|
|
/*
|
|
|
* Version Information
|
|
|
*/
|
|
|
-#define DRIVER_VERSION "v2.0"
|
|
|
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Stuart MacDonald <stuartm@connecttech.com>"
|
|
|
#define DRIVER_DESC "USB ConnectTech WhiteHEAT driver"
|
|
|
|
|
@@ -96,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,
|
|
@@ -108,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 = {
|
|
@@ -138,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[] = {
|
|
@@ -166,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;
|
|
|
};
|
|
|
|
|
|
|
|
@@ -198,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);
|
|
@@ -349,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];
|
|
|
|
|
@@ -408,8 +361,8 @@ static int whiteheat_attach(struct usb_serial *serial)
|
|
|
|
|
|
hw_info = (struct whiteheat_hw_info *)&result[1];
|
|
|
|
|
|
- dev_info(&serial->dev->dev, "%s: Driver %s: Firmware v%d.%02d\n",
|
|
|
- serial->type->description, DRIVER_VERSION,
|
|
|
+ dev_info(&serial->dev->dev, "%s: Firmware v%d.%02d\n",
|
|
|
+ serial->type->description,
|
|
|
hw_info->sw_major_rev, hw_info->sw_minor_rev);
|
|
|
|
|
|
for (i = 0; i < serial->num_ports; i++) {
|
|
@@ -423,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);
|
|
|
}
|
|
@@ -531,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:
|
|
|
;
|
|
@@ -569,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__);
|
|
@@ -584,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);
|
|
|
|
|
@@ -616,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) {
|
|
@@ -640,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;
|
|
@@ -659,125 +494,14 @@ 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);
|
|
|
- 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);
|
|
|
- }
|
|
|
- }
|
|
|
+ usb_serial_generic_close(port);
|
|
|
|
|
|
- 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);
|
|
|
+ stop_command_port(port->serial);
|
|
|
}
|
|
|
|
|
|
static int whiteheat_tiocmget(struct tty_struct *tty)
|
|
@@ -837,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;
|
|
@@ -867,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
|
|
|
*****************************************************************************/
|
|
@@ -989,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
|
|
|
*****************************************************************************/
|
|
@@ -1337,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);
|
|
@@ -1463,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");
|