usb-skeleton.c 17.0 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
	int			open_count;		/* count the number of openers */
64 65
	bool			ongoing_read;		/* a read is going on */
	bool			processed_urb;		/* indicates we haven't processed the urb */
66
	spinlock_t		err_lock;		/* lock for errors */
L
Linus Torvalds 已提交
67
	struct kref		kref;
68
	struct mutex		io_mutex;		/* synchronize I/O with disconnect */
69
	struct completion	bulk_in_completion;	/* to wait for an ongoing read */
L
Linus Torvalds 已提交
70 71 72 73
};
#define to_skel_dev(d) container_of(d, struct usb_skel, kref)

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

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

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

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) {
97
		err("%s - error, can't find device for minor %d",
98
		     __func__, subminor);
L
Linus Torvalds 已提交
99 100 101 102 103 104 105 106 107 108
		retval = -ENODEV;
		goto exit;
	}

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

109 110 111
	/* increment our usage count for the device */
	kref_get(&dev->kref);

112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
	/* lock the device to allow correctly handling errors
	 * in resumption */
	mutex_lock(&dev->io_mutex);

	if (!dev->open_count++) {
		retval = usb_autopm_get_interface(interface);
			if (retval) {
				dev->open_count--;
				mutex_unlock(&dev->io_mutex);
				kref_put(&dev->kref, skel_delete);
				goto exit;
			}
	} /* else { //uncomment this block if you want exclusive open
		retval = -EBUSY;
		dev->open_count--;
		mutex_unlock(&dev->io_mutex);
128
		kref_put(&dev->kref, skel_delete);
129
		goto exit;
130 131
	} */
	/* prevent the device from being autosuspended */
L
Linus Torvalds 已提交
132 133 134

	/* save our object in the file's private structure */
	file->private_data = dev;
135
	mutex_unlock(&dev->io_mutex);
L
Linus Torvalds 已提交
136 137 138 139 140 141 142 143 144 145 146 147 148

exit:
	return retval;
}

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

	dev = (struct usb_skel *)file->private_data;
	if (dev == NULL)
		return -ENODEV;

149 150
	/* allow the device to be autosuspended */
	mutex_lock(&dev->io_mutex);
151
	if (!--dev->open_count && dev->interface)
152 153 154
		usb_autopm_put_interface(dev->interface);
	mutex_unlock(&dev->io_mutex);

L
Linus Torvalds 已提交
155 156 157 158 159
	/* decrement the count on our device */
	kref_put(&dev->kref, skel_delete);
	return 0;
}

160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
static int skel_flush(struct file *file, fl_owner_t id)
{
	struct usb_skel *dev;
	int res;

	dev = (struct usb_skel *)file->private_data;
	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;
}

184 185 186 187 188 189 190 191 192
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) {
193
		if (!(urb->status == -ENOENT ||
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
		    urb->status == -ECONNRESET ||
		    urb->status == -ESHUTDOWN))
			err("%s - nonzero write bulk status received: %d",
			    __func__, urb->status);

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

	complete(&dev->bulk_in_completion);
}

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

	/* do it */
	rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);
	if (rv < 0) {
		err("%s - failed submitting read urb, error %d",
			__func__, rv);
		dev->bulk_in_filled = 0;
		rv = (rv == -ENOMEM) ? rv : -EIO;
		spin_lock_irq(&dev->err_lock);
		dev->ongoing_read = 0;
		spin_unlock_irq(&dev->err_lock);
	}

	return rv;
}

242 243
static ssize_t skel_read(struct file *file, char *buffer, size_t count,
			 loff_t *ppos)
L
Linus Torvalds 已提交
244 245
{
	struct usb_skel *dev;
246 247
	int rv;
	bool ongoing_io;
L
Linus Torvalds 已提交
248 249

	dev = (struct usb_skel *)file->private_data;
250

251 252 253 254 255 256 257 258 259
	/* 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;

260
	if (!dev->interface) {		/* disconnect() was called */
261
		rv = -ENODEV;
262 263 264
		goto exit;
	}

265 266 267 268 269 270 271
	/* 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) {
272 273 274 275 276
		/* nonblocking IO shall not wait */
		if (file->f_flags & O_NONBLOCK) {
			rv = -EAGAIN;
			goto exit;
		}
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
		/*
		 * IO may take forever
		 * hence wait in an interruptible state
		 */
		rv = wait_for_completion_interruptible(&dev->bulk_in_completion);
		if (rv < 0)
			goto exit;
		/*
		 * by waiting we also semiprocessed the urb
		 * we must finish now
		 */
		dev->bulk_in_copied = 0;
		dev->processed_urb = 1;
	}

	if (!dev->processed_urb) {
		/*
		 * the URB hasn't been processed
		 * do it now
		 */
		wait_for_completion(&dev->bulk_in_completion);
		dev->bulk_in_copied = 0;
		dev->processed_urb = 1;
L
Linus Torvalds 已提交
300 301
	}

302
	/* errors must be reported */
303 304
	rv = dev->errors;
	if (rv < 0) {
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
		/* any error is reported once */
		dev->errors = 0;
		/* to preserve notifications about reset */
		rv = (rv == -EPIPE) ? rv : -EIO;
		/* no data to deliver */
		dev->bulk_in_filled = 0;
		/* 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;
361
		else if (!(file->f_flags & O_NONBLOCK))
362
			goto retry;
363
		rv = -EAGAIN;
364
	}
365 366
exit:
	mutex_unlock(&dev->io_mutex);
367
	return rv;
L
Linus Torvalds 已提交
368 369
}

370
static void skel_write_bulk_callback(struct urb *urb)
L
Linus Torvalds 已提交
371 372 373
{
	struct usb_skel *dev;

374
	dev = urb->context;
L
Linus Torvalds 已提交
375 376

	/* sync/async unlink faults aren't errors */
377
	if (urb->status) {
378
		if (!(urb->status == -ENOENT ||
379 380 381
		    urb->status == -ECONNRESET ||
		    urb->status == -ESHUTDOWN))
			err("%s - nonzero write bulk status received: %d",
382
			    __func__, urb->status);
383 384 385 386

		spin_lock(&dev->err_lock);
		dev->errors = urb->status;
		spin_unlock(&dev->err_lock);
L
Linus Torvalds 已提交
387 388 389
	}

	/* free up our allocated buffer */
390
	usb_buffer_free(urb->dev, urb->transfer_buffer_length,
L
Linus Torvalds 已提交
391
			urb->transfer_buffer, urb->transfer_dma);
392
	up(&dev->limit_sem);
L
Linus Torvalds 已提交
393 394
}

395 396
static ssize_t skel_write(struct file *file, const char *user_buffer,
			  size_t count, loff_t *ppos)
L
Linus Torvalds 已提交
397 398 399 400 401
{
	struct usb_skel *dev;
	int retval = 0;
	struct urb *urb = NULL;
	char *buf = NULL;
402
	size_t writesize = min(count, (size_t)MAX_TRANSFER);
L
Linus Torvalds 已提交
403 404 405 406 407 408 409

	dev = (struct usb_skel *)file->private_data;

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

410 411 412 413
	/*
	 * limit the number of URBs in flight to stop a user from using up all
	 * RAM
	 */
414
	if (!(file->f_flags & O_NONBLOCK)) {
415 416 417 418 419 420 421 422 423
		if (down_interruptible(&dev->limit_sem)) {
			retval = -ERESTARTSYS;
			goto exit;
		}
	} else {
		if (down_trylock(&dev->limit_sem)) {
			retval = -EAGAIN;
			goto exit;
		}
424
	}
425

426
	spin_lock_irq(&dev->err_lock);
427 428
	retval = dev->errors;
	if (retval < 0) {
429 430 431 432 433 434 435 436 437
		/* 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 已提交
438 439 440 441 442 443 444
	/* 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;
	}

445 446
	buf = usb_buffer_alloc(dev->udev, writesize, GFP_KERNEL,
			       &urb->transfer_dma);
L
Linus Torvalds 已提交
447 448 449 450 451
	if (!buf) {
		retval = -ENOMEM;
		goto error;
	}

452
	if (copy_from_user(buf, user_buffer, writesize)) {
L
Linus Torvalds 已提交
453 454 455 456
		retval = -EFAULT;
		goto error;
	}

O
Oliver Neukum 已提交
457 458 459 460 461 462 463 464
	/* 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 已提交
465 466 467
	/* initialize the urb properly */
	usb_fill_bulk_urb(urb, dev->udev,
			  usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
468
			  buf, writesize, skel_write_bulk_callback, dev);
L
Linus Torvalds 已提交
469
	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
470
	usb_anchor_urb(urb, &dev->submitted);
L
Linus Torvalds 已提交
471 472 473

	/* send the data out the bulk port */
	retval = usb_submit_urb(urb, GFP_KERNEL);
O
Oliver Neukum 已提交
474
	mutex_unlock(&dev->io_mutex);
L
Linus Torvalds 已提交
475
	if (retval) {
476 477
		err("%s - failed submitting write urb, error %d", __func__,
		    retval);
478
		goto error_unanchor;
L
Linus Torvalds 已提交
479 480
	}

481 482 483 484
	/*
	 * release our reference to this urb, the USB core will eventually free
	 * it entirely
	 */
L
Linus Torvalds 已提交
485 486
	usb_free_urb(urb);

O
Oliver Neukum 已提交
487

488
	return writesize;
L
Linus Torvalds 已提交
489

490 491
error_unanchor:
	usb_unanchor_urb(urb);
L
Linus Torvalds 已提交
492
error:
493 494 495 496
	if (urb) {
		usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
		usb_free_urb(urb);
	}
497
	up(&dev->limit_sem);
498 499

exit:
L
Linus Torvalds 已提交
500 501 502
	return retval;
}

503
static const struct file_operations skel_fops = {
L
Linus Torvalds 已提交
504 505 506 507 508
	.owner =	THIS_MODULE,
	.read =		skel_read,
	.write =	skel_write,
	.open =		skel_open,
	.release =	skel_release,
509
	.flush =	skel_flush,
L
Linus Torvalds 已提交
510 511
};

512
/*
L
Linus Torvalds 已提交
513
 * usb class driver info in order to get a minor number from the usb core,
514
 * and to have the device registered with the driver core
L
Linus Torvalds 已提交
515 516
 */
static struct usb_class_driver skel_class = {
517
	.name =		"skel%d",
L
Linus Torvalds 已提交
518 519 520 521
	.fops =		&skel_fops,
	.minor_base =	USB_SKEL_MINOR_BASE,
};

522 523
static int skel_probe(struct usb_interface *interface,
		      const struct usb_device_id *id)
L
Linus Torvalds 已提交
524
{
525
	struct usb_skel *dev;
L
Linus Torvalds 已提交
526 527 528 529 530 531 532
	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 */
533
	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
534
	if (!dev) {
L
Linus Torvalds 已提交
535 536 537 538
		err("Out of memory");
		goto error;
	}
	kref_init(&dev->kref);
539
	sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
540
	mutex_init(&dev->io_mutex);
541 542
	spin_lock_init(&dev->err_lock);
	init_usb_anchor(&dev->submitted);
543
	init_completion(&dev->bulk_in_completion);
L
Linus Torvalds 已提交
544 545 546 547 548 549 550 551 552 553 554

	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 &&
555
		    usb_endpoint_is_bulk_in(endpoint)) {
L
Linus Torvalds 已提交
556 557 558 559 560 561 562 563 564
			/* we found a bulk in endpoint */
			buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
			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) {
				err("Could not allocate bulk_in_buffer");
				goto error;
			}
565 566 567 568 569
			dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);
			if (!dev->bulk_in_urb) {
				err("Could not allocate bulk_in_urb");
				goto error;
			}
L
Linus Torvalds 已提交
570 571 572
		}

		if (!dev->bulk_out_endpointAddr &&
573
		    usb_endpoint_is_bulk_out(endpoint)) {
L
Linus Torvalds 已提交
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
			/* we found a bulk out endpoint */
			dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
		}
	}
	if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
		err("Could not find both bulk-in and bulk-out endpoints");
		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 */
		err("Not able to get a minor for this device.");
		usb_set_intfdata(interface, NULL);
		goto error;
	}

	/* let the user know what node this device is now attached to */
596 597 598
	dev_info(&interface->dev,
		 "USB Skeleton device now attached to USBSkel-%d",
		 interface->minor);
L
Linus Torvalds 已提交
599 600 601 602
	return 0;

error:
	if (dev)
O
Oliver Neukum 已提交
603
		/* this frees allocated memory */
L
Linus Torvalds 已提交
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618
		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);
	usb_set_intfdata(interface, NULL);

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

619 620 621 622 623
	/* prevent more I/O from starting */
	mutex_lock(&dev->io_mutex);
	dev->interface = NULL;
	mutex_unlock(&dev->io_mutex);

624 625
	usb_kill_anchored_urbs(&dev->submitted);

L
Linus Torvalds 已提交
626 627 628
	/* decrement our usage count */
	kref_put(&dev->kref, skel_delete);

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

632 633 634 635 636 637 638
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);
639
	usb_kill_urb(dev->bulk_in_urb);
640 641
}

642 643 644 645 646 647 648 649 650 651
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;
}

652
static int skel_resume(struct usb_interface *intf)
653 654 655 656
{
	return 0;
}

657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
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 已提交
678 679 680 681
static struct usb_driver skel_driver = {
	.name =		"skeleton",
	.probe =	skel_probe,
	.disconnect =	skel_disconnect,
682 683
	.suspend =	skel_suspend,
	.resume =	skel_resume,
684 685
	.pre_reset =	skel_pre_reset,
	.post_reset =	skel_post_reset,
L
Linus Torvalds 已提交
686
	.id_table =	skel_table,
O
Oliver Neukum 已提交
687
	.supports_autosuspend = 1,
L
Linus Torvalds 已提交
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
};

static int __init usb_skel_init(void)
{
	int result;

	/* register this driver with the USB subsystem */
	result = usb_register(&skel_driver);
	if (result)
		err("usb_register failed. Error number %d", result);

	return result;
}

static void __exit usb_skel_exit(void)
{
	/* deregister this driver with the USB subsystem */
	usb_deregister(&skel_driver);
}

708 709
module_init(usb_skel_init);
module_exit(usb_skel_exit);
L
Linus Torvalds 已提交
710 711

MODULE_LICENSE("GPL");