safe_serial.c 14.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Safe Encapsulated USB Serial Driver
 *
 *      Copyright (C) 2001 Lineo
 *      Copyright (C) 2001 Hewlett-Packard
 *
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; either version 2 of the License, or
 *	(at your option) any later version.
 *
 * By:
 *      Stuart Lynne <sl@lineo.com>, Tom Rushworth <tbr@lineo.com>
 */

A
Alan Cox 已提交
16 17 18
/*
 * The encapsultaion is designed to overcome difficulties with some USB
 * hardware.
L
Linus Torvalds 已提交
19 20
 *
 * While the USB protocol has a CRC over the data while in transit, i.e. while
A
Alan Cox 已提交
21 22 23
 * being carried over the bus, there is no end to end protection. If the
 * hardware has any problems getting the data into or out of the USB transmit
 * and receive FIFO's then data can be lost.
L
Linus Torvalds 已提交
24
 *
A
Alan Cox 已提交
25 26 27
 * This protocol adds a two byte trailer to each USB packet to specify the
 * number of bytes of valid data and a 10 bit CRC that will allow the receiver
 * to verify that the entire USB packet was received without error.
L
Linus Torvalds 已提交
28
 *
A
Alan Cox 已提交
29 30
 * Because in this case the sender and receiver are the class and function
 * drivers there is now end to end protection.
L
Linus Torvalds 已提交
31
 *
A
Alan Cox 已提交
32 33 34
 * There is an additional option that can be used to force all transmitted
 * packets to be padded to the maximum packet size. This provides a work
 * around for some devices which have problems with small USB packets.
L
Linus Torvalds 已提交
35 36 37 38 39 40 41 42 43 44 45 46 47
 *
 * Assuming a packetsize of N:
 *
 *      0..N-2  data and optional padding
 *
 *      N-2     bits 7-2 - number of bytes of valid data
 *              bits 1-0 top two bits of 10 bit CRC
 *      N-1     bottom 8 bits of 10 bit CRC
 *
 *
 *      | Data Length       | 10 bit CRC                                |
 *      + 7 . 6 . 5 . 4 . 3 . 2 . 1 . 0 | 7 . 6 . 5 . 4 . 3 . 2 . 1 . 0 +
 *
A
Alan Cox 已提交
48 49 50
 * The 10 bit CRC is computed across the sent data, followed by the trailer
 * with the length set and the CRC set to zero. The CRC is then OR'd into
 * the trailer.
L
Linus Torvalds 已提交
51
 *
A
Alan Cox 已提交
52 53
 * When received a 10 bit CRC is computed over the entire frame including
 * the trailer and should be equal to zero.
L
Linus Torvalds 已提交
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
 *
 * Two module parameters are used to control the encapsulation, if both are
 * turned of the module works as a simple serial device with NO
 * encapsulation.
 *
 * See linux/drivers/usbd/serial_fd for a device function driver
 * implementation of this.
 *
 */


#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/spinlock.h>
A
Alan Cox 已提交
74
#include <linux/uaccess.h>
L
Linus Torvalds 已提交
75
#include <linux/usb.h>
76
#include <linux/usb/serial.h>
L
Linus Torvalds 已提交
77 78


79 80
#ifndef CONFIG_USB_SERIAL_SAFE_PADDED
#define CONFIG_USB_SERIAL_SAFE_PADDED 0
L
Linus Torvalds 已提交
81 82 83 84
#endif

static int debug;
static int safe = 1;
85
static int padded = CONFIG_USB_SERIAL_SAFE_PADDED;
L
Linus Torvalds 已提交
86 87 88 89 90

#define DRIVER_VERSION "v0.0b"
#define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com"
#define DRIVER_DESC "USB Safe Encapsulated Serial"

A
Alan Cox 已提交
91 92
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
L
Linus Torvalds 已提交
93 94
MODULE_LICENSE("GPL");

A
Alan Cox 已提交
95 96
static __u16 vendor;		/* no default */
static __u16 product;		/* no default */
L
Linus Torvalds 已提交
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
module_param(vendor, ushort, 0);
MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)");
module_param(product, ushort, 0);
MODULE_PARM_DESC(product, "User specified USB idProduct (required)");

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

module_param(safe, bool, 0);
MODULE_PARM_DESC(safe, "Turn Safe Encapsulation On/Off");

module_param(padded, bool, 0);
MODULE_PARM_DESC(padded, "Pad to full wMaxPacketSize On/Off");

#define CDC_DEVICE_CLASS                        0x02

#define CDC_INTERFACE_CLASS                     0x02
#define CDC_INTERFACE_SUBCLASS                  0x06

#define LINEO_INTERFACE_CLASS                   0xff

#define LINEO_INTERFACE_SUBCLASS_SAFENET        0x01
#define LINEO_SAFENET_CRC                       0x01
#define LINEO_SAFENET_CRC_PADDED                0x02

#define LINEO_INTERFACE_SUBCLASS_SAFESERIAL     0x02
#define LINEO_SAFESERIAL_CRC                    0x01
#define LINEO_SAFESERIAL_CRC_PADDED             0x02


A
Alan Cox 已提交
127 128 129 130 131 132 133 134 135 136
#define MY_USB_DEVICE(vend, prod, dc, ic, isc) \
	.match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
		       USB_DEVICE_ID_MATCH_DEV_CLASS | \
		       USB_DEVICE_ID_MATCH_INT_CLASS | \
		       USB_DEVICE_ID_MATCH_INT_SUBCLASS, \
	.idVendor = (vend), \
	.idProduct = (prod),\
	.bDeviceClass = (dc),\
	.bInterfaceClass = (ic), \
	.bInterfaceSubClass = (isc),
L
Linus Torvalds 已提交
137 138

static struct usb_device_id id_table[] = {
A
Alan Cox 已提交
139 140 141 142 143 144 145 146 147 148
	{MY_USB_DEVICE(0x49f, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	/* Itsy */
	{MY_USB_DEVICE(0x3f0, 0x2101, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	/* Calypso */
	{MY_USB_DEVICE(0x4dd, 0x8001, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	/* Iris */
	{MY_USB_DEVICE(0x4dd, 0x8002, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	/* Collie */
	{MY_USB_DEVICE(0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	/* Collie */
	{MY_USB_DEVICE(0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	/* Collie */
	{MY_USB_DEVICE(0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	/* Sharp tmp */
	/* extra null entry for module vendor/produc parameters */
	{MY_USB_DEVICE(0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
	{}			/* terminating entry  */
L
Linus Torvalds 已提交
149 150
};

A
Alan Cox 已提交
151
MODULE_DEVICE_TABLE(usb, id_table);
L
Linus Torvalds 已提交
152 153 154 155 156 157

static struct usb_driver safe_driver = {
	.name =		"safe_serial",
	.probe =	usb_serial_probe,
	.disconnect =	usb_serial_disconnect,
	.id_table =	id_table,
158
	.no_dynamic_id = 	1,
L
Linus Torvalds 已提交
159 160
};

161
static const __u16 crc10_table[256] = {
A
Alan Cox 已提交
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
	0x000, 0x233, 0x255, 0x066, 0x299, 0x0aa, 0x0cc, 0x2ff,
	0x301, 0x132, 0x154, 0x367, 0x198, 0x3ab, 0x3cd, 0x1fe,
	0x031, 0x202, 0x264, 0x057, 0x2a8, 0x09b, 0x0fd, 0x2ce,
	0x330, 0x103, 0x165, 0x356, 0x1a9, 0x39a, 0x3fc, 0x1cf,
	0x062, 0x251, 0x237, 0x004, 0x2fb, 0x0c8, 0x0ae, 0x29d,
	0x363, 0x150, 0x136, 0x305, 0x1fa, 0x3c9, 0x3af, 0x19c,
	0x053, 0x260, 0x206, 0x035, 0x2ca, 0x0f9, 0x09f, 0x2ac,
	0x352, 0x161, 0x107, 0x334, 0x1cb, 0x3f8, 0x39e, 0x1ad,
	0x0c4, 0x2f7, 0x291, 0x0a2, 0x25d, 0x06e, 0x008, 0x23b,
	0x3c5, 0x1f6, 0x190, 0x3a3, 0x15c, 0x36f, 0x309, 0x13a,
	0x0f5, 0x2c6, 0x2a0, 0x093, 0x26c, 0x05f, 0x039, 0x20a,
	0x3f4, 0x1c7, 0x1a1, 0x392, 0x16d, 0x35e, 0x338, 0x10b,
	0x0a6, 0x295, 0x2f3, 0x0c0, 0x23f, 0x00c, 0x06a, 0x259,
	0x3a7, 0x194, 0x1f2, 0x3c1, 0x13e, 0x30d, 0x36b, 0x158,
	0x097, 0x2a4, 0x2c2, 0x0f1, 0x20e, 0x03d, 0x05b, 0x268,
	0x396, 0x1a5, 0x1c3, 0x3f0, 0x10f, 0x33c, 0x35a, 0x169,
	0x188, 0x3bb, 0x3dd, 0x1ee, 0x311, 0x122, 0x144, 0x377,
	0x289, 0x0ba, 0x0dc, 0x2ef, 0x010, 0x223, 0x245, 0x076,
	0x1b9, 0x38a, 0x3ec, 0x1df, 0x320, 0x113, 0x175, 0x346,
	0x2b8, 0x08b, 0x0ed, 0x2de, 0x021, 0x212, 0x274, 0x047,
	0x1ea, 0x3d9, 0x3bf, 0x18c, 0x373, 0x140, 0x126, 0x315,
	0x2eb, 0x0d8, 0x0be, 0x28d, 0x072, 0x241, 0x227, 0x014,
	0x1db, 0x3e8, 0x38e, 0x1bd, 0x342, 0x171, 0x117, 0x324,
	0x2da, 0x0e9, 0x08f, 0x2bc, 0x043, 0x270, 0x216, 0x025,
	0x14c, 0x37f, 0x319, 0x12a, 0x3d5, 0x1e6, 0x180, 0x3b3,
	0x24d, 0x07e, 0x018, 0x22b, 0x0d4, 0x2e7, 0x281, 0x0b2,
	0x17d, 0x34e, 0x328, 0x11b, 0x3e4, 0x1d7, 0x1b1, 0x382,
	0x27c, 0x04f, 0x029, 0x21a, 0x0e5, 0x2d6, 0x2b0, 0x083,
	0x12e, 0x31d, 0x37b, 0x148, 0x3b7, 0x184, 0x1e2, 0x3d1,
	0x22f, 0x01c, 0x07a, 0x249, 0x0b6, 0x285, 0x2e3, 0x0d0,
	0x11f, 0x32c, 0x34a, 0x179, 0x386, 0x1b5, 0x1d3, 0x3e0,
	0x21e, 0x02d, 0x04b, 0x278, 0x087, 0x2b4, 0x2d2, 0x0e1,
L
Linus Torvalds 已提交
194 195
};

A
Alan Cox 已提交
196 197 198
#define CRC10_INITFCS     0x000	/* Initial FCS value */
#define CRC10_GOODFCS     0x000	/* Good final FCS value */
#define CRC10_FCS(fcs, c) ((((fcs) << 8) & 0x3ff) ^ crc10_table[((fcs) >> 2) & 0xff] ^ (c))
L
Linus Torvalds 已提交
199

A
Alan Cox 已提交
200
/**
L
Linus Torvalds 已提交
201 202 203 204 205 206 207 208
 * fcs_compute10 - memcpy and calculate 10 bit CRC across buffer
 * @sp: pointer to buffer
 * @len: number of bytes
 * @fcs: starting FCS
 *
 * Perform a memcpy and calculate fcs using ppp 10bit CRC algorithm. Return
 * new 10 bit FCS.
 */
A
Alan Cox 已提交
209
static __u16 __inline__ fcs_compute10(unsigned char *sp, int len, __u16 fcs)
L
Linus Torvalds 已提交
210
{
A
Alan Cox 已提交
211
	for (; len-- > 0; fcs = CRC10_FCS(fcs, *sp++));
L
Linus Torvalds 已提交
212 213 214
	return fcs;
}

A
Alan Cox 已提交
215
static void safe_read_bulk_callback(struct urb *urb)
L
Linus Torvalds 已提交
216
{
217
	struct usb_serial_port *port =  urb->context;
L
Linus Torvalds 已提交
218 219
	unsigned char *data = urb->transfer_buffer;
	unsigned char length = urb->actual_length;
A
Alan Cox 已提交
220
	struct tty_struct *tty;
L
Linus Torvalds 已提交
221
	int result;
222
	int status = urb->status;
L
Linus Torvalds 已提交
223

A
Alan Cox 已提交
224
	dbg("%s", __func__);
L
Linus Torvalds 已提交
225

226 227
	if (status) {
		dbg("%s - nonzero read bulk status received: %d",
228
		    __func__, status);
L
Linus Torvalds 已提交
229 230 231
		return;
	}

A
Alan Cox 已提交
232 233
	dbg("safe_read_bulk_callback length: %d",
					port->read_urb->actual_length);
L
Linus Torvalds 已提交
234 235 236 237 238
#ifdef ECHO_RCV
	{
		int i;
		unsigned char *cp = port->read_urb->transfer_buffer;
		for (i = 0; i < port->read_urb->actual_length; i++) {
A
Alan Cox 已提交
239 240 241
			if ((i % 32) == 0)
				printk("\nru[%02x] ", i);
			printk("%02x ", *cp++);
L
Linus Torvalds 已提交
242
		}
A
Alan Cox 已提交
243
		printk("\n");
L
Linus Torvalds 已提交
244 245
	}
#endif
A
Alan Cox 已提交
246
	tty = tty_port_tty_get(&port->port);
L
Linus Torvalds 已提交
247 248
	if (safe) {
		__u16 fcs;
A
Alan Cox 已提交
249 250
		fcs = fcs_compute10(data, length, CRC10_INITFCS);
		if (!fcs) {
L
Linus Torvalds 已提交
251 252
			int actual_length = data[length - 2] >> 2;
			if (actual_length <= (length - 2)) {
253 254
				dev_info(&urb->dev->dev, "%s - actual: %d\n",
					 __func__, actual_length);
A
Alan Cox 已提交
255
				tty_insert_flip_string(tty,
A
Alan Cox 已提交
256
							data, actual_length);
A
Alan Cox 已提交
257
				tty_flip_buffer_push(tty);
L
Linus Torvalds 已提交
258
			} else {
259 260
				dev_err(&port->dev,
					"%s - inconsistent lengths %d:%d\n",
A
Alan Cox 已提交
261
					__func__, actual_length, length);
L
Linus Torvalds 已提交
262 263
			}
		} else {
264
			dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs);
L
Linus Torvalds 已提交
265 266
		}
	} else {
A
Alan Cox 已提交
267 268
		tty_insert_flip_string(tty, data, length);
		tty_flip_buffer_push(tty);
L
Linus Torvalds 已提交
269
	}
A
Alan Cox 已提交
270
	tty_kref_put(tty);
L
Linus Torvalds 已提交
271 272

	/* Continue trying to always read  */
A
Alan Cox 已提交
273 274 275 276 277 278 279 280
	usb_fill_bulk_urb(urb, port->serial->dev,
			usb_rcvbulkpipe(port->serial->dev,
					port->bulk_in_endpointAddress),
			urb->transfer_buffer, urb->transfer_buffer_length,
			safe_read_bulk_callback, port);

	result = usb_submit_urb(urb, GFP_ATOMIC);
	if (result)
281 282 283
		dev_err(&port->dev,
			"%s - failed resubmitting read urb, error %d\n",
			__func__, result);
284
		/* FIXME: Need a mechanism to retry later if this happens */
L
Linus Torvalds 已提交
285 286
}

A
Alan Cox 已提交
287 288
static int safe_write(struct tty_struct *tty, struct usb_serial_port *port,
					const unsigned char *buf, int count)
L
Linus Torvalds 已提交
289 290 291 292 293 294
{
	unsigned char *data;
	int result;
	int i;
	int packet_length;

A
Alan Cox 已提交
295 296
	dbg("safe_write port: %p %d urb: %p count: %d",
				port, port->number, port->write_urb, count);
L
Linus Torvalds 已提交
297 298

	if (!port->write_urb) {
A
Alan Cox 已提交
299
		dbg("%s - write urb NULL", __func__);
300
		return 0;
L
Linus Torvalds 已提交
301 302
	}

A
Alan Cox 已提交
303
	dbg("safe_write write_urb: %d transfer_buffer_length",
L
Linus Torvalds 已提交
304 305 306
	     port->write_urb->transfer_buffer_length);

	if (!port->write_urb->transfer_buffer_length) {
A
Alan Cox 已提交
307
		dbg("%s - write urb transfer_buffer_length zero", __func__);
308
		return 0;
L
Linus Torvalds 已提交
309 310
	}
	if (count == 0) {
A
Alan Cox 已提交
311
		dbg("%s - write request of 0 bytes", __func__);
312
		return 0;
L
Linus Torvalds 已提交
313
	}
314
	spin_lock_bh(&port->lock);
315
	if (port->write_urb_busy) {
316
		spin_unlock_bh(&port->lock);
317
		dbg("%s - already writing", __func__);
318
		return 0;
L
Linus Torvalds 已提交
319
	}
320
	port->write_urb_busy = 1;
321
	spin_unlock_bh(&port->lock);
L
Linus Torvalds 已提交
322

A
Alan Cox 已提交
323
	packet_length = port->bulk_out_size;	/* get max packetsize */
L
Linus Torvalds 已提交
324

A
Alan Cox 已提交
325
	i = packet_length - (safe ? 2 : 0);	/* get bytes to send */
L
Linus Torvalds 已提交
326 327 328
	count = (count > i) ? i : count;


A
Alan Cox 已提交
329
	/* get the data into the transfer buffer */
L
Linus Torvalds 已提交
330
	data = port->write_urb->transfer_buffer;
A
Alan Cox 已提交
331
	memset(data, '0', packet_length);
L
Linus Torvalds 已提交
332

A
Alan Cox 已提交
333
	memcpy(data, buf, count);
L
Linus Torvalds 已提交
334 335 336 337

	if (safe) {
		__u16 fcs;

A
Alan Cox 已提交
338 339
		/* pad if necessary */
		if (!padded)
L
Linus Torvalds 已提交
340
			packet_length = count + 2;
A
Alan Cox 已提交
341
		/* set count */
L
Linus Torvalds 已提交
342 343 344
		data[packet_length - 2] = count << 2;
		data[packet_length - 1] = 0;

A
Alan Cox 已提交
345 346
		/* compute fcs and insert into trailer */
		fcs = fcs_compute10(data, packet_length, CRC10_INITFCS);
L
Linus Torvalds 已提交
347 348 349
		data[packet_length - 2] |= fcs >> 8;
		data[packet_length - 1] |= fcs & 0xff;

A
Alan Cox 已提交
350
		/* set length to send */
L
Linus Torvalds 已提交
351 352 353 354 355
		port->write_urb->transfer_buffer_length = packet_length;
	} else {
		port->write_urb->transfer_buffer_length = count;
	}

A
Alan Cox 已提交
356 357
	usb_serial_debug_data(debug, &port->dev, __func__, count,
					port->write_urb->transfer_buffer);
L
Linus Torvalds 已提交
358 359 360 361 362
#ifdef ECHO_TX
	{
		int i;
		unsigned char *cp = port->write_urb->transfer_buffer;
		for (i = 0; i < port->write_urb->transfer_buffer_length; i++) {
A
Alan Cox 已提交
363 364 365
			if ((i % 32) == 0)
				printk("\nsu[%02x] ", i);
			printk("%02x ", *cp++);
L
Linus Torvalds 已提交
366
		}
A
Alan Cox 已提交
367
		printk("\n");
L
Linus Torvalds 已提交
368 369 370
	}
#endif
	port->write_urb->dev = port->serial->dev;
A
Alan Cox 已提交
371 372
	result = usb_submit_urb(port->write_urb, GFP_KERNEL);
	if (result) {
373
		port->write_urb_busy = 0;
374 375 376
		dev_err(&port->dev,
			"%s - failed submitting write urb, error %d\n",
			__func__, result);
L
Linus Torvalds 已提交
377 378
		return 0;
	}
A
Alan Cox 已提交
379
	dbg("%s urb: %p submitted", __func__, port->write_urb);
L
Linus Torvalds 已提交
380

A
Alan Cox 已提交
381
	return count;
L
Linus Torvalds 已提交
382 383
}

A
Alan Cox 已提交
384
static int safe_write_room(struct tty_struct *tty)
L
Linus Torvalds 已提交
385
{
A
Alan Cox 已提交
386
	struct usb_serial_port *port = tty->driver_data;
387 388
	int room = 0;		/* Default: no room */
	unsigned long flags;
L
Linus Torvalds 已提交
389

A
Alan Cox 已提交
390
	dbg("%s", __func__);
L
Linus Torvalds 已提交
391

392
	spin_lock_irqsave(&port->lock, flags);
393
	if (port->write_urb_busy)
L
Linus Torvalds 已提交
394
		room = port->bulk_out_size - (safe ? 2 : 0);
395
	spin_unlock_irqrestore(&port->lock, flags);
L
Linus Torvalds 已提交
396

A
Alan Cox 已提交
397 398
	if (room)
		dbg("safe_write_room returns %d", room);
399
	return room;
L
Linus Torvalds 已提交
400 401
}

A
Alan Cox 已提交
402
static int safe_startup(struct usb_serial *serial)
L
Linus Torvalds 已提交
403 404 405 406 407 408 409 410 411 412 413 414 415
{
	switch (serial->interface->cur_altsetting->desc.bInterfaceProtocol) {
	case LINEO_SAFESERIAL_CRC:
		break;
	case LINEO_SAFESERIAL_CRC_PADDED:
		padded = 1;
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

416
static struct usb_serial_driver safe_device = {
417 418
	.driver = {
		.owner =	THIS_MODULE,
419
		.name =		"safe_serial",
420
	},
L
Linus Torvalds 已提交
421
	.id_table =		id_table,
422
	.usb_driver =		&safe_driver,
L
Linus Torvalds 已提交
423 424 425 426 427 428 429
	.num_ports =		1,
	.write =		safe_write,
	.write_room =		safe_write_room,
	.read_bulk_callback =	safe_read_bulk_callback,
	.attach =		safe_startup,
};

A
Alan Cox 已提交
430
static int __init safe_init(void)
L
Linus Torvalds 已提交
431 432 433
{
	int i, retval;

434 435
	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
	       DRIVER_DESC "\n");
L
Linus Torvalds 已提交
436

A
Alan Cox 已提交
437
	/* if we have vendor / product parameters patch them into id list */
L
Linus Torvalds 已提交
438
	if (vendor || product) {
439 440
		printk(KERN_INFO KBUILD_MODNAME ": vendor: %x product: %x\n",
		       vendor, product);
L
Linus Torvalds 已提交
441

442
		for (i = 0; i < ARRAY_SIZE(id_table); i++) {
L
Linus Torvalds 已提交
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
			if (!id_table[i].idVendor && !id_table[i].idProduct) {
				id_table[i].idVendor = vendor;
				id_table[i].idProduct = product;
				break;
			}
		}
	}

	retval = usb_serial_register(&safe_device);
	if (retval)
		goto failed_usb_serial_register;
	retval = usb_register(&safe_driver);
	if (retval)
		goto failed_usb_register;

	return 0;
failed_usb_register:
	usb_serial_deregister(&safe_device);
failed_usb_serial_register:
	return retval;
}

A
Alan Cox 已提交
465
static void __exit safe_exit(void)
L
Linus Torvalds 已提交
466
{
A
Alan Cox 已提交
467 468
	usb_deregister(&safe_driver);
	usb_serial_deregister(&safe_device);
L
Linus Torvalds 已提交
469 470
}

A
Alan Cox 已提交
471 472
module_init(safe_init);
module_exit(safe_exit);