visor.c 29.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7
/*
 * USB HandSpring Visor, Palm m50x, and Sony Clie driver
 * (supports all of the Palm OS USB devices)
 *
 *	Copyright (C) 1999 - 2004
 *	    Greg Kroah-Hartman (greg@kroah.com)
 *
8 9 10
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License version
 *	2 as published by the Free Software Foundation.
L
Linus Torvalds 已提交
11
 *
A
Alan Cox 已提交
12 13
 * See Documentation/usb/usb-serial.txt for more information on using this
 * driver
L
Linus Torvalds 已提交
14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 */

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
A
Alan Cox 已提交
27
#include <linux/uaccess.h>
L
Linus Torvalds 已提交
28
#include <linux/usb.h>
29
#include <linux/usb/serial.h>
L
Linus Torvalds 已提交
30 31 32 33 34 35 36 37 38
#include "visor.h"

/*
 * Version Information
 */
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
#define DRIVER_DESC "USB HandSpring Visor / Palm OS driver"

/* function prototypes for a handspring visor */
A
Alan Cox 已提交
39 40 41 42 43 44 45 46 47 48 49
static int  visor_open(struct tty_struct *tty, struct usb_serial_port *port,
					struct file *filp);
static void visor_close(struct tty_struct *tty, struct usb_serial_port *port,
					struct file *filp);
static int  visor_write(struct tty_struct *tty, struct usb_serial_port *port,
					const unsigned char *buf, int count);
static int  visor_write_room(struct tty_struct *tty);
static void visor_throttle(struct tty_struct *tty);
static void visor_unthrottle(struct tty_struct *tty);
static int  visor_probe(struct usb_serial *serial,
					const struct usb_device_id *id);
L
Linus Torvalds 已提交
50
static int  visor_calc_num_ports(struct usb_serial *serial);
A
Alan Cox 已提交
51 52 53 54 55 56 57 58 59 60 61
static void visor_shutdown(struct usb_serial *serial);
static void visor_write_bulk_callback(struct urb *urb);
static void visor_read_bulk_callback(struct urb *urb);
static void visor_read_int_callback(struct urb *urb);
static int  clie_3_5_startup(struct usb_serial *serial);
static int  treo_attach(struct usb_serial *serial);
static int clie_5_attach(struct usb_serial *serial);
static int palm_os_3_probe(struct usb_serial *serial,
					const struct usb_device_id *id);
static int palm_os_4_probe(struct usb_serial *serial,
					const struct usb_device_id *id);
L
Linus Torvalds 已提交
62 63 64 65 66 67 68 69 70 71 72 73 74

/* Parameters that may be passed into the module. */
static int debug;
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_3_probe },
	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO600_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
75 76
	{ USB_DEVICE(GSPDA_VENDOR_ID, GSPDA_XPLORE_M68_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
L
Linus Torvalds 已提交
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M100_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
93 94
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
L
Linus Torvalds 已提交
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_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),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
111 112
	{ USB_DEVICE(ACER_VENDOR_ID, ACER_S10_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
A
Alan Cox 已提交
113
	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID),
L
Linus Torvalds 已提交
114
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
A
Alan Cox 已提交
115
	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID),
L
Linus Torvalds 已提交
116
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
117 118
	{ USB_DEVICE(TAPWAVE_VENDOR_ID, TAPWAVE_ZODIAC_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
A
Alan Cox 已提交
119
	{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID),
L
Linus Torvalds 已提交
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ },					/* optional parameter entry */
	{ }					/* Terminating entry */
};

static struct usb_device_id clie_id_5_table [] = {
	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
	{ },					/* optional parameter entry */
	{ }					/* Terminating entry */
};

static struct usb_device_id clie_id_3_5_table [] = {
	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
	{ }					/* Terminating entry */
};

static struct usb_device_id id_table_combined [] = {
	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID) },
	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO600_ID) },
147
	{ USB_DEVICE(GSPDA_VENDOR_ID, GSPDA_XPLORE_M68_ID) },
L
Linus Torvalds 已提交
148 149 150 151 152 153 154 155
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M100_ID) },
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
156
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) },
L
Linus Torvalds 已提交
157 158 159 160 161 162 163 164 165 166 167 168
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_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) },
	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) },
	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID) },
	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID) },
	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID) },
	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) },
	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID) },
169
	{ USB_DEVICE(TAPWAVE_VENDOR_ID, TAPWAVE_ZODIAC_ID) },
L
Linus Torvalds 已提交
170 171 172 173 174 175 176 177
	{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) },
	{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) },
	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID) },
	{ USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID) },
	{ },					/* optional parameter entry */
	{ }					/* Terminating entry */
};

A
Alan Cox 已提交
178
MODULE_DEVICE_TABLE(usb, id_table_combined);
L
Linus Torvalds 已提交
179 180 181 182 183 184

static struct usb_driver visor_driver = {
	.name =		"visor",
	.probe =	usb_serial_probe,
	.disconnect =	usb_serial_disconnect,
	.id_table =	id_table_combined,
185
	.no_dynamic_id = 	1,
L
Linus Torvalds 已提交
186 187
};

A
Alan Cox 已提交
188 189
/* All of the device info needed for the Handspring Visor,
   and Palm 4.0 devices */
190
static struct usb_serial_driver handspring_device = {
191 192
	.driver = {
		.owner =	THIS_MODULE,
193
		.name =		"visor",
194
	},
195
	.description =		"Handspring Visor / Palm OS",
196
	.usb_driver =		&visor_driver,
L
Linus Torvalds 已提交
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
	.id_table =		id_table,
	.num_ports =		2,
	.open =			visor_open,
	.close =		visor_close,
	.throttle =		visor_throttle,
	.unthrottle =		visor_unthrottle,
	.attach =		treo_attach,
	.probe =		visor_probe,
	.calc_num_ports =	visor_calc_num_ports,
	.shutdown =		visor_shutdown,
	.write =		visor_write,
	.write_room =		visor_write_room,
	.write_bulk_callback =	visor_write_bulk_callback,
	.read_bulk_callback =	visor_read_bulk_callback,
	.read_int_callback =	visor_read_int_callback,
};

/* All of the device info needed for the Clie UX50, TH55 Palm 5.0 devices */
215
static struct usb_serial_driver clie_5_device = {
216 217
	.driver = {
		.owner =	THIS_MODULE,
218
		.name =		"clie_5",
219
	},
220
	.description =		"Sony Clie 5.0",
221
	.usb_driver =		&visor_driver,
L
Linus Torvalds 已提交
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
	.id_table =		clie_id_5_table,
	.num_ports =		2,
	.open =			visor_open,
	.close =		visor_close,
	.throttle =		visor_throttle,
	.unthrottle =		visor_unthrottle,
	.attach =		clie_5_attach,
	.probe =		visor_probe,
	.calc_num_ports =	visor_calc_num_ports,
	.shutdown =		visor_shutdown,
	.write =		visor_write,
	.write_room =		visor_write_room,
	.write_bulk_callback =	visor_write_bulk_callback,
	.read_bulk_callback =	visor_read_bulk_callback,
	.read_int_callback =	visor_read_int_callback,
};

/* device info for the Sony Clie OS version 3.5 */
240
static struct usb_serial_driver clie_3_5_device = {
241 242
	.driver = {
		.owner =	THIS_MODULE,
243
		.name =		"clie_3.5",
244
	},
245
	.description =		"Sony Clie 3.5",
246
	.usb_driver =		&visor_driver,
L
Linus Torvalds 已提交
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
	.id_table =		clie_id_3_5_table,
	.num_ports =		1,
	.open =			visor_open,
	.close =		visor_close,
	.throttle =		visor_throttle,
	.unthrottle =		visor_unthrottle,
	.attach =		clie_3_5_startup,
	.write =		visor_write,
	.write_room =		visor_write_room,
	.write_bulk_callback =	visor_write_bulk_callback,
	.read_bulk_callback =	visor_read_bulk_callback,
};

struct visor_private {
	spinlock_t lock;
	int bytes_in;
	int bytes_out;
	int outstanding_urbs;
265 266
	unsigned char throttled;
	unsigned char actually_throttled;
L
Linus Torvalds 已提交
267 268 269 270 271 272 273 274 275 276
};

/* number of outstanding urbs to prevent userspace DoS from happening */
#define URB_UPPER_LIMIT	42

static int stats;

/******************************************************************************
 * Handspring Visor specific driver functions
 ******************************************************************************/
A
Alan Cox 已提交
277 278
static int visor_open(struct tty_struct *tty, struct usb_serial_port *port,
							struct file *filp)
L
Linus Torvalds 已提交
279 280 281 282 283 284
{
	struct usb_serial *serial = port->serial;
	struct visor_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;
	int result = 0;

285
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303

	if (!port->read_urb) {
		/* this is needed for some brain dead Sony devices */
		dev_err(&port->dev, "Device lied about number of ports, please use a lower one.\n");
		return -ENODEV;
	}

	spin_lock_irqsave(&priv->lock, flags);
	priv->bytes_in = 0;
	priv->bytes_out = 0;
	priv->throttled = 0;
	spin_unlock_irqrestore(&priv->lock, flags);

	/*
	 * Force low_latency on so that our tty_push actually forces the data
	 * through, otherwise it is scheduled, and with high data rates (like
	 * with OHCI) data can get lost.
	 */
A
Alan Cox 已提交
304 305
	if (tty)
		tty->low_latency = 1;
L
Linus Torvalds 已提交
306 307

	/* Start reading from the device */
A
Alan Cox 已提交
308 309
	usb_fill_bulk_urb(port->read_urb, serial->dev,
			   usb_rcvbulkpipe(serial->dev,
L
Linus Torvalds 已提交
310 311 312 313 314 315
					    port->bulk_in_endpointAddress),
			   port->read_urb->transfer_buffer,
			   port->read_urb->transfer_buffer_length,
			   visor_read_bulk_callback, port);
	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
	if (result) {
A
Alan Cox 已提交
316 317 318
		dev_err(&port->dev,
			"%s - failed submitting read urb, error %d\n",
							__func__, result);
L
Linus Torvalds 已提交
319 320
		goto exit;
	}
A
Alan Cox 已提交
321

L
Linus Torvalds 已提交
322
	if (port->interrupt_in_urb) {
323
		dbg("%s - adding interrupt input for treo", __func__);
L
Linus Torvalds 已提交
324 325
		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
		if (result)
A
Alan Cox 已提交
326 327 328
			dev_err(&port->dev,
			    "%s - failed submitting interrupt urb, error %d\n",
							__func__, result);
L
Linus Torvalds 已提交
329
	}
A
Alan Cox 已提交
330
exit:
L
Linus Torvalds 已提交
331 332 333 334
	return result;
}


A
Alan Cox 已提交
335
static void visor_close(struct tty_struct *tty,
A
Alan Cox 已提交
336
			struct usb_serial_port *port, struct file *filp)
L
Linus Torvalds 已提交
337 338 339 340
{
	struct visor_private *priv = usb_get_serial_port_data(port);
	unsigned char *transfer_buffer;

341
	dbg("%s - port %d", __func__, port->number);
A
Alan Cox 已提交
342

L
Linus Torvalds 已提交
343 344
	/* shutdown our urbs */
	usb_kill_urb(port->read_urb);
M
Mariusz Kozlowski 已提交
345
	usb_kill_urb(port->interrupt_in_urb);
L
Linus Torvalds 已提交
346

347 348 349
	mutex_lock(&port->serial->disc_mutex);
	if (!port->serial->disconnected) {
		/* Try to send shutdown message, unless the device is gone */
A
Alan Cox 已提交
350
		transfer_buffer =  kmalloc(0x12, GFP_KERNEL);
351
		if (transfer_buffer) {
A
Alan Cox 已提交
352
			usb_control_msg(port->serial->dev,
353 354 355 356
					 usb_rcvctrlpipe(port->serial->dev, 0),
					 VISOR_CLOSE_NOTIFICATION, 0xc2,
					 0x0000, 0x0000,
					 transfer_buffer, 0x12, 300);
A
Alan Cox 已提交
357
			kfree(transfer_buffer);
358
		}
L
Linus Torvalds 已提交
359
	}
360
	mutex_unlock(&port->serial->disc_mutex);
L
Linus Torvalds 已提交
361 362 363 364 365 366 367

	if (stats)
		dev_info(&port->dev, "Bytes In = %d  Bytes Out = %d\n",
			 priv->bytes_in, priv->bytes_out);
}


A
Alan Cox 已提交
368 369
static int visor_write(struct tty_struct *tty, struct usb_serial_port *port,
					const unsigned char *buf, int count)
L
Linus Torvalds 已提交
370 371 372 373 374 375 376 377
{
	struct visor_private *priv = usb_get_serial_port_data(port);
	struct usb_serial *serial = port->serial;
	struct urb *urb;
	unsigned char *buffer;
	unsigned long flags;
	int status;

378
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
379 380 381 382

	spin_lock_irqsave(&priv->lock, flags);
	if (priv->outstanding_urbs > URB_UPPER_LIMIT) {
		spin_unlock_irqrestore(&priv->lock, flags);
383
		dbg("%s - write limit hit\n", __func__);
L
Linus Torvalds 已提交
384 385
		return 0;
	}
O
Oliver Neukum 已提交
386
	priv->outstanding_urbs++;
L
Linus Torvalds 已提交
387 388
	spin_unlock_irqrestore(&priv->lock, flags);

A
Alan Cox 已提交
389
	buffer = kmalloc(count, GFP_ATOMIC);
L
Linus Torvalds 已提交
390 391
	if (!buffer) {
		dev_err(&port->dev, "out of memory\n");
O
Oliver Neukum 已提交
392 393
		count = -ENOMEM;
		goto error_no_buffer;
L
Linus Torvalds 已提交
394 395 396 397 398
	}

	urb = usb_alloc_urb(0, GFP_ATOMIC);
	if (!urb) {
		dev_err(&port->dev, "no more free urbs\n");
O
Oliver Neukum 已提交
399 400
		count = -ENOMEM;
		goto error_no_urb;
L
Linus Torvalds 已提交
401 402
	}

A
Alan Cox 已提交
403
	memcpy(buffer, buf, count);
L
Linus Torvalds 已提交
404

405
	usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
L
Linus Torvalds 已提交
406

A
Alan Cox 已提交
407 408
	usb_fill_bulk_urb(urb, serial->dev,
			   usb_sndbulkpipe(serial->dev,
L
Linus Torvalds 已提交
409
					    port->bulk_out_endpointAddress),
A
Alan Cox 已提交
410
			   buffer, count,
L
Linus Torvalds 已提交
411 412 413 414 415
			   visor_write_bulk_callback, port);

	/* send it down the pipe */
	status = usb_submit_urb(urb, GFP_ATOMIC);
	if (status) {
A
Alan Cox 已提交
416 417 418
		dev_err(&port->dev,
		   "%s - usb_submit_urb(write bulk) failed with status = %d\n",
							__func__, status);
L
Linus Torvalds 已提交
419
		count = status;
O
Oliver Neukum 已提交
420
		goto error;
L
Linus Torvalds 已提交
421 422 423 424 425 426 427 428
	} else {
		spin_lock_irqsave(&priv->lock, flags);
		priv->bytes_out += count;
		spin_unlock_irqrestore(&priv->lock, flags);
	}

	/* we are done with this urb, so let the host driver
	 * really free it when it is finished with it */
O
Oliver Neukum 已提交
429
	usb_free_urb(urb);
L
Linus Torvalds 已提交
430

O
Oliver Neukum 已提交
431 432 433 434 435 436 437 438 439
	return count;
error:
	usb_free_urb(urb);
error_no_urb:
	kfree(buffer);
error_no_buffer:
	spin_lock_irqsave(&priv->lock, flags);
	--priv->outstanding_urbs;
	spin_unlock_irqrestore(&priv->lock, flags);
L
Linus Torvalds 已提交
440 441 442 443
	return count;
}


A
Alan Cox 已提交
444
static int visor_write_room(struct tty_struct *tty)
L
Linus Torvalds 已提交
445
{
A
Alan Cox 已提交
446
	struct usb_serial_port *port = tty->driver_data;
P
Pete Zaitcev 已提交
447 448 449
	struct visor_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;

450
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
451 452 453 454

	/*
	 * We really can take anything the user throws at us
	 * but let's pick a nice big number to tell the tty
P
Pete Zaitcev 已提交
455
	 * layer that we have lots of free space, unless we don't.
L
Linus Torvalds 已提交
456
	 */
P
Pete Zaitcev 已提交
457 458 459 460

	spin_lock_irqsave(&priv->lock, flags);
	if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) {
		spin_unlock_irqrestore(&priv->lock, flags);
461
		dbg("%s - write limit hit\n", __func__);
P
Pete Zaitcev 已提交
462 463 464 465
		return 0;
	}
	spin_unlock_irqrestore(&priv->lock, flags);

L
Linus Torvalds 已提交
466 467 468 469
	return 2048;
}


A
Alan Cox 已提交
470
static void visor_write_bulk_callback(struct urb *urb)
L
Linus Torvalds 已提交
471
{
472
	struct usb_serial_port *port = urb->context;
L
Linus Torvalds 已提交
473
	struct visor_private *priv = usb_get_serial_port_data(port);
474
	int status = urb->status;
L
Linus Torvalds 已提交
475 476 477
	unsigned long flags;

	/* free up the transfer buffer, as usb_free_urb() does not do this */
A
Alan Cox 已提交
478
	kfree(urb->transfer_buffer);
L
Linus Torvalds 已提交
479

480
	dbg("%s - port %d", __func__, port->number);
481 482

	if (status)
L
Linus Torvalds 已提交
483
		dbg("%s - nonzero write bulk status received: %d",
484
		    __func__, status);
L
Linus Torvalds 已提交
485 486 487 488 489

	spin_lock_irqsave(&priv->lock, flags);
	--priv->outstanding_urbs;
	spin_unlock_irqrestore(&priv->lock, flags);

490
	usb_serial_port_softint(port);
L
Linus Torvalds 已提交
491 492 493
}


A
Alan Cox 已提交
494
static void visor_read_bulk_callback(struct urb *urb)
L
Linus Torvalds 已提交
495
{
496
	struct usb_serial_port *port = urb->context;
L
Linus Torvalds 已提交
497 498
	struct visor_private *priv = usb_get_serial_port_data(port);
	unsigned char *data = urb->transfer_buffer;
499
	int status = urb->status;
L
Linus Torvalds 已提交
500 501
	struct tty_struct *tty;
	int result;
A
Alan Cox 已提交
502
	int available_room = 0;
L
Linus Torvalds 已提交
503

504
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
505

506 507
	if (status) {
		dbg("%s - nonzero read bulk status received: %d",
508
		    __func__, status);
L
Linus Torvalds 已提交
509 510 511
		return;
	}

A
Alan Cox 已提交
512 513
	usb_serial_debug_data(debug, &port->dev, __func__,
						urb->actual_length, data);
L
Linus Torvalds 已提交
514

A
Alan Cox 已提交
515 516 517 518
	if (urb->actual_length) {
		tty = tty_port_tty_get(&port->port);
		if (tty) {
			available_room = tty_buffer_request_room(tty,
A
Alan Cox 已提交
519
							urb->actual_length);
A
Alan Cox 已提交
520 521 522 523 524 525
			if (available_room) {
				tty_insert_flip_string(tty, data,
							available_room);
				tty_flip_buffer_push(tty);
			}
			tty_kref_put(tty);
526 527 528 529 530 531
		}
		spin_lock(&priv->lock);
		priv->bytes_in += available_room;

	} else {
		spin_lock(&priv->lock);
L
Linus Torvalds 已提交
532 533 534
	}

	/* Continue trying to always read if we should */
535
	if (!priv->throttled) {
A
Alan Cox 已提交
536
		usb_fill_bulk_urb(port->read_urb, port->serial->dev,
L
Linus Torvalds 已提交
537
				   usb_rcvbulkpipe(port->serial->dev,
A
Alan Cox 已提交
538
					   port->bulk_in_endpointAddress),
L
Linus Torvalds 已提交
539 540 541 542 543
				   port->read_urb->transfer_buffer,
				   port->read_urb->transfer_buffer_length,
				   visor_read_bulk_callback, port);
		result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
		if (result)
A
Alan Cox 已提交
544 545 546 547
			dev_err(&port->dev,
			    "%s - failed resubmitting read urb, error %d\n",
							__func__, result);
	} else
548 549
		priv->actually_throttled = 1;
	spin_unlock(&priv->lock);
L
Linus Torvalds 已提交
550 551
}

A
Alan Cox 已提交
552
static void visor_read_int_callback(struct urb *urb)
L
Linus Torvalds 已提交
553
{
554
	struct usb_serial_port *port = urb->context;
555
	int status = urb->status;
L
Linus Torvalds 已提交
556 557
	int result;

558
	switch (status) {
L
Linus Torvalds 已提交
559 560 561 562 563 564 565 566
	case 0:
		/* success */
		break;
	case -ECONNRESET:
	case -ENOENT:
	case -ESHUTDOWN:
		/* this urb is terminated, clean up */
		dbg("%s - urb shutting down with status: %d",
567
		    __func__, status);
L
Linus Torvalds 已提交
568 569 570
		return;
	default:
		dbg("%s - nonzero urb status received: %d",
571
		    __func__, status);
L
Linus Torvalds 已提交
572 573 574 575 576 577 578 579 580 581
		goto exit;
	}

	/*
	 * This information is still unknown what it can be used for.
	 * If anyone has an idea, please let the author know...
	 *
	 * Rumor has it this endpoint is used to notify when data
	 * is ready to be read from the bulk ones.
	 */
582
	usb_serial_debug_data(debug, &port->dev, __func__,
L
Linus Torvalds 已提交
583 584 585
			      urb->actual_length, urb->transfer_buffer);

exit:
A
Alan Cox 已提交
586
	result = usb_submit_urb(urb, GFP_ATOMIC);
L
Linus Torvalds 已提交
587
	if (result)
A
Alan Cox 已提交
588 589 590
		dev_err(&urb->dev->dev,
				"%s - Error %d submitting interrupt urb\n",
							__func__, result);
L
Linus Torvalds 已提交
591 592
}

A
Alan Cox 已提交
593
static void visor_throttle(struct tty_struct *tty)
L
Linus Torvalds 已提交
594
{
A
Alan Cox 已提交
595
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
596 597 598
	struct visor_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;

599
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
600 601 602 603 604 605
	spin_lock_irqsave(&priv->lock, flags);
	priv->throttled = 1;
	spin_unlock_irqrestore(&priv->lock, flags);
}


A
Alan Cox 已提交
606
static void visor_unthrottle(struct tty_struct *tty)
L
Linus Torvalds 已提交
607
{
A
Alan Cox 已提交
608
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
609 610 611 612
	struct visor_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;
	int result;

613
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
614 615
	spin_lock_irqsave(&priv->lock, flags);
	priv->throttled = 0;
616
	priv->actually_throttled = 0;
L
Linus Torvalds 已提交
617 618 619 620 621
	spin_unlock_irqrestore(&priv->lock, flags);

	port->read_urb->dev = port->serial->dev;
	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
	if (result)
A
Alan Cox 已提交
622 623 624
		dev_err(&port->dev,
			"%s - failed submitting read urb, error %d\n",
							__func__, result);
L
Linus Torvalds 已提交
625 626
}

A
Alan Cox 已提交
627 628
static int palm_os_3_probe(struct usb_serial *serial,
						const struct usb_device_id *id)
L
Linus Torvalds 已提交
629 630 631 632 633 634 635 636 637
{
	struct device *dev = &serial->dev->dev;
	struct visor_connection_info *connection_info;
	unsigned char *transfer_buffer;
	char *string;
	int retval = 0;
	int i;
	int num_ports = 0;

638
	dbg("%s", __func__);
L
Linus Torvalds 已提交
639

A
Alan Cox 已提交
640
	transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL);
L
Linus Torvalds 已提交
641
	if (!transfer_buffer) {
642
		dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__,
L
Linus Torvalds 已提交
643 644 645 646 647
			sizeof(*connection_info));
		return -ENOMEM;
	}

	/* send a get connection info request */
A
Alan Cox 已提交
648
	retval = usb_control_msg(serial->dev,
L
Linus Torvalds 已提交
649 650 651 652 653 654
				  usb_rcvctrlpipe(serial->dev, 0),
				  VISOR_GET_CONNECTION_INFORMATION,
				  0xc2, 0x0000, 0x0000, transfer_buffer,
				  sizeof(*connection_info), 300);
	if (retval < 0) {
		dev_err(dev, "%s - error %d getting connection information\n",
655
			__func__, retval);
L
Linus Torvalds 已提交
656 657 658 659
		goto exit;
	}

	if (retval == sizeof(*connection_info)) {
A
Alan Cox 已提交
660 661
			connection_info = (struct visor_connection_info *)
							transfer_buffer;
L
Linus Torvalds 已提交
662 663 664

		num_ports = le16_to_cpu(connection_info->num_ports);
		for (i = 0; i < num_ports; ++i) {
A
Alan Cox 已提交
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
			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;
L
Linus Torvalds 已提交
685 686
			}
			dev_info(dev, "%s: port %d, is for %s use\n",
687
				serial->type->description,
L
Linus Torvalds 已提交
688 689 690 691 692 693 694
				connection_info->connections[i].port, string);
		}
	}
	/*
	* Handle devices that report invalid stuff here.
	*/
	if (num_ports == 0 || num_ports > 2) {
A
Alan Cox 已提交
695
		dev_warn(dev, "%s: No valid connect info available\n",
696
			serial->type->description);
L
Linus Torvalds 已提交
697 698
		num_ports = 2;
	}
A
Alan Cox 已提交
699

700
	dev_info(dev, "%s: Number of ports: %d\n", serial->type->description,
L
Linus Torvalds 已提交
701 702 703 704 705 706 707 708
		num_ports);

	/*
	 * save off our num_ports info so that we can use it in the
	 * calc_num_ports callback
	 */
	usb_set_serial_data(serial, (void *)(long)num_ports);

A
Alan Cox 已提交
709 710 711
	/* ask for the number of bytes available, but ignore the
	   response as it is broken */
	retval = usb_control_msg(serial->dev,
L
Linus Torvalds 已提交
712 713 714 715 716 717
				  usb_rcvctrlpipe(serial->dev, 0),
				  VISOR_REQUEST_BYTES_AVAILABLE,
				  0xc2, 0x0000, 0x0005, transfer_buffer,
				  0x02, 300);
	if (retval < 0)
		dev_err(dev, "%s - error %d getting bytes available request\n",
718
			__func__, retval);
L
Linus Torvalds 已提交
719 720 721
	retval = 0;

exit:
A
Alan Cox 已提交
722
	kfree(transfer_buffer);
L
Linus Torvalds 已提交
723 724 725 726

	return retval;
}

A
Alan Cox 已提交
727 728
static int palm_os_4_probe(struct usb_serial *serial,
						const struct usb_device_id *id)
L
Linus Torvalds 已提交
729 730 731 732 733 734
{
	struct device *dev = &serial->dev->dev;
	struct palm_ext_connection_info *connection_info;
	unsigned char *transfer_buffer;
	int retval;

735
	dbg("%s", __func__);
L
Linus Torvalds 已提交
736

A
Alan Cox 已提交
737
	transfer_buffer =  kmalloc(sizeof(*connection_info), GFP_KERNEL);
L
Linus Torvalds 已提交
738
	if (!transfer_buffer) {
739
		dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__,
L
Linus Torvalds 已提交
740 741 742 743
			sizeof(*connection_info));
		return -ENOMEM;
	}

A
Alan Cox 已提交
744 745
	retval = usb_control_msg(serial->dev,
				  usb_rcvctrlpipe(serial->dev, 0),
L
Linus Torvalds 已提交
746 747
				  PALM_GET_EXT_CONNECTION_INFORMATION,
				  0xc2, 0x0000, 0x0000, transfer_buffer,
A
Alan Cox 已提交
748
				  sizeof(*connection_info), 300);
L
Linus Torvalds 已提交
749 750
	if (retval < 0)
		dev_err(dev, "%s - error %d getting connection info\n",
751
			__func__, retval);
L
Linus Torvalds 已提交
752
	else
753
		usb_serial_debug_data(debug, &serial->dev->dev, __func__,
L
Linus Torvalds 已提交
754 755
				      retval, transfer_buffer);

A
Alan Cox 已提交
756
	kfree(transfer_buffer);
L
Linus Torvalds 已提交
757 758 759 760
	return 0;
}


A
Alan Cox 已提交
761 762
static int visor_probe(struct usb_serial *serial,
					const struct usb_device_id *id)
L
Linus Torvalds 已提交
763 764
{
	int retval = 0;
A
Alan Cox 已提交
765 766
	int (*startup)(struct usb_serial *serial,
					const struct usb_device_id *id);
L
Linus Torvalds 已提交
767

768
	dbg("%s", __func__);
L
Linus Torvalds 已提交
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783

	if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
		err("active config #%d != 1 ??",
			serial->dev->actconfig->desc.bConfigurationValue);
		return -ENODEV;
	}

	if (id->driver_info) {
		startup = (void *)id->driver_info;
		retval = startup(serial, id);
	}

	return retval;
}

A
Alan Cox 已提交
784
static int visor_calc_num_ports(struct usb_serial *serial)
L
Linus Torvalds 已提交
785 786 787 788 789 790 791 792 793 794 795
{
	int num_ports = (int)(long)(usb_get_serial_data(serial));

	if (num_ports)
		usb_set_serial_data(serial, NULL);

	return num_ports;
}

static int generic_startup(struct usb_serial *serial)
{
P
Pete Zaitcev 已提交
796
	struct usb_serial_port **ports = serial->port;
L
Linus Torvalds 已提交
797 798 799 800
	struct visor_private *priv;
	int i;

	for (i = 0; i < serial->num_ports; ++i) {
A
Alan Cox 已提交
801
		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
P
Pete Zaitcev 已提交
802 803 804 805 806 807
		if (!priv) {
			while (i-- != 0) {
				priv = usb_get_serial_port_data(ports[i]);
				usb_set_serial_port_data(ports[i], NULL);
				kfree(priv);
			}
L
Linus Torvalds 已提交
808
			return -ENOMEM;
P
Pete Zaitcev 已提交
809
		}
L
Linus Torvalds 已提交
810
		spin_lock_init(&priv->lock);
P
Pete Zaitcev 已提交
811
		usb_set_serial_port_data(ports[i], priv);
L
Linus Torvalds 已提交
812 813 814 815
	}
	return 0;
}

A
Alan Cox 已提交
816
static int clie_3_5_startup(struct usb_serial *serial)
L
Linus Torvalds 已提交
817 818 819 820 821
{
	struct device *dev = &serial->dev->dev;
	int result;
	u8 data;

822
	dbg("%s", __func__);
L
Linus Torvalds 已提交
823 824 825 826 827 828

	/*
	 * Note that PEG-300 series devices expect the following two calls.
	 */

	/* get the config number */
A
Alan Cox 已提交
829
	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
L
Linus Torvalds 已提交
830 831 832
				  USB_REQ_GET_CONFIGURATION, USB_DIR_IN,
				  0, 0, &data, 1, 3000);
	if (result < 0) {
A
Alan Cox 已提交
833 834
		dev_err(dev, "%s: get config number failed: %d\n",
							__func__, result);
L
Linus Torvalds 已提交
835 836 837
		return result;
	}
	if (result != 1) {
A
Alan Cox 已提交
838 839
		dev_err(dev, "%s: get config number bad return length: %d\n",
							__func__, result);
L
Linus Torvalds 已提交
840 841 842 843
		return -EIO;
	}

	/* get the interface number */
A
Alan Cox 已提交
844 845
	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
				  USB_REQ_GET_INTERFACE,
L
Linus Torvalds 已提交
846 847 848
				  USB_DIR_IN | USB_RECIP_INTERFACE,
				  0, 0, &data, 1, 3000);
	if (result < 0) {
A
Alan Cox 已提交
849 850
		dev_err(dev, "%s: get interface number failed: %d\n",
							__func__, result);
L
Linus Torvalds 已提交
851 852 853
		return result;
	}
	if (result != 1) {
A
Alan Cox 已提交
854 855 856
		dev_err(dev,
			"%s: get interface number bad return length: %d\n",
							__func__, result);
L
Linus Torvalds 已提交
857 858 859 860 861
		return -EIO;
	}

	return generic_startup(serial);
}
A
Alan Cox 已提交
862 863

static int treo_attach(struct usb_serial *serial)
L
Linus Torvalds 已提交
864 865 866 867 868
{
	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. */
A
Alan Cox 已提交
869 870 871 872 873
	if (!((le16_to_cpu(serial->dev->descriptor.idVendor)
						== HANDSPRING_VENDOR_ID) ||
		(le16_to_cpu(serial->dev->descriptor.idVendor)
						== KYOCERA_VENDOR_ID)) ||
		(serial->num_interrupt_in == 0))
L
Linus Torvalds 已提交
874 875
		goto generic_startup;

876
	dbg("%s", __func__);
L
Linus Torvalds 已提交
877 878

	/*
A
Alan Cox 已提交
879 880 881 882
	* It appears that Treos and Kyoceras want to use the
	* 1st bulk in 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
L
Linus Torvalds 已提交
883 884 885
	* apps that want to communicate on the second port.
	*/
#define COPY_PORT(dest, src)						\
A
Alan Cox 已提交
886 887 888 889 890 891 892 893 894
	do { \
		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;	\
	} while (0);
L
Linus Torvalds 已提交
895 896 897 898 899 900 901 902 903 904 905 906 907

	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);

generic_startup:
	return generic_startup(serial);
}

A
Alan Cox 已提交
908
static int clie_5_attach(struct usb_serial *serial)
L
Linus Torvalds 已提交
909
{
910
	dbg("%s", __func__);
L
Linus Torvalds 已提交
911

A
Alan Cox 已提交
912 913 914 915 916
	/* TH55 registers 2 ports.
	   Communication in from the UX50/TH55 uses bulk_in_endpointAddress
	   from port 0. Communication out to the UX50/TH55 uses
	   bulk_out_endpointAddress from port 1

L
Linus Torvalds 已提交
917 918
	   Lets do a quick and dirty mapping
	 */
A
Alan Cox 已提交
919

L
Linus Torvalds 已提交
920 921 922
	/* some sanity check */
	if (serial->num_ports < 2)
		return -1;
A
Alan Cox 已提交
923

L
Linus Torvalds 已提交
924
	/* port 0 now uses the modified endpoint Address */
A
Alan Cox 已提交
925 926
	serial->port[0]->bulk_out_endpointAddress =
				serial->port[1]->bulk_out_endpointAddress;
L
Linus Torvalds 已提交
927 928 929 930

	return generic_startup(serial);
}

A
Alan Cox 已提交
931
static void visor_shutdown(struct usb_serial *serial)
L
Linus Torvalds 已提交
932
{
P
Pete Zaitcev 已提交
933 934 935
	struct visor_private *priv;
	int i;

936
	dbg("%s", __func__);
P
Pete Zaitcev 已提交
937 938 939 940 941 942 943 944

	for (i = 0; i < serial->num_ports; i++) {
		priv = usb_get_serial_port_data(serial->port[i]);
		if (priv) {
			usb_set_serial_port_data(serial->port[i], NULL);
			kfree(priv);
		}
	}
L
Linus Torvalds 已提交
945 946
}

A
Alan Cox 已提交
947
static int __init visor_init(void)
L
Linus Torvalds 已提交
948 949 950
{
	int i, retval;
	/* Only if parameters were passed to us */
A
Alan Cox 已提交
951 952 953 954 955 956 957 958
	if (vendor > 0 && product > 0) {
		struct usb_device_id usb_dev_temp[] = {
			{
				USB_DEVICE(vendor, product),
				.driver_info =
					(kernel_ulong_t) &palm_os_4_probe
			}
		};
L
Linus Torvalds 已提交
959 960

		/* Find the last entry in id_table */
A
Alan Cox 已提交
961 962
		for (i = 0;; i++) {
			if (id_table[i].idVendor == 0) {
L
Linus Torvalds 已提交
963 964 965 966 967
				id_table[i] = usb_dev_temp[0];
				break;
			}
		}
		/* Find the last entry in id_table_combined */
A
Alan Cox 已提交
968 969
		for (i = 0;; i++) {
			if (id_table_combined[i].idVendor == 0) {
L
Linus Torvalds 已提交
970 971 972 973
				id_table_combined[i] = usb_dev_temp[0];
				break;
			}
		}
A
Alan Cox 已提交
974 975
		info(
		  "Untested USB device specified at time of module insertion");
L
Linus Torvalds 已提交
976 977 978 979 980 981 982 983 984 985 986 987 988 989 990
		info("Warning: This is not guaranteed to work");
		info("Using a newer kernel is preferred to this method");
		info("Adding Palm OS protocol 4.x support for unknown device: 0x%x/0x%x",
			vendor, product);
	}
	retval = usb_serial_register(&handspring_device);
	if (retval)
		goto failed_handspring_register;
	retval = usb_serial_register(&clie_3_5_device);
	if (retval)
		goto failed_clie_3_5_register;
	retval = usb_serial_register(&clie_5_device);
	if (retval)
		goto failed_clie_5_register;
	retval = usb_register(&visor_driver);
A
Alan Cox 已提交
991
	if (retval)
L
Linus Torvalds 已提交
992
		goto failed_usb_register;
993
	info(DRIVER_DESC);
L
Linus Torvalds 已提交
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008

	return 0;
failed_usb_register:
	usb_serial_deregister(&clie_5_device);
failed_clie_5_register:
	usb_serial_deregister(&clie_3_5_device);
failed_clie_3_5_register:
	usb_serial_deregister(&handspring_device);
failed_handspring_register:
	return retval;
}


static void __exit visor_exit (void)
{
A
Alan Cox 已提交
1009 1010 1011 1012
	usb_deregister(&visor_driver);
	usb_serial_deregister(&handspring_device);
	usb_serial_deregister(&clie_3_5_device);
	usb_serial_deregister(&clie_5_device);
L
Linus Torvalds 已提交
1013 1014 1015 1016 1017 1018
}


module_init(visor_init);
module_exit(visor_exit);

A
Alan Cox 已提交
1019 1020
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
L
Linus Torvalds 已提交
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
MODULE_LICENSE("GPL");

module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
module_param(stats, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(stats, "Enables statistics or not");

module_param(vendor, ushort, 0);
MODULE_PARM_DESC(vendor, "User specified vendor ID");
module_param(product, ushort, 0);
MODULE_PARM_DESC(product, "User specified product ID");