usb-skeleton.c 15.8 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2
 * USB Skeleton driver - 2.2
L
Linus Torvalds 已提交
3 4 5 6 7 8 9
 *
 * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
 *
 *	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, version 2.
 *
10
 * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
11
 * but has been rewritten to be easier to read and use.
L
Linus Torvalds 已提交
12 13 14 15 16 17 18 19 20
 *
 */

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
21
#include <linux/uaccess.h>
L
Linus Torvalds 已提交
22
#include <linux/usb.h>
23
#include <linux/mutex.h>
L
Linus Torvalds 已提交
24 25 26 27 28 29 30


/* Define these values to match your devices */
#define USB_SKEL_VENDOR_ID	0xfff0
#define USB_SKEL_PRODUCT_ID	0xfff0

/* table of devices that work with this driver */
31
static const struct usb_device_id skel_table[] = {
L
Linus Torvalds 已提交
32 33 34
	{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
	{ }					/* Terminating entry */
};
35
MODULE_DEVICE_TABLE(usb, skel_table);
L
Linus Torvalds 已提交
36 37 38 39 40


/* Get a minor range for your devices from the usb maintainer */
#define USB_SKEL_MINOR_BASE	192

41
/* our private defines. if this grows any larger, use your own .h file */
42
#define MAX_TRANSFER		(PAGE_SIZE - 512)
O
Oliver Neukum 已提交
43 44 45
/* MAX_TRANSFER is chosen so that the VM is not stressed by
   allocations > PAGE_SIZE and the number of packets in a page
   is an integer 512 is the largest possible packet on EHCI */
46
#define WRITES_IN_FLIGHT	8
O
Oliver Neukum 已提交
47
/* arbitrarily chosen */
48

L
Linus Torvalds 已提交
49 50
/* Structure to hold all of our device specific stuff */
struct usb_skel {
O
Oliver Neukum 已提交
51 52
	struct usb_device	*udev;			/* the usb device for this device */
	struct usb_interface	*interface;		/* the interface for this device */
53
	struct semaphore	limit_sem;		/* limiting the number of writes in progress */
54
	struct usb_anchor	submitted;		/* in case we need to retract our submissions */
55
	struct urb		*bulk_in_urb;		/* the urb to read data with */
56
	unsigned char           *bulk_in_buffer;	/* the buffer to receive data */
L
Linus Torvalds 已提交
57
	size_t			bulk_in_size;		/* the size of the receive buffer */
58 59
	size_t			bulk_in_filled;		/* number of bytes in the buffer */
	size_t			bulk_in_copied;		/* already copied to user space */
L
Linus Torvalds 已提交
60 61
	__u8			bulk_in_endpointAddr;	/* the address of the bulk in endpoint */
	__u8			bulk_out_endpointAddr;	/* the address of the bulk out endpoint */
62
	int			errors;			/* the last request tanked */
63
	bool			ongoing_read;		/* a read is going on */
64
	spinlock_t		err_lock;		/* lock for errors */
L
Linus Torvalds 已提交
65
	struct kref		kref;
66
	struct mutex		io_mutex;		/* synchronize I/O with disconnect */
67
	wait_queue_head_t	bulk_in_wait;		/* to wait for an ongoing read */
L
Linus Torvalds 已提交
68 69 70 71
};
#define to_skel_dev(d) container_of(d, struct usb_skel, kref)

static struct usb_driver skel_driver;
72
static void skel_draw_down(struct usb_skel *dev);
L
Linus Torvalds 已提交
73 74

static void skel_delete(struct kref *kref)
75
{
L
Linus Torvalds 已提交
76 77
	struct usb_skel *dev = to_skel_dev(kref);

78
	usb_free_urb(dev->bulk_in_urb);
L
Linus Torvalds 已提交
79
	usb_put_dev(dev->udev);
80 81
	kfree(dev->bulk_in_buffer);
	kfree(dev);
L
Linus Torvalds 已提交
82 83 84 85 86 87 88 89 90 91 92 93 94
}

static int skel_open(struct inode *inode, struct file *file)
{
	struct usb_skel *dev;
	struct usb_interface *interface;
	int subminor;
	int retval = 0;

	subminor = iminor(inode);

	interface = usb_find_interface(&skel_driver, subminor);
	if (!interface) {
95 96
		pr_err("%s - error, can't find device for minor %d\n",
			__func__, subminor);
L
Linus Torvalds 已提交
97 98 99 100 101 102 103 104 105 106
		retval = -ENODEV;
		goto exit;
	}

	dev = usb_get_intfdata(interface);
	if (!dev) {
		retval = -ENODEV;
		goto exit;
	}

107 108
	retval = usb_autopm_get_interface(interface);
	if (retval)
109 110 111 112
		goto exit;

	/* increment our usage count for the device */
	kref_get(&dev->kref);
L
Linus Torvalds 已提交
113 114 115 116 117 118 119 120 121 122 123 124

	/* save our object in the file's private structure */
	file->private_data = dev;

exit:
	return retval;
}

static int skel_release(struct inode *inode, struct file *file)
{
	struct usb_skel *dev;

125
	dev = file->private_data;
L
Linus Torvalds 已提交
126 127 128
	if (dev == NULL)
		return -ENODEV;

129 130
	/* allow the device to be autosuspended */
	mutex_lock(&dev->io_mutex);
131
	if (dev->interface)
132 133 134
		usb_autopm_put_interface(dev->interface);
	mutex_unlock(&dev->io_mutex);

L
Linus Torvalds 已提交
135 136 137 138 139
	/* decrement the count on our device */
	kref_put(&dev->kref, skel_delete);
	return 0;
}

140 141 142 143 144
static int skel_flush(struct file *file, fl_owner_t id)
{
	struct usb_skel *dev;
	int res;

145
	dev = file->private_data;
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
	if (dev == NULL)
		return -ENODEV;

	/* wait for io to stop */
	mutex_lock(&dev->io_mutex);
	skel_draw_down(dev);

	/* read out errors, leave subsequent opens a clean slate */
	spin_lock_irq(&dev->err_lock);
	res = dev->errors ? (dev->errors == -EPIPE ? -EPIPE : -EIO) : 0;
	dev->errors = 0;
	spin_unlock_irq(&dev->err_lock);

	mutex_unlock(&dev->io_mutex);

	return res;
}

164 165 166 167 168 169 170 171 172
static void skel_read_bulk_callback(struct urb *urb)
{
	struct usb_skel *dev;

	dev = urb->context;

	spin_lock(&dev->err_lock);
	/* sync/async unlink faults aren't errors */
	if (urb->status) {
173
		if (!(urb->status == -ENOENT ||
174 175
		    urb->status == -ECONNRESET ||
		    urb->status == -ESHUTDOWN))
176 177 178
			dev_err(&dev->interface->dev,
				"%s - nonzero write bulk status received: %d\n",
				__func__, urb->status);
179 180 181 182 183 184 185 186

		dev->errors = urb->status;
	} else {
		dev->bulk_in_filled = urb->actual_length;
	}
	dev->ongoing_read = 0;
	spin_unlock(&dev->err_lock);

187
	wake_up_interruptible(&dev->bulk_in_wait);
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
}

static int skel_do_read_io(struct usb_skel *dev, size_t count)
{
	int rv;

	/* prepare a read */
	usb_fill_bulk_urb(dev->bulk_in_urb,
			dev->udev,
			usb_rcvbulkpipe(dev->udev,
				dev->bulk_in_endpointAddr),
			dev->bulk_in_buffer,
			min(dev->bulk_in_size, count),
			skel_read_bulk_callback,
			dev);
	/* tell everybody to leave the URB alone */
	spin_lock_irq(&dev->err_lock);
	dev->ongoing_read = 1;
	spin_unlock_irq(&dev->err_lock);

208 209 210 211
	/* submit bulk in urb, which means no data to deliver */
	dev->bulk_in_filled = 0;
	dev->bulk_in_copied = 0;

212 213 214
	/* do it */
	rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);
	if (rv < 0) {
215 216
		dev_err(&dev->interface->dev,
			"%s - failed submitting read urb, error %d\n",
217 218 219 220 221 222 223 224 225 226
			__func__, rv);
		rv = (rv == -ENOMEM) ? rv : -EIO;
		spin_lock_irq(&dev->err_lock);
		dev->ongoing_read = 0;
		spin_unlock_irq(&dev->err_lock);
	}

	return rv;
}

227 228
static ssize_t skel_read(struct file *file, char *buffer, size_t count,
			 loff_t *ppos)
L
Linus Torvalds 已提交
229 230
{
	struct usb_skel *dev;
231 232
	int rv;
	bool ongoing_io;
L
Linus Torvalds 已提交
233

234
	dev = file->private_data;
235

236 237 238 239 240 241 242 243 244
	/* if we cannot read at all, return EOF */
	if (!dev->bulk_in_urb || !count)
		return 0;

	/* no concurrent readers */
	rv = mutex_lock_interruptible(&dev->io_mutex);
	if (rv < 0)
		return rv;

245
	if (!dev->interface) {		/* disconnect() was called */
246
		rv = -ENODEV;
247 248 249
		goto exit;
	}

250 251 252 253 254 255 256
	/* if IO is under way, we must not touch things */
retry:
	spin_lock_irq(&dev->err_lock);
	ongoing_io = dev->ongoing_read;
	spin_unlock_irq(&dev->err_lock);

	if (ongoing_io) {
257 258 259 260 261
		/* nonblocking IO shall not wait */
		if (file->f_flags & O_NONBLOCK) {
			rv = -EAGAIN;
			goto exit;
		}
262 263 264 265
		/*
		 * IO may take forever
		 * hence wait in an interruptible state
		 */
266
		rv = wait_event_interruptible(dev->bulk_in_wait, (!dev->ongoing_read));
267 268
		if (rv < 0)
			goto exit;
L
Linus Torvalds 已提交
269 270
	}

271
	/* errors must be reported */
272 273
	rv = dev->errors;
	if (rv < 0) {
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
		/* any error is reported once */
		dev->errors = 0;
		/* to preserve notifications about reset */
		rv = (rv == -EPIPE) ? rv : -EIO;
		/* report it */
		goto exit;
	}

	/*
	 * if the buffer is filled we may satisfy the read
	 * else we need to start IO
	 */

	if (dev->bulk_in_filled) {
		/* we had read data */
		size_t available = dev->bulk_in_filled - dev->bulk_in_copied;
		size_t chunk = min(available, count);

		if (!available) {
			/*
			 * all data has been used
			 * actual IO needs to be done
			 */
			rv = skel_do_read_io(dev, count);
			if (rv < 0)
				goto exit;
			else
				goto retry;
		}
		/*
		 * data is available
		 * chunk tells us how much shall be copied
		 */

		if (copy_to_user(buffer,
				 dev->bulk_in_buffer + dev->bulk_in_copied,
				 chunk))
			rv = -EFAULT;
		else
			rv = chunk;

		dev->bulk_in_copied += chunk;

		/*
		 * if we are asked for more than we have,
		 * we start IO but don't wait
		 */
		if (available < count)
			skel_do_read_io(dev, count - chunk);
	} else {
		/* no data in the buffer */
		rv = skel_do_read_io(dev, count);
		if (rv < 0)
			goto exit;
328
		else
329 330
			goto retry;
	}
331 332
exit:
	mutex_unlock(&dev->io_mutex);
333
	return rv;
L
Linus Torvalds 已提交
334 335
}

336
static void skel_write_bulk_callback(struct urb *urb)
L
Linus Torvalds 已提交
337 338 339
{
	struct usb_skel *dev;

340
	dev = urb->context;
L
Linus Torvalds 已提交
341 342

	/* sync/async unlink faults aren't errors */
343
	if (urb->status) {
344
		if (!(urb->status == -ENOENT ||
345 346
		    urb->status == -ECONNRESET ||
		    urb->status == -ESHUTDOWN))
347 348 349
			dev_err(&dev->interface->dev,
				"%s - nonzero write bulk status received: %d\n",
				__func__, urb->status);
350 351 352 353

		spin_lock(&dev->err_lock);
		dev->errors = urb->status;
		spin_unlock(&dev->err_lock);
L
Linus Torvalds 已提交
354 355 356
	}

	/* free up our allocated buffer */
357 358
	usb_free_coherent(urb->dev, urb->transfer_buffer_length,
			  urb->transfer_buffer, urb->transfer_dma);
359
	up(&dev->limit_sem);
L
Linus Torvalds 已提交
360 361
}

362 363
static ssize_t skel_write(struct file *file, const char *user_buffer,
			  size_t count, loff_t *ppos)
L
Linus Torvalds 已提交
364 365 366 367 368
{
	struct usb_skel *dev;
	int retval = 0;
	struct urb *urb = NULL;
	char *buf = NULL;
369
	size_t writesize = min(count, (size_t)MAX_TRANSFER);
L
Linus Torvalds 已提交
370

371
	dev = file->private_data;
L
Linus Torvalds 已提交
372 373 374 375 376

	/* verify that we actually have some data to write */
	if (count == 0)
		goto exit;

377 378 379 380
	/*
	 * limit the number of URBs in flight to stop a user from using up all
	 * RAM
	 */
381
	if (!(file->f_flags & O_NONBLOCK)) {
382 383 384 385 386 387 388 389 390
		if (down_interruptible(&dev->limit_sem)) {
			retval = -ERESTARTSYS;
			goto exit;
		}
	} else {
		if (down_trylock(&dev->limit_sem)) {
			retval = -EAGAIN;
			goto exit;
		}
391
	}
392

393
	spin_lock_irq(&dev->err_lock);
394 395
	retval = dev->errors;
	if (retval < 0) {
396 397 398 399 400 401 402 403 404
		/* any error is reported once */
		dev->errors = 0;
		/* to preserve notifications about reset */
		retval = (retval == -EPIPE) ? retval : -EIO;
	}
	spin_unlock_irq(&dev->err_lock);
	if (retval < 0)
		goto error;

L
Linus Torvalds 已提交
405 406 407 408 409 410 411
	/* create a urb, and a buffer for it, and copy the data to the urb */
	urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!urb) {
		retval = -ENOMEM;
		goto error;
	}

412 413
	buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL,
				 &urb->transfer_dma);
L
Linus Torvalds 已提交
414 415 416 417 418
	if (!buf) {
		retval = -ENOMEM;
		goto error;
	}

419
	if (copy_from_user(buf, user_buffer, writesize)) {
L
Linus Torvalds 已提交
420 421 422 423
		retval = -EFAULT;
		goto error;
	}

O
Oliver Neukum 已提交
424 425 426 427 428 429 430 431
	/* this lock makes sure we don't submit URBs to gone devices */
	mutex_lock(&dev->io_mutex);
	if (!dev->interface) {		/* disconnect() was called */
		mutex_unlock(&dev->io_mutex);
		retval = -ENODEV;
		goto error;
	}

L
Linus Torvalds 已提交
432 433 434
	/* initialize the urb properly */
	usb_fill_bulk_urb(urb, dev->udev,
			  usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
435
			  buf, writesize, skel_write_bulk_callback, dev);
L
Linus Torvalds 已提交
436
	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
437
	usb_anchor_urb(urb, &dev->submitted);
L
Linus Torvalds 已提交
438 439 440

	/* send the data out the bulk port */
	retval = usb_submit_urb(urb, GFP_KERNEL);
O
Oliver Neukum 已提交
441
	mutex_unlock(&dev->io_mutex);
L
Linus Torvalds 已提交
442
	if (retval) {
443 444 445
		dev_err(&dev->interface->dev,
			"%s - failed submitting write urb, error %d\n",
			__func__, retval);
446
		goto error_unanchor;
L
Linus Torvalds 已提交
447 448
	}

449 450 451 452
	/*
	 * release our reference to this urb, the USB core will eventually free
	 * it entirely
	 */
L
Linus Torvalds 已提交
453 454
	usb_free_urb(urb);

O
Oliver Neukum 已提交
455

456
	return writesize;
L
Linus Torvalds 已提交
457

458 459
error_unanchor:
	usb_unanchor_urb(urb);
L
Linus Torvalds 已提交
460
error:
461
	if (urb) {
462
		usb_free_coherent(dev->udev, writesize, buf, urb->transfer_dma);
463 464
		usb_free_urb(urb);
	}
465
	up(&dev->limit_sem);
466 467

exit:
L
Linus Torvalds 已提交
468 469 470
	return retval;
}

471
static const struct file_operations skel_fops = {
L
Linus Torvalds 已提交
472 473 474 475 476
	.owner =	THIS_MODULE,
	.read =		skel_read,
	.write =	skel_write,
	.open =		skel_open,
	.release =	skel_release,
477
	.flush =	skel_flush,
478
	.llseek =	noop_llseek,
L
Linus Torvalds 已提交
479 480
};

481
/*
L
Linus Torvalds 已提交
482
 * usb class driver info in order to get a minor number from the usb core,
483
 * and to have the device registered with the driver core
L
Linus Torvalds 已提交
484 485
 */
static struct usb_class_driver skel_class = {
486
	.name =		"skel%d",
L
Linus Torvalds 已提交
487 488 489 490
	.fops =		&skel_fops,
	.minor_base =	USB_SKEL_MINOR_BASE,
};

491 492
static int skel_probe(struct usb_interface *interface,
		      const struct usb_device_id *id)
L
Linus Torvalds 已提交
493
{
494
	struct usb_skel *dev;
L
Linus Torvalds 已提交
495 496 497 498 499 500 501
	struct usb_host_interface *iface_desc;
	struct usb_endpoint_descriptor *endpoint;
	size_t buffer_size;
	int i;
	int retval = -ENOMEM;

	/* allocate memory for our device state and initialize it */
502
	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
503
	if (!dev) {
504
		dev_err(&interface->dev, "Out of memory\n");
L
Linus Torvalds 已提交
505 506 507
		goto error;
	}
	kref_init(&dev->kref);
508
	sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
509
	mutex_init(&dev->io_mutex);
510 511
	spin_lock_init(&dev->err_lock);
	init_usb_anchor(&dev->submitted);
512
	init_waitqueue_head(&dev->bulk_in_wait);
L
Linus Torvalds 已提交
513 514 515 516 517 518 519 520 521 522 523

	dev->udev = usb_get_dev(interface_to_usbdev(interface));
	dev->interface = interface;

	/* set up the endpoint information */
	/* use only the first bulk-in and bulk-out endpoints */
	iface_desc = interface->cur_altsetting;
	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
		endpoint = &iface_desc->endpoint[i].desc;

		if (!dev->bulk_in_endpointAddr &&
524
		    usb_endpoint_is_bulk_in(endpoint)) {
L
Linus Torvalds 已提交
525
			/* we found a bulk in endpoint */
526
			buffer_size = usb_endpoint_maxp(endpoint);
L
Linus Torvalds 已提交
527 528 529 530
			dev->bulk_in_size = buffer_size;
			dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
			dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
			if (!dev->bulk_in_buffer) {
531 532
				dev_err(&interface->dev,
					"Could not allocate bulk_in_buffer\n");
L
Linus Torvalds 已提交
533 534
				goto error;
			}
535 536
			dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);
			if (!dev->bulk_in_urb) {
537 538
				dev_err(&interface->dev,
					"Could not allocate bulk_in_urb\n");
539 540
				goto error;
			}
L
Linus Torvalds 已提交
541 542 543
		}

		if (!dev->bulk_out_endpointAddr &&
544
		    usb_endpoint_is_bulk_out(endpoint)) {
L
Linus Torvalds 已提交
545 546 547 548 549
			/* we found a bulk out endpoint */
			dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
		}
	}
	if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
550 551
		dev_err(&interface->dev,
			"Could not find both bulk-in and bulk-out endpoints\n");
L
Linus Torvalds 已提交
552 553 554 555 556 557 558 559 560 561
		goto error;
	}

	/* save our data pointer in this interface device */
	usb_set_intfdata(interface, dev);

	/* we can register the device now, as it is ready */
	retval = usb_register_dev(interface, &skel_class);
	if (retval) {
		/* something prevented us from registering this driver */
562 563
		dev_err(&interface->dev,
			"Not able to get a minor for this device.\n");
L
Linus Torvalds 已提交
564 565 566 567 568
		usb_set_intfdata(interface, NULL);
		goto error;
	}

	/* let the user know what node this device is now attached to */
569 570 571
	dev_info(&interface->dev,
		 "USB Skeleton device now attached to USBSkel-%d",
		 interface->minor);
L
Linus Torvalds 已提交
572 573 574 575
	return 0;

error:
	if (dev)
O
Oliver Neukum 已提交
576
		/* this frees allocated memory */
L
Linus Torvalds 已提交
577 578 579 580 581 582 583 584 585 586
		kref_put(&dev->kref, skel_delete);
	return retval;
}

static void skel_disconnect(struct usb_interface *interface)
{
	struct usb_skel *dev;
	int minor = interface->minor;

	dev = usb_get_intfdata(interface);
587
	usb_set_intfdata(interface, NULL);
L
Linus Torvalds 已提交
588 589 590 591

	/* give back our minor */
	usb_deregister_dev(interface, &skel_class);

592 593 594 595 596
	/* prevent more I/O from starting */
	mutex_lock(&dev->io_mutex);
	dev->interface = NULL;
	mutex_unlock(&dev->io_mutex);

597 598
	usb_kill_anchored_urbs(&dev->submitted);

L
Linus Torvalds 已提交
599 600 601
	/* decrement our usage count */
	kref_put(&dev->kref, skel_delete);

602
	dev_info(&interface->dev, "USB Skeleton #%d now disconnected", minor);
L
Linus Torvalds 已提交
603 604
}

605 606 607 608 609 610 611
static void skel_draw_down(struct usb_skel *dev)
{
	int time;

	time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000);
	if (!time)
		usb_kill_anchored_urbs(&dev->submitted);
612
	usb_kill_urb(dev->bulk_in_urb);
613 614
}

615 616 617 618 619 620 621 622 623 624
static int skel_suspend(struct usb_interface *intf, pm_message_t message)
{
	struct usb_skel *dev = usb_get_intfdata(intf);

	if (!dev)
		return 0;
	skel_draw_down(dev);
	return 0;
}

625
static int skel_resume(struct usb_interface *intf)
626 627 628 629
{
	return 0;
}

630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650
static int skel_pre_reset(struct usb_interface *intf)
{
	struct usb_skel *dev = usb_get_intfdata(intf);

	mutex_lock(&dev->io_mutex);
	skel_draw_down(dev);

	return 0;
}

static int skel_post_reset(struct usb_interface *intf)
{
	struct usb_skel *dev = usb_get_intfdata(intf);

	/* we are sure no URBs are active - no locking needed */
	dev->errors = -EPIPE;
	mutex_unlock(&dev->io_mutex);

	return 0;
}

L
Linus Torvalds 已提交
651 652 653 654
static struct usb_driver skel_driver = {
	.name =		"skeleton",
	.probe =	skel_probe,
	.disconnect =	skel_disconnect,
655 656
	.suspend =	skel_suspend,
	.resume =	skel_resume,
657 658
	.pre_reset =	skel_pre_reset,
	.post_reset =	skel_post_reset,
L
Linus Torvalds 已提交
659
	.id_table =	skel_table,
O
Oliver Neukum 已提交
660
	.supports_autosuspend = 1,
L
Linus Torvalds 已提交
661 662
};

663
module_usb_driver(skel_driver);
L
Linus Torvalds 已提交
664 665

MODULE_LICENSE("GPL");