patch-2.4.0-test9 linux/drivers/usb/serial/visor.c
Next file: linux/drivers/usb/serial/whiteheat.c
Previous file: linux/drivers/usb/serial/usbserial.c
Back to the patch index
Back to the overall index
- Lines: 302
- Date:
Mon Sep 18 15:23:25 2000
- Orig file:
v2.4.0-test8/linux/drivers/usb/serial/visor.c
- Orig date:
Tue Sep 5 13:42:52 2000
diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c
@@ -11,6 +11,17 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (09/11/2000) gkh
+ * Got rid of always calling kmalloc for every urb we wrote out to the
+ * device.
+ * Added visor_read_callback so we can keep track of bytes in and out for
+ * those people who like to know the speed of their device.
+ * Removed DEBUG #ifdefs with call to usb_serial_debug_data
+ *
+ * (09/06/2000) gkh
+ * Fixed oops in visor_exit. Need to uncomment usb_unlink_urb call _after_
+ * the host controller drivers set urb->dev = NULL when the urb is finished.
+ *
* (08/28/2000) gkh
* Added locks for SMP safeness.
*
@@ -71,6 +82,7 @@
#include "visor.h"
+#define MIN(a,b) (((a)<(b))?(a):(b))
/* function prototypes for a handspring visor */
static int visor_open (struct usb_serial_port *port, struct file *filp);
@@ -82,7 +94,8 @@
static void visor_shutdown (struct usb_serial *serial);
static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios);
-static void visor_write_bulk_callback (struct urb *urb);
+static void visor_write_bulk_callback (struct urb *urb);
+static void visor_read_bulk_callback (struct urb *urb);
/* All of the device info needed for the Handspring Visor */
static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID;
@@ -108,12 +121,17 @@
set_termios: visor_set_termios,
write: visor_write,
write_bulk_callback: visor_write_bulk_callback,
+ read_bulk_callback: visor_read_bulk_callback,
};
-#define NUM_URBS 24
+#define NUM_URBS 24
+#define URB_TRANSFER_BUFFER_SIZE 64
static struct urb *write_urb_pool[NUM_URBS];
static spinlock_t write_urb_pool_lock;
+static int bytes_in;
+static int bytes_out;
+
/******************************************************************************
* Handspring Visor specific driver functions
@@ -134,6 +152,8 @@
if (!port->active) {
port->active = 1;
+ bytes_in = 0;
+ bytes_out = 0;
/*Start reading from the device*/
if (usb_submit_urb(port->read_urb))
@@ -181,78 +201,79 @@
usb_unlink_urb (port->read_urb);
port->active = 0;
port->open_count = 0;
- }
+ }
spin_unlock_irqrestore (&port->port_lock, flags);
+
+ /* 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 int visor_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
{
struct usb_serial *serial = port->serial;
- struct urb *urb = NULL;
- unsigned char *buffer = NULL;
+ struct urb *urb;
+ const unsigned char *current_position = buf;
+ unsigned long flags;
int status;
int i;
- unsigned long flags;
+ int bytes_sent = 0;
+ int transfer_size;
dbg(__FUNCTION__ " - port %d", port->number);
- if (count == 0) {
- dbg(__FUNCTION__ " - write request of 0 bytes");
- return 0;
- }
-
- /* try to find a free urb in our list of them */
- spin_lock_irqsave (&write_urb_pool_lock, flags);
- for (i = 0; i < NUM_URBS; ++i) {
- if (write_urb_pool[i]->status != -EINPROGRESS) {
- urb = write_urb_pool[i];
- break;
+ usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf);
+
+ while (count > 0) {
+ /* try to find a free urb in our list of them */
+ urb = NULL;
+ spin_lock_irqsave (&write_urb_pool_lock, flags);
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (write_urb_pool[i]->status != -EINPROGRESS) {
+ urb = write_urb_pool[i];
+ break;
+ }
}
+ spin_unlock_irqrestore (&write_urb_pool_lock, flags);
+ if (urb == NULL) {
+ dbg (__FUNCTION__ " - no more free urbs");
+ goto exit;
+ }
+ if (urb->transfer_buffer == NULL) {
+ urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+ if (urb->transfer_buffer == NULL) {
+ err(__FUNCTION__" no more kernel memory...");
+ goto exit;
+ }
+ }
+
+ transfer_size = MIN (count, URB_TRANSFER_BUFFER_SIZE);
+ if (from_user)
+ copy_from_user (urb->transfer_buffer, current_position, transfer_size);
+ else
+ memcpy (urb->transfer_buffer, current_position, transfer_size);
+
+ count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+
+ /* build up our urb */
+ FILL_BULK_URB (urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+ urb->transfer_buffer, transfer_size, visor_write_bulk_callback, port);
+ urb->transfer_flags |= USB_QUEUE_BULK;
+
+ /* send it down the pipe */
+ status = usb_submit_urb(urb);
+ if (status)
+ dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
+
+ current_position += transfer_size;
+ bytes_sent += transfer_size;
+ count -= transfer_size;
+ bytes_out += transfer_size;
}
- spin_unlock_irqrestore (&write_urb_pool_lock, flags);
- if (urb == NULL) {
- dbg (__FUNCTION__ " - no free urbs");
- return 0;
- }
-
- count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-
-#ifdef DEBUG
- printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count);
- for (i = 0; i < count; ++i) {
- printk ("%.2x ", buf[i]);
- }
- printk ("\n");
-#endif
- if (urb->transfer_buffer != NULL)
- kfree(urb->transfer_buffer);
- buffer = kmalloc (count, GFP_KERNEL);
- if (buffer == NULL) {
- err(__FUNCTION__" no more kernel memory...");
- return 0;
- }
-
- if (from_user) {
- copy_from_user(buffer, buf, count);
- }
- else {
- memcpy (buffer, buf, count);
- }
-
- /* build up our urb */
- FILL_BULK_URB (urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
- buffer, count, visor_write_bulk_callback, port);
- urb->transfer_flags |= USB_QUEUE_BULK;
-
- /* send it down the pipe */
- status = usb_submit_urb(urb);
- if (status)
- dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
-
- return (count);
+exit:
+ return bytes_sent;
}
@@ -277,6 +298,41 @@
}
+static void visor_read_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+ int i;
+
+ if (port_paranoia_check (port, __FUNCTION__))
+ return;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ if (urb->status) {
+ dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+ return;
+ }
+
+ usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+ tty = port->tty;
+ if (urb->actual_length) {
+ for (i = 0; i < urb->actual_length ; ++i) {
+ tty_insert_flip_char(tty, data[i], 0);
+ }
+ tty_flip_buffer_push(tty);
+ bytes_in += urb->actual_length;
+ }
+
+ /* Continue trying to always read */
+ if (usb_submit_urb(urb))
+ dbg(__FUNCTION__ " - failed resubmitting read urb");
+ return;
+}
+
+
static void visor_throttle (struct usb_serial_port *port)
{
unsigned long flags;
@@ -372,7 +428,7 @@
kfree (transfer_buffer);
/* continue on with initialization */
- return (0);
+ return 0;
}
@@ -466,20 +522,27 @@
static int __init visor_init (void)
{
+ struct urb *urb;
int i;
usb_serial_register (&handspring_device);
- /* create our write urb pool */
+ /* create our write urb pool and transfer buffers */
spin_lock_init (&write_urb_pool_lock);
for (i = 0; i < NUM_URBS; ++i) {
- struct urb *urb = usb_alloc_urb(0);
+ urb = usb_alloc_urb(0);
+ write_urb_pool[i] = urb;
if (urb == NULL) {
err("No more urbs???");
continue;
}
+
urb->transfer_buffer = NULL;
- write_urb_pool[i] = urb;
+ urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+ if (!urb->transfer_buffer) {
+ err (__FUNCTION__ " - out of memory for urb buffers.");
+ continue;
+ }
}
return 0;
@@ -496,10 +559,15 @@
spin_lock_irqsave (&write_urb_pool_lock, flags);
for (i = 0; i < NUM_URBS; ++i) {
- usb_unlink_urb(write_urb_pool[i]);
- if (write_urb_pool[i]->transfer_buffer)
- kfree(write_urb_pool[i]->transfer_buffer);
- usb_free_urb (write_urb_pool[i]);
+ if (write_urb_pool[i]) {
+ /* FIXME - uncomment the following usb_unlink_urb call when
+ * the host controllers get fixed to set urb->dev = NULL after
+ * the urb is finished. Otherwise this call oopses. */
+ /* usb_unlink_urb(write_urb_pool[i]); */
+ if (write_urb_pool[i]->transfer_buffer)
+ kfree(write_urb_pool[i]->transfer_buffer);
+ usb_free_urb (write_urb_pool[i]);
+ }
}
spin_unlock_irqrestore (&write_urb_pool_lock, flags);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)