patch-2.4.20 linux-2.4.20/drivers/usb/serial/ipaq.c
Next file: linux-2.4.20/drivers/usb/serial/ipaq.h
Previous file: linux-2.4.20/drivers/usb/serial/io_usbvend.h
Back to the patch index
Back to the overall index
- Lines: 487
- Date:
Thu Nov 28 15:53:14 2002
- Orig file:
linux-2.4.19/drivers/usb/serial/ipaq.c
- Orig date:
Fri Aug 2 17:39:45 2002
diff -urN linux-2.4.19/drivers/usb/serial/ipaq.c linux-2.4.20/drivers/usb/serial/ipaq.c
@@ -9,6 +9,10 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
+ * (26/7/2002) ganesh
+ * Fixed up broken error handling in ipaq_open. Retry the "kickstart"
+ * packet much harder - this drastically reduces connection failures.
+ *
* (30/4/2002) ganesh
* Added support for the Casio EM500. Completely untested. Thanks
* to info from Nathan <wfilardo@fuse.net>
@@ -34,18 +38,15 @@
#include <linux/config.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
#include <linux/errno.h>
-#include <linux/poll.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/fcntl.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <asm/uaccess.h>
#include <linux/usb.h>
#ifdef CONFIG_USB_SERIAL_DEBUG
@@ -57,6 +58,8 @@
#include "usb-serial.h"
#include "ipaq.h"
+#define KP_RETRIES 100
+
/*
* Version Information
*/
@@ -81,7 +84,7 @@
static void ipaq_destroy_lists(struct usb_serial_port *port);
-static __devinitdata struct usb_device_id ipaq_id_table [] = {
+static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) },
@@ -93,24 +96,22 @@
/* All of the device info needed for the Compaq iPAQ */
struct usb_serial_device_type ipaq_device = {
- name: "Compaq iPAQ",
- id_table: ipaq_id_table,
- needs_interrupt_in: DONT_CARE,
- needs_bulk_in: MUST_HAVE,
- needs_bulk_out: MUST_HAVE,
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: 1,
- num_bulk_out: 1,
- num_ports: 1,
- open: ipaq_open,
- close: ipaq_close,
- startup: ipaq_startup,
- shutdown: ipaq_shutdown,
- 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,
+ .owner = THIS_MODULE,
+ .name = "Compaq iPAQ",
+ .id_table = ipaq_id_table,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = ipaq_open,
+ .close = ipaq_close,
+ .startup = ipaq_startup,
+ .shutdown = ipaq_shutdown,
+ .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;
@@ -123,115 +124,110 @@
struct ipaq_private *priv;
struct ipaq_packet *pkt;
int i, result = 0;
+ int retries = KP_RETRIES;
if (port_paranoia_check(port, __FUNCTION__)) {
return -ENODEV;
}
- dbg(__FUNCTION__ " - port %d", port->number);
-
- down(&port->sem);
-
- ++port->open_count;
- MOD_INC_USE_COUNT;
-
- if (!port->active) {
- port->active = 1;
- bytes_in = 0;
- bytes_out = 0;
- priv = (struct ipaq_private *)kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
- if (priv == NULL) {
- err(__FUNCTION__ " - Out of memory");
- return -ENOMEM;
- }
- port->private = (void *)priv;
- priv->active = 0;
- priv->queue_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;
- }
-
- /*
- * Force low latency on. This will immediately push data to the line
- * discipline instead of queueing.
- */
-
- port->tty->low_latency = 1;
- port->tty->raw = 1;
- port->tty->real_raw = 1;
-
- /*
- * Lose the small buffers usbserial provides. Make larger ones.
- */
+ dbg("%s - port %d", __FUNCTION__, port->number);
- kfree(port->bulk_in_buffer);
- kfree(port->bulk_out_buffer);
- port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
- if (port->bulk_in_buffer == NULL) {
+ bytes_in = 0;
+ bytes_out = 0;
+ priv = (struct ipaq_private *)kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
+ if (priv == NULL) {
+ err("%s - Out of memory", __FUNCTION__);
+ return -ENOMEM;
+ }
+ port->private = (void *)priv;
+ priv->active = 0;
+ priv->queue_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;
}
- port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
- if (port->bulk_out_buffer == NULL) {
- kfree(port->bulk_in_buffer);
+ pkt->data = kmalloc(PACKET_SIZE, GFP_KERNEL);
+ if (pkt->data == NULL) {
+ kfree(pkt);
goto enomem;
}
- port->read_urb->transfer_buffer = port->bulk_in_buffer;
- port->write_urb->transfer_buffer = port->bulk_out_buffer;
- port->read_urb->transfer_buffer_length = URBDATA_SIZE;
- port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE;
-
- /* Start reading from the device */
- 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);
- if (result) {
- err(__FUNCTION__ " - failed submitting read urb, error %d", result);
- }
-
- /*
- * Send out two control messages observed in win98 sniffs. Not sure what
- * they do.
- */
-
- result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
- 0x1, 0, NULL, 0, 5 * HZ);
- if (result < 0) {
- err(__FUNCTION__ " - failed doing control urb, error %d", result);
- }
- result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
- 0x1, 0, NULL, 0, 5 * HZ);
- if (result < 0) {
- err(__FUNCTION__ " - failed doing control urb, error %d", result);
- }
+ pkt->len = 0;
+ pkt->written = 0;
+ INIT_LIST_HEAD(&pkt->list);
+ list_add(&pkt->list, &priv->freelist);
+ priv->free_len += PACKET_SIZE;
+ }
+
+ /*
+ * Force low latency on. This will immediately push data to the line
+ * discipline instead of queueing.
+ */
+
+ port->tty->low_latency = 1;
+ port->tty->raw = 1;
+ port->tty->real_raw = 1;
+
+ /*
+ * Lose the small buffers usbserial provides. Make larger ones.
+ */
+
+ kfree(port->bulk_in_buffer);
+ kfree(port->bulk_out_buffer);
+ port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
+ if (port->bulk_in_buffer == NULL) {
+ goto enomem;
}
+ port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
+ if (port->bulk_out_buffer == NULL) {
+ kfree(port->bulk_in_buffer);
+ goto enomem;
+ }
+ port->read_urb->transfer_buffer = port->bulk_in_buffer;
+ port->write_urb->transfer_buffer = port->bulk_out_buffer;
+ port->read_urb->transfer_buffer_length = URBDATA_SIZE;
+ port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE;
- up(&port->sem);
-
- return result;
+ /* Start reading from the device */
+ 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);
+ if (result) {
+ err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+ goto error;
+ }
+
+ /*
+ * Send out control message observed in win98 sniffs. Not sure what
+ * it does, but from empirical observations, it seems that the device
+ * will start the chat sequence once one of these messages gets
+ * 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,
+ 0x1, 0, NULL, 0, HZ / 10 + 1);
+ if (result == 0) {
+ return 0;
+ }
+ }
+ err("%s - failed doing control urb, error %d", __FUNCTION__, result);
+ goto error;
enomem:
+ result = -ENOMEM;
+ err("%s - Out of memory", __FUNCTION__);
+error:
ipaq_destroy_lists(port);
kfree(priv);
- err(__FUNCTION__ " - Out of memory");
- return -ENOMEM;
+ return result;
}
@@ -244,37 +240,24 @@
return;
}
- dbg(__FUNCTION__ " - port %d", port->number);
+ dbg("%s - port %d", __FUNCTION__, port->number);
serial = get_usb_serial(port, __FUNCTION__);
if (!serial)
return;
-
- down (&port->sem);
-
- --port->open_count;
- if (port->open_count <= 0) {
+ /*
+ * shut down bulk read and write
+ */
- /*
- * shut down bulk read and write
- */
-
- usb_unlink_urb(port->write_urb);
- usb_unlink_urb(port->read_urb);
- ipaq_destroy_lists(port);
- kfree(priv);
- port->private = NULL;
- port->active = 0;
- port->open_count = 0;
-
- }
- up (&port->sem);
+ usb_unlink_urb(port->write_urb);
+ usb_unlink_urb(port->read_urb);
+ ipaq_destroy_lists(port);
+ kfree(priv);
+ port->private = 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); */
-
- MOD_DEC_USE_COUNT;
}
static void ipaq_read_bulk_callback(struct urb *urb)
@@ -288,15 +271,15 @@
if (port_paranoia_check(port, __FUNCTION__))
return;
- dbg(__FUNCTION__ " - port %d", port->number);
+ dbg("%s - port %d", __FUNCTION__, port->number);
if (!serial) {
- dbg(__FUNCTION__ " - bad serial pointer, exiting");
+ dbg("%s - bad serial pointer, exiting", __FUNCTION__);
return;
}
if (urb->status) {
- dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+ dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
return;
}
@@ -323,7 +306,7 @@
ipaq_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb);
if (result)
- err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+ err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
return;
}
@@ -334,7 +317,7 @@
int bytes_sent = 0;
int transfer_size;
- dbg(__FUNCTION__ " - port %d", port->number);
+ dbg("%s - port %d", __FUNCTION__, port->number);
usb_serial_debug_data(__FILE__, __FUNCTION__, count, buf);
@@ -361,7 +344,7 @@
unsigned long flags;
if (priv->free_len <= 0) {
- dbg(__FUNCTION__ " - we're stuffed");
+ dbg("%s - we're stuffed", __FUNCTION__);
return -EAGAIN;
}
@@ -373,12 +356,13 @@
}
spin_unlock_irqrestore(&write_list_lock, flags);
if (pkt == NULL) {
- dbg(__FUNCTION__ " - we're stuffed");
+ dbg("%s - we're stuffed", __FUNCTION__);
return -EAGAIN;
}
if (from_user) {
- copy_from_user(pkt->data, buf, count);
+ if (copy_from_user(pkt->data, buf, count))
+ return -EFAULT;
} else {
memcpy(pkt->data, buf, count);
}
@@ -395,7 +379,7 @@
spin_unlock_irqrestore(&write_list_lock, flags);
result = usb_submit_urb(port->write_urb);
if (result) {
- err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+ err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
}
} else {
spin_unlock_irqrestore(&write_list_lock, flags);
@@ -414,7 +398,7 @@
if (urb->status == -EINPROGRESS) {
/* Should never happen */
- err(__FUNCTION__ " - flushing while urb is active !");
+ err("%s - flushing while urb is active !", __FUNCTION__);
return;
}
room = URBDATA_SIZE;
@@ -456,10 +440,10 @@
return;
}
- dbg(__FUNCTION__ " - port %d", port->number);
+ dbg("%s - port %d", __FUNCTION__, port->number);
if (urb->status) {
- dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+ dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
}
spin_lock_irqsave(&write_list_lock, flags);
@@ -468,7 +452,7 @@
spin_unlock_irqrestore(&write_list_lock, flags);
result = usb_submit_urb(port->write_urb);
if (result) {
- err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+ err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
}
} else {
priv->active = 0;
@@ -484,7 +468,7 @@
{
struct ipaq_private *priv = (struct ipaq_private *)port->private;
- dbg(__FUNCTION__ " - freelen %d", priv->free_len);
+ dbg("%s - freelen %d", __FUNCTION__, priv->free_len);
return priv->free_len;
}
@@ -492,7 +476,7 @@
{
struct ipaq_private *priv = (struct ipaq_private *)port->private;
- dbg(__FUNCTION__ " - queuelen %d", priv->queue_len);
+ dbg("%s - queuelen %d", __FUNCTION__, priv->queue_len);
return priv->queue_len;
}
@@ -520,23 +504,14 @@
static int ipaq_startup(struct usb_serial *serial)
{
- dbg(__FUNCTION__);
+ dbg("%s", __FUNCTION__);
usb_set_configuration(serial->dev, 1);
return 0;
}
static void ipaq_shutdown(struct usb_serial *serial)
{
- int i;
-
- dbg (__FUNCTION__);
-
- /* stop reads and writes on all ports */
- for (i=0; i < serial->num_ports; ++i) {
- while (serial->port[i].open_count > 0) {
- ipaq_close(&serial->port[i], NULL);
- }
- }
+ dbg("%s", __FUNCTION__);
}
static int __init ipaq_init(void)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)