visor.c 20.8 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 */
39
static int  visor_open(struct tty_struct *tty, struct usb_serial_port *port);
40
static void visor_close(struct usb_serial_port *port);
A
Alan Cox 已提交
41 42
static int  visor_probe(struct usb_serial *serial,
					const struct usb_device_id *id);
L
Linus Torvalds 已提交
43
static int  visor_calc_num_ports(struct usb_serial *serial);
A
Alan Cox 已提交
44 45 46 47 48 49 50 51
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 已提交
52 53 54 55 56 57 58 59 60 61 62 63 64

/* 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 },
65 66
	{ USB_DEVICE(GSPDA_VENDOR_ID, GSPDA_XPLORE_M68_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
L
Linus Torvalds 已提交
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
	{ 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 },
83 84
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
L
Linus Torvalds 已提交
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
	{ 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 },
101 102
	{ USB_DEVICE(ACER_VENDOR_ID, ACER_S10_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
A
Alan Cox 已提交
103
	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID),
L
Linus Torvalds 已提交
104
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
A
Alan Cox 已提交
105
	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID),
L
Linus Torvalds 已提交
106
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
107 108
	{ USB_DEVICE(TAPWAVE_VENDOR_ID, TAPWAVE_ZODIAC_ID),
		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
A
Alan Cox 已提交
109
	{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID),
L
Linus Torvalds 已提交
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
		.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) },
137
	{ USB_DEVICE(GSPDA_VENDOR_ID, GSPDA_XPLORE_M68_ID) },
L
Linus Torvalds 已提交
138 139 140 141 142 143 144 145
	{ 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) },
146
	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) },
L
Linus Torvalds 已提交
147 148 149 150 151 152 153 154 155 156 157 158
	{ 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) },
159
	{ USB_DEVICE(TAPWAVE_VENDOR_ID, TAPWAVE_ZODIAC_ID) },
L
Linus Torvalds 已提交
160 161 162 163 164 165 166 167
	{ 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 已提交
168
MODULE_DEVICE_TABLE(usb, id_table_combined);
L
Linus Torvalds 已提交
169 170 171 172 173 174

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

A
Alan Cox 已提交
178 179
/* All of the device info needed for the Handspring Visor,
   and Palm 4.0 devices */
180
static struct usb_serial_driver handspring_device = {
181 182
	.driver = {
		.owner =	THIS_MODULE,
183
		.name =		"visor",
184
	},
185
	.description =		"Handspring Visor / Palm OS",
186
	.usb_driver =		&visor_driver,
L
Linus Torvalds 已提交
187 188
	.id_table =		id_table,
	.num_ports =		2,
189
	.bulk_out_size =	256,
L
Linus Torvalds 已提交
190 191
	.open =			visor_open,
	.close =		visor_close,
192 193
	.throttle =		usb_serial_generic_throttle,
	.unthrottle =		usb_serial_generic_unthrottle,
L
Linus Torvalds 已提交
194 195 196 197 198 199 200
	.attach =		treo_attach,
	.probe =		visor_probe,
	.calc_num_ports =	visor_calc_num_ports,
	.read_int_callback =	visor_read_int_callback,
};

/* All of the device info needed for the Clie UX50, TH55 Palm 5.0 devices */
201
static struct usb_serial_driver clie_5_device = {
202 203
	.driver = {
		.owner =	THIS_MODULE,
204
		.name =		"clie_5",
205
	},
206
	.description =		"Sony Clie 5.0",
207
	.usb_driver =		&visor_driver,
L
Linus Torvalds 已提交
208 209
	.id_table =		clie_id_5_table,
	.num_ports =		2,
210
	.bulk_out_size =	256,
L
Linus Torvalds 已提交
211 212
	.open =			visor_open,
	.close =		visor_close,
213 214
	.throttle =		usb_serial_generic_throttle,
	.unthrottle =		usb_serial_generic_unthrottle,
L
Linus Torvalds 已提交
215 216 217 218 219 220 221
	.attach =		clie_5_attach,
	.probe =		visor_probe,
	.calc_num_ports =	visor_calc_num_ports,
	.read_int_callback =	visor_read_int_callback,
};

/* device info for the Sony Clie OS version 3.5 */
222
static struct usb_serial_driver clie_3_5_device = {
223 224
	.driver = {
		.owner =	THIS_MODULE,
225
		.name =		"clie_3.5",
226
	},
227
	.description =		"Sony Clie 3.5",
228
	.usb_driver =		&visor_driver,
L
Linus Torvalds 已提交
229 230
	.id_table =		clie_id_3_5_table,
	.num_ports =		1,
231
	.bulk_out_size =	256,
L
Linus Torvalds 已提交
232 233
	.open =			visor_open,
	.close =		visor_close,
234 235
	.throttle =		usb_serial_generic_throttle,
	.unthrottle =		usb_serial_generic_unthrottle,
L
Linus Torvalds 已提交
236 237 238 239 240 241
	.attach =		clie_3_5_startup,
};

/******************************************************************************
 * Handspring Visor specific driver functions
 ******************************************************************************/
242
static int visor_open(struct tty_struct *tty, struct usb_serial_port *port)
L
Linus Torvalds 已提交
243 244 245
{
	int result = 0;

246
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
247 248 249 250 251 252 253 254

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

	/* Start reading from the device */
255 256
	result = usb_serial_generic_open(tty, port);
	if (result)
L
Linus Torvalds 已提交
257
		goto exit;
A
Alan Cox 已提交
258

L
Linus Torvalds 已提交
259
	if (port->interrupt_in_urb) {
260
		dbg("%s - adding interrupt input for treo", __func__);
L
Linus Torvalds 已提交
261 262
		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
		if (result)
A
Alan Cox 已提交
263 264 265
			dev_err(&port->dev,
			    "%s - failed submitting interrupt urb, error %d\n",
							__func__, result);
L
Linus Torvalds 已提交
266
	}
A
Alan Cox 已提交
267
exit:
L
Linus Torvalds 已提交
268 269 270 271
	return result;
}


272
static void visor_close(struct usb_serial_port *port)
L
Linus Torvalds 已提交
273 274 275
{
	unsigned char *transfer_buffer;

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

L
Linus Torvalds 已提交
278
	/* shutdown our urbs */
279
	usb_serial_generic_close(port);
M
Mariusz Kozlowski 已提交
280
	usb_kill_urb(port->interrupt_in_urb);
L
Linus Torvalds 已提交
281

282 283 284
	mutex_lock(&port->serial->disc_mutex);
	if (!port->serial->disconnected) {
		/* Try to send shutdown message, unless the device is gone */
A
Alan Cox 已提交
285
		transfer_buffer =  kmalloc(0x12, GFP_KERNEL);
286
		if (transfer_buffer) {
A
Alan Cox 已提交
287
			usb_control_msg(port->serial->dev,
288 289 290 291
					 usb_rcvctrlpipe(port->serial->dev, 0),
					 VISOR_CLOSE_NOTIFICATION, 0xc2,
					 0x0000, 0x0000,
					 transfer_buffer, 0x12, 300);
A
Alan Cox 已提交
292
			kfree(transfer_buffer);
293
		}
L
Linus Torvalds 已提交
294
	}
295
	mutex_unlock(&port->serial->disc_mutex);
L
Linus Torvalds 已提交
296 297
}

A
Alan Cox 已提交
298
static void visor_read_int_callback(struct urb *urb)
L
Linus Torvalds 已提交
299
{
300
	struct usb_serial_port *port = urb->context;
301
	int status = urb->status;
L
Linus Torvalds 已提交
302 303
	int result;

304
	switch (status) {
L
Linus Torvalds 已提交
305 306 307 308 309 310 311 312
	case 0:
		/* success */
		break;
	case -ECONNRESET:
	case -ENOENT:
	case -ESHUTDOWN:
		/* this urb is terminated, clean up */
		dbg("%s - urb shutting down with status: %d",
313
		    __func__, status);
L
Linus Torvalds 已提交
314 315 316
		return;
	default:
		dbg("%s - nonzero urb status received: %d",
317
		    __func__, status);
L
Linus Torvalds 已提交
318 319 320 321 322 323 324 325 326 327
		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.
	 */
328
	usb_serial_debug_data(debug, &port->dev, __func__,
L
Linus Torvalds 已提交
329 330 331
			      urb->actual_length, urb->transfer_buffer);

exit:
A
Alan Cox 已提交
332
	result = usb_submit_urb(urb, GFP_ATOMIC);
L
Linus Torvalds 已提交
333
	if (result)
A
Alan Cox 已提交
334 335 336
		dev_err(&urb->dev->dev,
				"%s - Error %d submitting interrupt urb\n",
							__func__, result);
L
Linus Torvalds 已提交
337 338
}

A
Alan Cox 已提交
339 340
static int palm_os_3_probe(struct usb_serial *serial,
						const struct usb_device_id *id)
L
Linus Torvalds 已提交
341 342 343 344 345 346 347 348 349
{
	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;

350
	dbg("%s", __func__);
L
Linus Torvalds 已提交
351

A
Alan Cox 已提交
352
	transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL);
L
Linus Torvalds 已提交
353
	if (!transfer_buffer) {
354
		dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__,
L
Linus Torvalds 已提交
355 356 357 358 359
			sizeof(*connection_info));
		return -ENOMEM;
	}

	/* send a get connection info request */
A
Alan Cox 已提交
360
	retval = usb_control_msg(serial->dev,
L
Linus Torvalds 已提交
361 362 363 364 365 366
				  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",
367
			__func__, retval);
L
Linus Torvalds 已提交
368 369 370 371
		goto exit;
	}

	if (retval == sizeof(*connection_info)) {
A
Alan Cox 已提交
372 373
			connection_info = (struct visor_connection_info *)
							transfer_buffer;
L
Linus Torvalds 已提交
374 375 376

		num_ports = le16_to_cpu(connection_info->num_ports);
		for (i = 0; i < num_ports; ++i) {
A
Alan Cox 已提交
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
			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 已提交
397 398
			}
			dev_info(dev, "%s: port %d, is for %s use\n",
399
				serial->type->description,
L
Linus Torvalds 已提交
400 401 402 403 404 405 406
				connection_info->connections[i].port, string);
		}
	}
	/*
	* Handle devices that report invalid stuff here.
	*/
	if (num_ports == 0 || num_ports > 2) {
A
Alan Cox 已提交
407
		dev_warn(dev, "%s: No valid connect info available\n",
408
			serial->type->description);
L
Linus Torvalds 已提交
409 410
		num_ports = 2;
	}
A
Alan Cox 已提交
411

412
	dev_info(dev, "%s: Number of ports: %d\n", serial->type->description,
L
Linus Torvalds 已提交
413 414 415 416 417 418 419 420
		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 已提交
421 422 423
	/* ask for the number of bytes available, but ignore the
	   response as it is broken */
	retval = usb_control_msg(serial->dev,
L
Linus Torvalds 已提交
424 425 426 427 428 429
				  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",
430
			__func__, retval);
L
Linus Torvalds 已提交
431 432 433
	retval = 0;

exit:
A
Alan Cox 已提交
434
	kfree(transfer_buffer);
L
Linus Torvalds 已提交
435 436 437 438

	return retval;
}

A
Alan Cox 已提交
439 440
static int palm_os_4_probe(struct usb_serial *serial,
						const struct usb_device_id *id)
L
Linus Torvalds 已提交
441 442 443 444 445 446
{
	struct device *dev = &serial->dev->dev;
	struct palm_ext_connection_info *connection_info;
	unsigned char *transfer_buffer;
	int retval;

447
	dbg("%s", __func__);
L
Linus Torvalds 已提交
448

A
Alan Cox 已提交
449
	transfer_buffer =  kmalloc(sizeof(*connection_info), GFP_KERNEL);
L
Linus Torvalds 已提交
450
	if (!transfer_buffer) {
451
		dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__,
L
Linus Torvalds 已提交
452 453 454 455
			sizeof(*connection_info));
		return -ENOMEM;
	}

A
Alan Cox 已提交
456 457
	retval = usb_control_msg(serial->dev,
				  usb_rcvctrlpipe(serial->dev, 0),
L
Linus Torvalds 已提交
458 459
				  PALM_GET_EXT_CONNECTION_INFORMATION,
				  0xc2, 0x0000, 0x0000, transfer_buffer,
A
Alan Cox 已提交
460
				  sizeof(*connection_info), 300);
L
Linus Torvalds 已提交
461 462
	if (retval < 0)
		dev_err(dev, "%s - error %d getting connection info\n",
463
			__func__, retval);
L
Linus Torvalds 已提交
464
	else
465
		usb_serial_debug_data(debug, &serial->dev->dev, __func__,
L
Linus Torvalds 已提交
466 467
				      retval, transfer_buffer);

A
Alan Cox 已提交
468
	kfree(transfer_buffer);
L
Linus Torvalds 已提交
469 470 471 472
	return 0;
}


A
Alan Cox 已提交
473 474
static int visor_probe(struct usb_serial *serial,
					const struct usb_device_id *id)
L
Linus Torvalds 已提交
475 476
{
	int retval = 0;
A
Alan Cox 已提交
477 478
	int (*startup)(struct usb_serial *serial,
					const struct usb_device_id *id);
L
Linus Torvalds 已提交
479

480
	dbg("%s", __func__);
L
Linus Torvalds 已提交
481 482

	if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
483
		dev_err(&serial->dev->dev, "active config #%d != 1 ??\n",
L
Linus Torvalds 已提交
484 485 486 487 488 489 490 491 492 493 494 495
			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 已提交
496
static int visor_calc_num_ports(struct usb_serial *serial)
L
Linus Torvalds 已提交
497 498 499 500 501 502 503 504 505
{
	int num_ports = (int)(long)(usb_get_serial_data(serial));

	if (num_ports)
		usb_set_serial_data(serial, NULL);

	return num_ports;
}

A
Alan Cox 已提交
506
static int clie_3_5_startup(struct usb_serial *serial)
L
Linus Torvalds 已提交
507 508 509
{
	struct device *dev = &serial->dev->dev;
	int result;
510
	u8 *data;
L
Linus Torvalds 已提交
511

512
	dbg("%s", __func__);
L
Linus Torvalds 已提交
513

514 515 516 517
	data = kmalloc(1, GFP_KERNEL);
	if (!data)
		return -ENOMEM;

L
Linus Torvalds 已提交
518 519 520 521 522
	/*
	 * Note that PEG-300 series devices expect the following two calls.
	 */

	/* get the config number */
A
Alan Cox 已提交
523
	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
L
Linus Torvalds 已提交
524
				  USB_REQ_GET_CONFIGURATION, USB_DIR_IN,
525
				  0, 0, data, 1, 3000);
L
Linus Torvalds 已提交
526
	if (result < 0) {
A
Alan Cox 已提交
527 528
		dev_err(dev, "%s: get config number failed: %d\n",
							__func__, result);
529
		goto out;
L
Linus Torvalds 已提交
530 531
	}
	if (result != 1) {
A
Alan Cox 已提交
532 533
		dev_err(dev, "%s: get config number bad return length: %d\n",
							__func__, result);
534 535
		result = -EIO;
		goto out;
L
Linus Torvalds 已提交
536 537 538
	}

	/* get the interface number */
A
Alan Cox 已提交
539 540
	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
				  USB_REQ_GET_INTERFACE,
L
Linus Torvalds 已提交
541
				  USB_DIR_IN | USB_RECIP_INTERFACE,
542
				  0, 0, data, 1, 3000);
L
Linus Torvalds 已提交
543
	if (result < 0) {
A
Alan Cox 已提交
544 545
		dev_err(dev, "%s: get interface number failed: %d\n",
							__func__, result);
546
		goto out;
L
Linus Torvalds 已提交
547 548
	}
	if (result != 1) {
A
Alan Cox 已提交
549 550 551
		dev_err(dev,
			"%s: get interface number bad return length: %d\n",
							__func__, result);
552 553
		result = -EIO;
		goto out;
L
Linus Torvalds 已提交
554 555
	}

556
	result = 0;
557 558 559 560
out:
	kfree(data);

	return result;
L
Linus Torvalds 已提交
561
}
A
Alan Cox 已提交
562 563

static int treo_attach(struct usb_serial *serial)
L
Linus Torvalds 已提交
564 565 566 567 568
{
	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 已提交
569 570 571 572 573
	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))
574
		return 0;
L
Linus Torvalds 已提交
575

576
	dbg("%s", __func__);
L
Linus Torvalds 已提交
577 578

	/*
A
Alan Cox 已提交
579 580 581 582
	* 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 已提交
583 584 585
	* apps that want to communicate on the second port.
	*/
#define COPY_PORT(dest, src)						\
A
Alan Cox 已提交
586 587 588 589 590 591 592 593 594
	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 已提交
595 596 597 598 599 600 601 602 603

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

604
	return 0;
L
Linus Torvalds 已提交
605 606
}

A
Alan Cox 已提交
607
static int clie_5_attach(struct usb_serial *serial)
L
Linus Torvalds 已提交
608
{
609
	dbg("%s", __func__);
L
Linus Torvalds 已提交
610

A
Alan Cox 已提交
611 612 613 614 615
	/* 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 已提交
616 617
	   Lets do a quick and dirty mapping
	 */
A
Alan Cox 已提交
618

L
Linus Torvalds 已提交
619 620 621
	/* some sanity check */
	if (serial->num_ports < 2)
		return -1;
A
Alan Cox 已提交
622

L
Linus Torvalds 已提交
623
	/* port 0 now uses the modified endpoint Address */
A
Alan Cox 已提交
624 625
	serial->port[0]->bulk_out_endpointAddress =
				serial->port[1]->bulk_out_endpointAddress;
L
Linus Torvalds 已提交
626

627
	return 0;
L
Linus Torvalds 已提交
628 629
}

A
Alan Cox 已提交
630
static int __init visor_init(void)
L
Linus Torvalds 已提交
631 632 633
{
	int i, retval;
	/* Only if parameters were passed to us */
A
Alan Cox 已提交
634 635 636 637 638 639 640 641
	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 已提交
642 643

		/* Find the last entry in id_table */
A
Alan Cox 已提交
644 645
		for (i = 0;; i++) {
			if (id_table[i].idVendor == 0) {
L
Linus Torvalds 已提交
646 647 648 649 650
				id_table[i] = usb_dev_temp[0];
				break;
			}
		}
		/* Find the last entry in id_table_combined */
A
Alan Cox 已提交
651 652
		for (i = 0;; i++) {
			if (id_table_combined[i].idVendor == 0) {
L
Linus Torvalds 已提交
653 654 655 656
				id_table_combined[i] = usb_dev_temp[0];
				break;
			}
		}
657 658 659 660 661 662 663 664
		printk(KERN_INFO KBUILD_MODNAME
		       ": Untested USB device specified at time of module insertion\n");
		printk(KERN_INFO KBUILD_MODNAME
		       ": Warning: This is not guaranteed to work\n");
		printk(KERN_INFO KBUILD_MODNAME
		       ": Using a newer kernel is preferred to this method\n");
		printk(KERN_INFO KBUILD_MODNAME
		       ": Adding Palm OS protocol 4.x support for unknown device: 0x%x/0x%x\n",
L
Linus Torvalds 已提交
665 666 667 668 669 670 671 672 673 674 675 676
			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 已提交
677
	if (retval)
L
Linus Torvalds 已提交
678
		goto failed_usb_register;
679
	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
L
Linus Torvalds 已提交
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694

	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 已提交
695 696 697 698
	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 已提交
699 700 701 702 703 704
}


module_init(visor_init);
module_exit(visor_exit);

A
Alan Cox 已提交
705 706
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
L
Linus Torvalds 已提交
707 708 709 710 711 712 713 714 715 716
MODULE_LICENSE("GPL");

module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled 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");