diff options
author | Johan Hovold <jhovold@gmail.com> | 2010-05-15 17:53:46 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-20 13:21:48 -0700 |
commit | 6b6962f9c489ecfa43ae27eb798c46717e203322 (patch) | |
tree | 80efc634058a09fe1b6c95fe5c8cfc8e94c2d4dd /drivers/usb/serial | |
parent | 695aaae684e249f9f0e7f1ed4caafa0687dbfa5b (diff) |
USB: ipaq: reimplement using generic framework
Kill custom fifo, read and write implementations (single-urb and fifo,
but still maintained list of 256*256b urb buffers per port).
Compile-only tested.
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r-- | drivers/usb/serial/ipaq.c | 333 | ||||
-rw-r--r-- | drivers/usb/serial/ipaq.h | 54 |
2 files changed, 10 insertions, 377 deletions
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 87b11461bf1..28913fa95fb 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -56,7 +56,6 @@ #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/serial.h> -#include "ipaq.h" #define KP_RETRIES 100 @@ -64,7 +63,7 @@ * Version Information */ -#define DRIVER_VERSION "v0.5" +#define DRIVER_VERSION "v1.0" #define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>" #define DRIVER_DESC "USB PocketPC PDA driver" @@ -76,20 +75,8 @@ static int initial_wait; /* Function prototypes for an ipaq */ static int ipaq_open(struct tty_struct *tty, struct usb_serial_port *port); -static void ipaq_close(struct usb_serial_port *port); static int ipaq_calc_num_ports(struct usb_serial *serial); static int ipaq_startup(struct usb_serial *serial); -static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -static int ipaq_write_bulk(struct usb_serial_port *port, - const unsigned char *buf, int count); -static void ipaq_write_gather(struct usb_serial_port *port); -static void ipaq_read_bulk_callback(struct urb *urb); -static void ipaq_write_bulk_callback(struct urb *urb); -static int ipaq_write_room(struct tty_struct *tty); -static int ipaq_chars_in_buffer(struct tty_struct *tty); -static void ipaq_destroy_lists(struct usb_serial_port *port); - static struct usb_device_id ipaq_id_table [] = { /* The first entry is a placeholder for the insmod-specified device */ @@ -558,7 +545,7 @@ static struct usb_driver ipaq_driver = { .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = ipaq_id_table, - .no_dynamic_id = 1, + .no_dynamic_id = 1, }; @@ -569,67 +556,24 @@ static struct usb_serial_driver ipaq_device = { .name = "ipaq", }, .description = "PocketPC PDA", - .usb_driver = &ipaq_driver, + .usb_driver = &ipaq_driver, .id_table = ipaq_id_table, - .bulk_in_size = URBDATA_SIZE, - .bulk_out_size = URBDATA_SIZE, + .bulk_in_size = 256, + .bulk_out_size = 256, .open = ipaq_open, - .close = ipaq_close, .attach = ipaq_startup, .calc_num_ports = ipaq_calc_num_ports, - .write = ipaq_write, - .write_room = ipaq_write_room, - .chars_in_buffer = ipaq_chars_in_buffer, - .read_bulk_callback = ipaq_read_bulk_callback, - .write_bulk_callback = ipaq_write_bulk_callback, }; -static spinlock_t write_list_lock; -static int bytes_in; -static int bytes_out; - static int ipaq_open(struct tty_struct *tty, struct usb_serial_port *port) { struct usb_serial *serial = port->serial; - struct ipaq_private *priv; - struct ipaq_packet *pkt; - int i, result = 0; + int result = 0; int retries = connect_retries; dbg("%s - port %d", __func__, port->number); - bytes_in = 0; - bytes_out = 0; - priv = kmalloc(sizeof(struct ipaq_private), GFP_KERNEL); - if (priv == NULL) { - dev_err(&port->dev, "%s - Out of memory\n", __func__); - return -ENOMEM; - } - usb_set_serial_port_data(port, priv); - priv->active = 0; - priv->queue_len = 0; - priv->free_len = 0; - INIT_LIST_HEAD(&priv->queue); - INIT_LIST_HEAD(&priv->freelist); - - for (i = 0; i < URBDATA_QUEUE_MAX / PACKET_SIZE; i++) { - pkt = kmalloc(sizeof(struct ipaq_packet), GFP_KERNEL); - if (pkt == NULL) - goto enomem; - - pkt->data = kmalloc(PACKET_SIZE, GFP_KERNEL); - if (pkt->data == NULL) { - kfree(pkt); - goto enomem; - } - pkt->len = 0; - pkt->written = 0; - INIT_LIST_HEAD(&pkt->list); - list_add(&pkt->list, &priv->freelist); - priv->free_len += PACKET_SIZE; - } - msleep(1000*initial_wait); /* @@ -639,7 +583,6 @@ static int ipaq_open(struct tty_struct *tty, * through. Since this has a reasonably high failure rate, we retry * several times. */ - while (retries--) { result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21, @@ -649,269 +592,15 @@ static int ipaq_open(struct tty_struct *tty, msleep(1000); } - if (!retries && result) { - dev_err(&port->dev, "%s - failed doing control urb, error %d\n", __func__, result); - goto error; - } - - /* Start reading from the device */ - usb_fill_bulk_urb(port->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - ipaq_read_bulk_callback, port); - - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) { - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); - goto error; - } - - return 0; - -enomem: - result = -ENOMEM; - dev_err(&port->dev, "%s - Out of memory\n", __func__); -error: - ipaq_destroy_lists(port); - kfree(priv); - return result; -} - - -static void ipaq_close(struct usb_serial_port *port) -{ - struct ipaq_private *priv = usb_get_serial_port_data(port); - - dbg("%s - port %d", __func__, port->number); - - /* - * shut down bulk read and write - */ - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); - ipaq_destroy_lists(port); - kfree(priv); - usb_set_serial_port_data(port, NULL); - - /* Uncomment the following line if you want to see some statistics - * in your syslog */ - /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ -} - -static void ipaq_read_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int result; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); - return; + dev_err(&port->dev, "%s - failed doing control urb, error %d\n", + __func__, result); + return result; } - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - - tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); - bytes_in += urb->actual_length; - } - tty_kref_put(tty); - - /* Continue trying to always read */ - usb_fill_bulk_urb(port->read_urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - ipaq_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - return; + return usb_serial_generic_open(tty, port); } -static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - const unsigned char *current_position = buf; - int bytes_sent = 0; - int transfer_size; - - dbg("%s - port %d", __func__, port->number); - - while (count > 0) { - transfer_size = min(count, PACKET_SIZE); - if (ipaq_write_bulk(port, current_position, transfer_size)) - break; - current_position += transfer_size; - bytes_sent += transfer_size; - count -= transfer_size; - bytes_out += transfer_size; - } - - return bytes_sent; -} - -static int ipaq_write_bulk(struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct ipaq_private *priv = usb_get_serial_port_data(port); - struct ipaq_packet *pkt = NULL; - int result = 0; - unsigned long flags; - - if (priv->free_len <= 0) { - dbg("%s - we're stuffed", __func__); - return -EAGAIN; - } - - spin_lock_irqsave(&write_list_lock, flags); - if (!list_empty(&priv->freelist)) { - pkt = list_entry(priv->freelist.next, struct ipaq_packet, list); - list_del(&pkt->list); - priv->free_len -= PACKET_SIZE; - } - spin_unlock_irqrestore(&write_list_lock, flags); - if (pkt == NULL) { - dbg("%s - we're stuffed", __func__); - return -EAGAIN; - } - - memcpy(pkt->data, buf, count); - usb_serial_debug_data(debug, &port->dev, __func__, count, pkt->data); - - pkt->len = count; - pkt->written = 0; - spin_lock_irqsave(&write_list_lock, flags); - list_add_tail(&pkt->list, &priv->queue); - priv->queue_len += count; - if (priv->active == 0) { - priv->active = 1; - ipaq_write_gather(port); - spin_unlock_irqrestore(&write_list_lock, flags); - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed submitting write urb, error %d\n", - __func__, result); - } else { - spin_unlock_irqrestore(&write_list_lock, flags); - } - return result; -} - -static void ipaq_write_gather(struct usb_serial_port *port) -{ - struct ipaq_private *priv = usb_get_serial_port_data(port); - struct usb_serial *serial = port->serial; - int count, room; - struct ipaq_packet *pkt, *tmp; - struct urb *urb = port->write_urb; - - room = URBDATA_SIZE; - list_for_each_entry_safe(pkt, tmp, &priv->queue, list) { - count = min(room, (int)(pkt->len - pkt->written)); - memcpy(urb->transfer_buffer + (URBDATA_SIZE - room), - pkt->data + pkt->written, count); - room -= count; - pkt->written += count; - priv->queue_len -= count; - if (pkt->written == pkt->len) { - list_move(&pkt->list, &priv->freelist); - priv->free_len += PACKET_SIZE; - } - if (room == 0) - break; - } - - count = URBDATA_SIZE - room; - usb_fill_bulk_urb(port->write_urb, serial->dev, - usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, count, - ipaq_write_bulk_callback, port); - return; -} - -static void ipaq_write_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct ipaq_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - int result; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - return; - } - - spin_lock_irqsave(&write_list_lock, flags); - if (!list_empty(&priv->queue)) { - ipaq_write_gather(port); - spin_unlock_irqrestore(&write_list_lock, flags); - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed submitting write urb, error %d\n", - __func__, result); - } else { - priv->active = 0; - spin_unlock_irqrestore(&write_list_lock, flags); - } - - usb_serial_port_softint(port); -} - -static int ipaq_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct ipaq_private *priv = usb_get_serial_port_data(port); - - dbg("%s - freelen %d", __func__, priv->free_len); - return priv->free_len; -} - -static int ipaq_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct ipaq_private *priv = usb_get_serial_port_data(port); - - dbg("%s - queuelen %d", __func__, priv->queue_len); - return priv->queue_len; -} - -static void ipaq_destroy_lists(struct usb_serial_port *port) -{ - struct ipaq_private *priv = usb_get_serial_port_data(port); - struct ipaq_packet *pkt, *tmp; - - list_for_each_entry_safe(pkt, tmp, &priv->queue, list) { - kfree(pkt->data); - kfree(pkt); - } - list_for_each_entry_safe(pkt, tmp, &priv->freelist, list) { - kfree(pkt->data); - kfree(pkt); - } -} - - static int ipaq_calc_num_ports(struct usb_serial *serial) { /* @@ -970,7 +659,6 @@ static int ipaq_startup(struct usb_serial *serial) static int __init ipaq_init(void) { int retval; - spin_lock_init(&write_list_lock); retval = usb_serial_register(&ipaq_device); if (retval) goto failed_usb_serial_register; @@ -991,7 +679,6 @@ failed_usb_serial_register: return retval; } - static void __exit ipaq_exit(void) { usb_deregister(&ipaq_driver); diff --git a/drivers/usb/serial/ipaq.h b/drivers/usb/serial/ipaq.h deleted file mode 100644 index 2b9035918b8..00000000000 --- a/drivers/usb/serial/ipaq.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * USB Compaq iPAQ driver - * - * Copyright (C) 2001 - 2002 - * Ganesh Varadarajan <ganesh@veritas.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - */ - -#ifndef __LINUX_USB_SERIAL_IPAQ_H -#define __LINUX_USB_SERIAL_IPAQ_H - -/* - * Since we can't queue our bulk write urbs (don't know why - it just - * doesn't work), we can send down only one write urb at a time. The simplistic - * approach taken by the generic usbserial driver will work, but it's not good - * for performance. Therefore, we buffer upto URBDATA_QUEUE_MAX bytes of write - * requests coming from the line discipline. This is done by chaining them - * in lists of struct ipaq_packet, each packet holding a maximum of - * PACKET_SIZE bytes. - * - * ipaq_write() can be called from bottom half context; hence we can't - * allocate memory for packets there. So we initialize a pool of packets at - * the first open and maintain a freelist. - * - * The value of PACKET_SIZE was empirically determined by - * checking the maximum write sizes sent down by the ppp ldisc. - * URBDATA_QUEUE_MAX is set to 64K, which is the maximum TCP window size. - */ - -struct ipaq_packet { - char *data; - size_t len; - size_t written; - struct list_head list; -}; - -struct ipaq_private { - int active; - int queue_len; - int free_len; - struct list_head queue; - struct list_head freelist; -}; - -#define URBDATA_SIZE 4096 -#define URBDATA_QUEUE_MAX (64 * 1024) -#define PACKET_SIZE 256 - -#endif |