cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

visor.c (17933B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * USB HandSpring Visor, Palm m50x, and Sony Clie driver
      4 * (supports all of the Palm OS USB devices)
      5 *
      6 *	Copyright (C) 1999 - 2004
      7 *	    Greg Kroah-Hartman (greg@kroah.com)
      8 *
      9 * See Documentation/usb/usb-serial.rst for more information on using this
     10 * driver
     11 *
     12 */
     13
     14#include <linux/kernel.h>
     15#include <linux/errno.h>
     16#include <linux/slab.h>
     17#include <linux/tty.h>
     18#include <linux/tty_driver.h>
     19#include <linux/tty_flip.h>
     20#include <linux/module.h>
     21#include <linux/moduleparam.h>
     22#include <linux/spinlock.h>
     23#include <linux/uaccess.h>
     24#include <linux/usb.h>
     25#include <linux/usb/serial.h>
     26#include <linux/usb/cdc.h>
     27#include "visor.h"
     28
     29/*
     30 * Version Information
     31 */
     32#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
     33#define DRIVER_DESC "USB HandSpring Visor / Palm OS driver"
     34
     35/* function prototypes for a handspring visor */
     36static int  visor_open(struct tty_struct *tty, struct usb_serial_port *port);
     37static void visor_close(struct usb_serial_port *port);
     38static int  visor_probe(struct usb_serial *serial,
     39					const struct usb_device_id *id);
     40static int  visor_calc_num_ports(struct usb_serial *serial,
     41					struct usb_serial_endpoints *epds);
     42static int  clie_5_calc_num_ports(struct usb_serial *serial,
     43					struct usb_serial_endpoints *epds);
     44static void visor_read_int_callback(struct urb *urb);
     45static int  clie_3_5_startup(struct usb_serial *serial);
     46static int palm_os_3_probe(struct usb_serial *serial,
     47					const struct usb_device_id *id);
     48static int palm_os_4_probe(struct usb_serial *serial,
     49					const struct usb_device_id *id);
     50
     51static const struct usb_device_id id_table[] = {
     52	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID),
     53		.driver_info = (kernel_ulong_t)&palm_os_3_probe },
     54	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID),
     55		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     56	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO600_ID),
     57		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     58	{ USB_DEVICE(GSPDA_VENDOR_ID, GSPDA_XPLORE_M68_ID),
     59		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     60	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID),
     61		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     62	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID),
     63		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     64	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID),
     65		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     66	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID),
     67		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     68	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M100_ID),
     69		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     70	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID),
     71		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     72	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID),
     73		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     74	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID),
     75		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     76	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650),
     77		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     78	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID),
     79		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     80	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID),
     81		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     82	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID),
     83		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     84	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID),
     85		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     86	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID),
     87		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     88	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID),
     89		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     90	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID),
     91		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     92	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID),
     93		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     94	{ USB_DEVICE(ACER_VENDOR_ID, ACER_S10_ID),
     95		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     96	{ USB_DEVICE_INTERFACE_CLASS(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID, 0xff),
     97		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
     98	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID),
     99		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
    100	{ USB_DEVICE(TAPWAVE_VENDOR_ID, TAPWAVE_ZODIAC_ID),
    101		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
    102	{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID),
    103		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
    104	{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID),
    105		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
    106	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID),
    107		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
    108	{ USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID),
    109		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
    110	{ }					/* Terminating entry */
    111};
    112
    113static const struct usb_device_id clie_id_5_table[] = {
    114	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID),
    115		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
    116	{ }					/* Terminating entry */
    117};
    118
    119static const struct usb_device_id clie_id_3_5_table[] = {
    120	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
    121	{ }					/* Terminating entry */
    122};
    123
    124static const struct usb_device_id id_table_combined[] = {
    125	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
    126	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID) },
    127	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO600_ID) },
    128	{ USB_DEVICE(GSPDA_VENDOR_ID, GSPDA_XPLORE_M68_ID) },
    129	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
    130	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
    131	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
    132	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
    133	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M100_ID) },
    134	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
    135	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
    136	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
    137	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) },
    138	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
    139	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
    140	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
    141	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
    142	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
    143	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
    144	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) },
    145	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID) },
    146	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID) },
    147	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID) },
    148	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) },
    149	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID) },
    150	{ USB_DEVICE(TAPWAVE_VENDOR_ID, TAPWAVE_ZODIAC_ID) },
    151	{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) },
    152	{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) },
    153	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID) },
    154	{ USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID) },
    155	{ }					/* Terminating entry */
    156};
    157
    158MODULE_DEVICE_TABLE(usb, id_table_combined);
    159
    160/* All of the device info needed for the Handspring Visor,
    161   and Palm 4.0 devices */
    162static struct usb_serial_driver handspring_device = {
    163	.driver = {
    164		.owner =	THIS_MODULE,
    165		.name =		"visor",
    166	},
    167	.description =		"Handspring Visor / Palm OS",
    168	.id_table =		id_table,
    169	.num_ports =		2,
    170	.bulk_out_size =	256,
    171	.open =			visor_open,
    172	.close =		visor_close,
    173	.throttle =		usb_serial_generic_throttle,
    174	.unthrottle =		usb_serial_generic_unthrottle,
    175	.probe =		visor_probe,
    176	.calc_num_ports =	visor_calc_num_ports,
    177	.read_int_callback =	visor_read_int_callback,
    178};
    179
    180/* All of the device info needed for the Clie UX50, TH55 Palm 5.0 devices */
    181static struct usb_serial_driver clie_5_device = {
    182	.driver = {
    183		.owner =	THIS_MODULE,
    184		.name =		"clie_5",
    185	},
    186	.description =		"Sony Clie 5.0",
    187	.id_table =		clie_id_5_table,
    188	.num_ports =		2,
    189	.num_bulk_out =		2,
    190	.bulk_out_size =	256,
    191	.open =			visor_open,
    192	.close =		visor_close,
    193	.throttle =		usb_serial_generic_throttle,
    194	.unthrottle =		usb_serial_generic_unthrottle,
    195	.probe =		visor_probe,
    196	.calc_num_ports =	clie_5_calc_num_ports,
    197	.read_int_callback =	visor_read_int_callback,
    198};
    199
    200/* device info for the Sony Clie OS version 3.5 */
    201static struct usb_serial_driver clie_3_5_device = {
    202	.driver = {
    203		.owner =	THIS_MODULE,
    204		.name =		"clie_3.5",
    205	},
    206	.description =		"Sony Clie 3.5",
    207	.id_table =		clie_id_3_5_table,
    208	.num_ports =		1,
    209	.bulk_out_size =	256,
    210	.open =			visor_open,
    211	.close =		visor_close,
    212	.throttle =		usb_serial_generic_throttle,
    213	.unthrottle =		usb_serial_generic_unthrottle,
    214	.attach =		clie_3_5_startup,
    215};
    216
    217static struct usb_serial_driver * const serial_drivers[] = {
    218	&handspring_device, &clie_5_device, &clie_3_5_device, NULL
    219};
    220
    221/******************************************************************************
    222 * Handspring Visor specific driver functions
    223 ******************************************************************************/
    224static int visor_open(struct tty_struct *tty, struct usb_serial_port *port)
    225{
    226	int result = 0;
    227
    228	if (!port->read_urb) {
    229		/* this is needed for some brain dead Sony devices */
    230		dev_err(&port->dev, "Device lied about number of ports, please use a lower one.\n");
    231		return -ENODEV;
    232	}
    233
    234	/* Start reading from the device */
    235	result = usb_serial_generic_open(tty, port);
    236	if (result)
    237		goto exit;
    238
    239	if (port->interrupt_in_urb) {
    240		dev_dbg(&port->dev, "adding interrupt input for treo\n");
    241		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
    242		if (result)
    243			dev_err(&port->dev,
    244			    "%s - failed submitting interrupt urb, error %d\n",
    245							__func__, result);
    246	}
    247exit:
    248	return result;
    249}
    250
    251
    252static void visor_close(struct usb_serial_port *port)
    253{
    254	unsigned char *transfer_buffer;
    255
    256	usb_serial_generic_close(port);
    257	usb_kill_urb(port->interrupt_in_urb);
    258
    259	transfer_buffer = kmalloc(0x12, GFP_KERNEL);
    260	if (!transfer_buffer)
    261		return;
    262	usb_control_msg(port->serial->dev,
    263					 usb_rcvctrlpipe(port->serial->dev, 0),
    264					 VISOR_CLOSE_NOTIFICATION, 0xc2,
    265					 0x0000, 0x0000,
    266					 transfer_buffer, 0x12, 300);
    267	kfree(transfer_buffer);
    268}
    269
    270static void visor_read_int_callback(struct urb *urb)
    271{
    272	struct usb_serial_port *port = urb->context;
    273	int status = urb->status;
    274	int result;
    275
    276	switch (status) {
    277	case 0:
    278		/* success */
    279		break;
    280	case -ECONNRESET:
    281	case -ENOENT:
    282	case -ESHUTDOWN:
    283		/* this urb is terminated, clean up */
    284		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
    285			__func__, status);
    286		return;
    287	default:
    288		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
    289			__func__, status);
    290		goto exit;
    291	}
    292
    293	/*
    294	 * This information is still unknown what it can be used for.
    295	 * If anyone has an idea, please let the author know...
    296	 *
    297	 * Rumor has it this endpoint is used to notify when data
    298	 * is ready to be read from the bulk ones.
    299	 */
    300	usb_serial_debug_data(&port->dev, __func__, urb->actual_length,
    301			      urb->transfer_buffer);
    302
    303exit:
    304	result = usb_submit_urb(urb, GFP_ATOMIC);
    305	if (result)
    306		dev_err(&urb->dev->dev,
    307				"%s - Error %d submitting interrupt urb\n",
    308							__func__, result);
    309}
    310
    311static int palm_os_3_probe(struct usb_serial *serial,
    312						const struct usb_device_id *id)
    313{
    314	struct device *dev = &serial->dev->dev;
    315	struct visor_connection_info *connection_info;
    316	unsigned char *transfer_buffer;
    317	char *string;
    318	int retval = 0;
    319	int i;
    320	int num_ports = 0;
    321
    322	transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL);
    323	if (!transfer_buffer)
    324		return -ENOMEM;
    325
    326	/* send a get connection info request */
    327	retval = usb_control_msg(serial->dev,
    328				  usb_rcvctrlpipe(serial->dev, 0),
    329				  VISOR_GET_CONNECTION_INFORMATION,
    330				  0xc2, 0x0000, 0x0000, transfer_buffer,
    331				  sizeof(*connection_info), 300);
    332	if (retval < 0) {
    333		dev_err(dev, "%s - error %d getting connection information\n",
    334			__func__, retval);
    335		goto exit;
    336	}
    337
    338	if (retval != sizeof(*connection_info)) {
    339		dev_err(dev, "Invalid connection information received from device\n");
    340		retval = -ENODEV;
    341		goto exit;
    342	}
    343
    344	connection_info = (struct visor_connection_info *)transfer_buffer;
    345
    346	num_ports = le16_to_cpu(connection_info->num_ports);
    347
    348	/* Handle devices that report invalid stuff here. */
    349	if (num_ports == 0 || num_ports > 2) {
    350		dev_warn(dev, "%s: No valid connect info available\n",
    351			serial->type->description);
    352		num_ports = 2;
    353	}
    354
    355	for (i = 0; i < num_ports; ++i) {
    356		switch (connection_info->connections[i].port_function_id) {
    357		case VISOR_FUNCTION_GENERIC:
    358			string = "Generic";
    359			break;
    360		case VISOR_FUNCTION_DEBUGGER:
    361			string = "Debugger";
    362			break;
    363		case VISOR_FUNCTION_HOTSYNC:
    364			string = "HotSync";
    365			break;
    366		case VISOR_FUNCTION_CONSOLE:
    367			string = "Console";
    368			break;
    369		case VISOR_FUNCTION_REMOTE_FILE_SYS:
    370			string = "Remote File System";
    371			break;
    372		default:
    373			string = "unknown";
    374			break;
    375		}
    376		dev_info(dev, "%s: port %d, is for %s use\n",
    377			serial->type->description,
    378			connection_info->connections[i].port, string);
    379	}
    380	dev_info(dev, "%s: Number of ports: %d\n", serial->type->description,
    381		num_ports);
    382
    383	/*
    384	 * save off our num_ports info so that we can use it in the
    385	 * calc_num_ports callback
    386	 */
    387	usb_set_serial_data(serial, (void *)(long)num_ports);
    388
    389	/* ask for the number of bytes available, but ignore the
    390	   response as it is broken */
    391	retval = usb_control_msg(serial->dev,
    392				  usb_rcvctrlpipe(serial->dev, 0),
    393				  VISOR_REQUEST_BYTES_AVAILABLE,
    394				  0xc2, 0x0000, 0x0005, transfer_buffer,
    395				  0x02, 300);
    396	if (retval < 0)
    397		dev_err(dev, "%s - error %d getting bytes available request\n",
    398			__func__, retval);
    399	retval = 0;
    400
    401exit:
    402	kfree(transfer_buffer);
    403
    404	return retval;
    405}
    406
    407static int palm_os_4_probe(struct usb_serial *serial,
    408						const struct usb_device_id *id)
    409{
    410	struct device *dev = &serial->dev->dev;
    411	struct palm_ext_connection_info *connection_info;
    412	unsigned char *transfer_buffer;
    413	int retval;
    414
    415	transfer_buffer =  kmalloc(sizeof(*connection_info), GFP_KERNEL);
    416	if (!transfer_buffer)
    417		return -ENOMEM;
    418
    419	retval = usb_control_msg(serial->dev,
    420				  usb_rcvctrlpipe(serial->dev, 0),
    421				  PALM_GET_EXT_CONNECTION_INFORMATION,
    422				  0xc2, 0x0000, 0x0000, transfer_buffer,
    423				  sizeof(*connection_info), 300);
    424	if (retval < 0)
    425		dev_err(dev, "%s - error %d getting connection info\n",
    426			__func__, retval);
    427	else
    428		usb_serial_debug_data(dev, __func__, retval, transfer_buffer);
    429
    430	kfree(transfer_buffer);
    431	return 0;
    432}
    433
    434
    435static int visor_probe(struct usb_serial *serial,
    436					const struct usb_device_id *id)
    437{
    438	int retval = 0;
    439	int (*startup)(struct usb_serial *serial,
    440					const struct usb_device_id *id);
    441
    442	/*
    443	 * some Samsung Android phones in modem mode have the same ID
    444	 * as SPH-I500, but they are ACM devices, so dont bind to them
    445	 */
    446	if (id->idVendor == SAMSUNG_VENDOR_ID &&
    447		id->idProduct == SAMSUNG_SPH_I500_ID &&
    448		serial->dev->descriptor.bDeviceClass == USB_CLASS_COMM &&
    449		serial->dev->descriptor.bDeviceSubClass ==
    450			USB_CDC_SUBCLASS_ACM)
    451		return -ENODEV;
    452
    453	if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
    454		dev_err(&serial->dev->dev, "active config #%d != 1 ??\n",
    455			serial->dev->actconfig->desc.bConfigurationValue);
    456		return -ENODEV;
    457	}
    458
    459	if (id->driver_info) {
    460		startup = (void *)id->driver_info;
    461		retval = startup(serial, id);
    462	}
    463
    464	return retval;
    465}
    466
    467static int visor_calc_num_ports(struct usb_serial *serial,
    468					struct usb_serial_endpoints *epds)
    469{
    470	unsigned int vid = le16_to_cpu(serial->dev->descriptor.idVendor);
    471	int num_ports = (int)(long)(usb_get_serial_data(serial));
    472
    473	if (num_ports)
    474		usb_set_serial_data(serial, NULL);
    475
    476	/*
    477	 * Only swap the bulk endpoints for the Handspring devices with
    478	 * interrupt in endpoints, which for now are the Treo devices.
    479	 */
    480	if (!(vid == HANDSPRING_VENDOR_ID || vid == KYOCERA_VENDOR_ID) ||
    481			epds->num_interrupt_in == 0)
    482		goto out;
    483
    484	if (epds->num_bulk_in < 2 || epds->num_interrupt_in < 2) {
    485		dev_err(&serial->interface->dev, "missing endpoints\n");
    486		return -ENODEV;
    487	}
    488
    489	/*
    490	 * It appears that Treos and Kyoceras want to use the
    491	 * 1st bulk in endpoint to communicate with the 2nd bulk out endpoint,
    492	 * so let's swap the 1st and 2nd bulk in and interrupt endpoints.
    493	 * Note that swapping the bulk out endpoints would break lots of
    494	 * apps that want to communicate on the second port.
    495	 */
    496	swap(epds->bulk_in[0], epds->bulk_in[1]);
    497	swap(epds->interrupt_in[0], epds->interrupt_in[1]);
    498out:
    499	return num_ports;
    500}
    501
    502static int clie_5_calc_num_ports(struct usb_serial *serial,
    503					struct usb_serial_endpoints *epds)
    504{
    505	/*
    506	 * TH55 registers 2 ports.
    507	 * Communication in from the UX50/TH55 uses the first bulk-in
    508	 * endpoint, while communication out to the UX50/TH55 uses the second
    509	 * bulk-out endpoint.
    510	 */
    511
    512	/*
    513	 * FIXME: Should we swap the descriptors instead of using the same
    514	 *        bulk-out endpoint for both ports?
    515	 */
    516	epds->bulk_out[0] = epds->bulk_out[1];
    517
    518	return serial->type->num_ports;
    519}
    520
    521static int clie_3_5_startup(struct usb_serial *serial)
    522{
    523	struct device *dev = &serial->dev->dev;
    524	int result;
    525	u8 *data;
    526
    527	data = kmalloc(1, GFP_KERNEL);
    528	if (!data)
    529		return -ENOMEM;
    530
    531	/*
    532	 * Note that PEG-300 series devices expect the following two calls.
    533	 */
    534
    535	/* get the config number */
    536	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
    537				  USB_REQ_GET_CONFIGURATION, USB_DIR_IN,
    538				  0, 0, data, 1, 3000);
    539	if (result < 0) {
    540		dev_err(dev, "%s: get config number failed: %d\n",
    541							__func__, result);
    542		goto out;
    543	}
    544	if (result != 1) {
    545		dev_err(dev, "%s: get config number bad return length: %d\n",
    546							__func__, result);
    547		result = -EIO;
    548		goto out;
    549	}
    550
    551	/* get the interface number */
    552	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
    553				  USB_REQ_GET_INTERFACE,
    554				  USB_DIR_IN | USB_RECIP_INTERFACE,
    555				  0, 0, data, 1, 3000);
    556	if (result < 0) {
    557		dev_err(dev, "%s: get interface number failed: %d\n",
    558							__func__, result);
    559		goto out;
    560	}
    561	if (result != 1) {
    562		dev_err(dev,
    563			"%s: get interface number bad return length: %d\n",
    564							__func__, result);
    565		result = -EIO;
    566		goto out;
    567	}
    568
    569	result = 0;
    570out:
    571	kfree(data);
    572
    573	return result;
    574}
    575
    576module_usb_serial_driver(serial_drivers, id_table_combined);
    577
    578MODULE_AUTHOR(DRIVER_AUTHOR);
    579MODULE_DESCRIPTION(DRIVER_DESC);
    580MODULE_LICENSE("GPL v2");