* USB HandSpring Visor, Palm m50x, and Sony Clie driver
* (supports all of the Palm OS USB devices)
*
- * Copyright (C) 1999 - 2003
+ * Copyright (C) 1999 - 2004
* Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or modify
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
static int palm_os_4_probe (struct usb_serial *serial, const struct usb_device_id *id);
/* Parameters that may be passed into the module. */
-static int vendor = -1;
-static int product = -1;
+static __u16 vendor;
+static __u16 product;
static struct usb_device_id id_table [] = {
{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
+ { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID),
+ .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID),
{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
+ { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID) },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
struct usb_serial *serial = port->serial;
int result = 0;
- if (port_paranoia_check (port, __FUNCTION__))
- return -ENODEV;
-
dbg("%s - port %d", __FUNCTION__, port->number);
if (!port->read_urb) {
static void visor_close (struct usb_serial_port *port, struct file * filp)
{
- struct usb_serial *serial;
unsigned char *transfer_buffer;
- if (port_paranoia_check (port, __FUNCTION__))
- return;
-
dbg("%s - port %d", __FUNCTION__, port->number);
- serial = get_usb_serial (port, __FUNCTION__);
- if (!serial)
- return;
-
/* shutdown our urbs */
usb_unlink_urb (port->read_urb);
if (port->interrupt_in_urb)
/* Try to send shutdown message, if the device is gone, this will just fail. */
transfer_buffer = kmalloc (0x12, GFP_KERNEL);
if (transfer_buffer) {
- usb_control_msg (serial->dev,
- usb_rcvctrlpipe(serial->dev, 0),
+ usb_control_msg (port->serial->dev,
+ usb_rcvctrlpipe(port->serial->dev, 0),
VISOR_CLOSE_NOTIFICATION, 0xc2,
0x0000, 0x0000,
transfer_buffer, 0x12, 300);
/* free up the transfer buffer, as usb_free_urb() does not do this */
kfree (urb->transfer_buffer);
- if (port_paranoia_check (port, __FUNCTION__))
- return;
-
dbg("%s - port %d", __FUNCTION__, port->number);
if (urb->status)
static void visor_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int i;
int result;
- if (port_paranoia_check (port, __FUNCTION__))
- return;
-
dbg("%s - port %d", __FUNCTION__, port->number);
- if (!serial) {
- dbg("%s - bad serial pointer, exiting", __FUNCTION__);
- return;
- }
-
if (urb->status) {
dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
return;
bytes_in += urb->actual_length;
/* Continue trying to always read */
- usb_fill_bulk_urb (port->read_urb, serial->dev,
- usb_rcvbulkpipe (serial->dev,
- port->bulk_in_endpointAddress),
+ 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,
visor_read_bulk_callback, port);
char *string;
int retval = 0;
int i;
- int num_ports;
+ int num_ports = 0;
dbg("%s", __FUNCTION__);
__FUNCTION__, retval);
goto exit;
}
-
- connection_info = (struct visor_connection_info *)transfer_buffer;
-
- le16_to_cpus(&connection_info->num_ports);
- num_ports = connection_info->num_ports;
- /* handle devices that report invalid stuff here */
- if (num_ports > 2)
- num_ports = 2;
- dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
- connection_info->num_ports);
- for (i = 0; i < num_ports; ++i) {
- switch (connection_info->connections[i].port_function_id) {
- case VISOR_FUNCTION_GENERIC:
- string = "Generic";
- break;
- case VISOR_FUNCTION_DEBUGGER:
- string = "Debugger";
- break;
- case VISOR_FUNCTION_HOTSYNC:
- string = "HotSync";
- break;
- case VISOR_FUNCTION_CONSOLE:
- string = "Console";
- break;
- case VISOR_FUNCTION_REMOTE_FILE_SYS:
- string = "Remote File System";
- break;
- default:
- string = "unknown";
- break;
+ if (retval == sizeof(*connection_info)) {
+ connection_info = (struct visor_connection_info *)transfer_buffer;
+
+ le16_to_cpus(&connection_info->num_ports);
+ num_ports = connection_info->num_ports;
+
+ for (i = 0; i < num_ports; ++i) {
+ switch (connection_info->connections[i].port_function_id) {
+ case VISOR_FUNCTION_GENERIC:
+ string = "Generic";
+ break;
+ case VISOR_FUNCTION_DEBUGGER:
+ string = "Debugger";
+ break;
+ case VISOR_FUNCTION_HOTSYNC:
+ string = "HotSync";
+ break;
+ case VISOR_FUNCTION_CONSOLE:
+ string = "Console";
+ break;
+ case VISOR_FUNCTION_REMOTE_FILE_SYS:
+ string = "Remote File System";
+ break;
+ default:
+ string = "unknown";
+ break;
+ }
+ dev_info(dev, "%s: port %d, is for %s use\n",
+ serial->type->name,
+ connection_info->connections[i].port, string);
}
- dev_info(dev, "%s: port %d, is for %s use\n", serial->type->name,
- connection_info->connections[i].port, string);
}
+ /*
+ * Handle devices that report invalid stuff here.
+ */
+ if (num_ports == 0 || num_ports > 2) {
+ dev_warn (dev, "%s: No valid connect info available\n",
+ serial->type->name);
+ num_ports = 2;
+ }
+
+ dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
+ num_ports);
/*
* save off our num_ports info so that we can use it in the
static int treo_attach (struct usb_serial *serial)
{
- struct usb_serial_port *port;
- int i;
+ struct usb_serial_port *swap_port;
/* Only do this endpoint hack for the Handspring devices with
* interrupt in endpoints, which for now are the Treo devices. */
dbg("%s", __FUNCTION__);
- /* Ok, this is pretty ugly, but these devices want to use the
- * interrupt endpoint as paired up with a bulk endpoint for a
- * "virtual serial port". So let's force the endpoints to be
- * where we want them to be. */
- for (i = serial->num_bulk_in; i < serial->num_ports; ++i) {
- port = serial->port[i];
- port->read_urb = serial->port[0]->read_urb;
- port->bulk_in_endpointAddress = serial->port[0]->bulk_in_endpointAddress;
- port->bulk_in_buffer = serial->port[0]->bulk_in_buffer;
- }
-
- for (i = serial->num_bulk_out; i < serial->num_ports; ++i) {
- port = serial->port[i];
- port->write_urb = serial->port[0]->write_urb;
- port->bulk_out_size = serial->port[0]->bulk_out_size;
- port->bulk_out_endpointAddress = serial->port[0]->bulk_out_endpointAddress;
- port->bulk_out_buffer = serial->port[0]->bulk_out_buffer;
- }
-
- for (i = serial->num_interrupt_in; i < serial->num_ports; ++i) {
- port = serial->port[i];
- port->interrupt_in_urb = serial->port[0]->interrupt_in_urb;
- port->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;
- port->interrupt_in_buffer = serial->port[0]->interrupt_in_buffer;
- }
+ /*
+ * It appears that Treos want to use the 1st interrupt endpoint to
+ * communicate with the 2nd bulk out endpoint, so let's swap the 1st
+ * and 2nd bulk in and interrupt endpoints. Note that swapping the
+ * bulk out endpoints would break lots of apps that want to communicate
+ * on the second port.
+ */
+#define COPY_PORT(dest, src) \
+ dest->read_urb = src->read_urb; \
+ dest->bulk_in_endpointAddress = src->bulk_in_endpointAddress; \
+ dest->bulk_in_buffer = src->bulk_in_buffer; \
+ dest->interrupt_in_urb = src->interrupt_in_urb; \
+ dest->interrupt_in_endpointAddress = src->interrupt_in_endpointAddress; \
+ dest->interrupt_in_buffer = src->interrupt_in_buffer;
+
+ swap_port = kmalloc(sizeof(*swap_port), GFP_KERNEL);
+ if (!swap_port)
+ return -ENOMEM;
+ COPY_PORT(swap_port, serial->port[0]);
+ COPY_PORT(serial->port[0], serial->port[1]);
+ COPY_PORT(serial->port[1], swap_port);
+ kfree(swap_port);
return 0;
}
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
-MODULE_PARM(debug, "i");
+module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
-MODULE_PARM(vendor, "i");
+module_param(vendor, ushort, 0);
MODULE_PARM_DESC(vendor, "User specified vendor ID");
-MODULE_PARM(product, "i");
+module_param(product, ushort, 0);
MODULE_PARM_DESC(product, "User specified product ID");