Blame view

drivers/usb/usb-skeleton.c 16.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
c07045412   Luiz Fernando N. Capitulino   usb-skeleton: sma...
2
   * USB Skeleton driver - 2.2
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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.
   *
c07045412   Luiz Fernando N. Capitulino   usb-skeleton: sma...
10
   * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
121e287cb   Alan Stern   usb-skeleton: don...
11
   * but has been rewritten to be easier to read and use.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
  #include <linux/kernel.h>
  #include <linux/errno.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/module.h>
  #include <linux/kref.h>
3ae9da1c9   Greg Kroah-Hartman   USB: skeleton: fi...
20
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  #include <linux/usb.h>
121e287cb   Alan Stern   usb-skeleton: don...
22
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
  
  
  /* Define these values to match your devices */
  #define USB_SKEL_VENDOR_ID	0xfff0
  #define USB_SKEL_PRODUCT_ID	0xfff0
26c71a79c   Ming Lei   USB: usb-skeleton...
28
  static DEFINE_MUTEX(skel_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  /* table of devices that work with this driver */
1bd4f29d0   Németh Márton   USB skeleton: mak...
30
  static const struct usb_device_id skel_table[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
  	{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
  	{ }					/* Terminating entry */
  };
c07045412   Luiz Fernando N. Capitulino   usb-skeleton: sma...
34
  MODULE_DEVICE_TABLE(usb, skel_table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
  
  
  /* Get a minor range for your devices from the usb maintainer */
  #define USB_SKEL_MINOR_BASE	192
ff9065188   Oliver Neukum   [PATCH] USB: Limi...
39
  /* our private defines. if this grows any larger, use your own .h file */
c07045412   Luiz Fernando N. Capitulino   usb-skeleton: sma...
40
  #define MAX_TRANSFER		(PAGE_SIZE - 512)
ba35e02bd   Oliver Neukum   USB: fix skeleton...
41
42
43
  /* 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 */
ff9065188   Oliver Neukum   [PATCH] USB: Limi...
44
  #define WRITES_IN_FLIGHT	8
ba35e02bd   Oliver Neukum   USB: fix skeleton...
45
  /* arbitrarily chosen */
ff9065188   Oliver Neukum   [PATCH] USB: Limi...
46

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
  /* Structure to hold all of our device specific stuff */
  struct usb_skel {
ba35e02bd   Oliver Neukum   USB: fix skeleton...
49
50
  	struct usb_device	*udev;			/* the usb device for this device */
  	struct usb_interface	*interface;		/* the interface for this device */
ff9065188   Oliver Neukum   [PATCH] USB: Limi...
51
  	struct semaphore	limit_sem;		/* limiting the number of writes in progress */
403dfb58c   Oliver Neukum   USB: usb-skeleton...
52
  	struct usb_anchor	submitted;		/* in case we need to retract our submissions */
e7389cc9a   Oliver Neukum   USB: skel_read re...
53
  	struct urb		*bulk_in_urb;		/* the urb to read data with */
c07045412   Luiz Fernando N. Capitulino   usb-skeleton: sma...
54
  	unsigned char           *bulk_in_buffer;	/* the buffer to receive data */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  	size_t			bulk_in_size;		/* the size of the receive buffer */
e7389cc9a   Oliver Neukum   USB: skel_read re...
56
57
  	size_t			bulk_in_filled;		/* number of bytes in the buffer */
  	size_t			bulk_in_copied;		/* already copied to user space */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
  	__u8			bulk_in_endpointAddr;	/* the address of the bulk in endpoint */
  	__u8			bulk_out_endpointAddr;	/* the address of the bulk out endpoint */
403dfb58c   Oliver Neukum   USB: usb-skeleton...
60
  	int			errors;			/* the last request tanked */
e7389cc9a   Oliver Neukum   USB: skel_read re...
61
62
  	bool			ongoing_read;		/* a read is going on */
  	bool			processed_urb;		/* indicates we haven't processed the urb */
403dfb58c   Oliver Neukum   USB: usb-skeleton...
63
  	spinlock_t		err_lock;		/* lock for errors */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  	struct kref		kref;
121e287cb   Alan Stern   usb-skeleton: don...
65
  	struct mutex		io_mutex;		/* synchronize I/O with disconnect */
e7389cc9a   Oliver Neukum   USB: skel_read re...
66
  	struct completion	bulk_in_completion;	/* to wait for an ongoing read */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
  };
  #define to_skel_dev(d) container_of(d, struct usb_skel, kref)
  
  static struct usb_driver skel_driver;
403dfb58c   Oliver Neukum   USB: usb-skeleton...
71
  static void skel_draw_down(struct usb_skel *dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
  
  static void skel_delete(struct kref *kref)
c07045412   Luiz Fernando N. Capitulino   usb-skeleton: sma...
74
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  	struct usb_skel *dev = to_skel_dev(kref);
e7389cc9a   Oliver Neukum   USB: skel_read re...
76
  	usb_free_urb(dev->bulk_in_urb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
  	usb_put_dev(dev->udev);
c07045412   Luiz Fernando N. Capitulino   usb-skeleton: sma...
78
79
  	kfree(dev->bulk_in_buffer);
  	kfree(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
82
83
84
85
86
87
88
89
90
91
92
  }
  
  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) {
3ae9da1c9   Greg Kroah-Hartman   USB: skeleton: fi...
93
  		err("%s - error, can't find device for minor %d",
441b62c1e   Harvey Harrison   USB: replace rema...
94
  		     __func__, subminor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
  		retval = -ENODEV;
  		goto exit;
  	}
26c71a79c   Ming Lei   USB: usb-skeleton...
98
  	mutex_lock(&skel_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
  	dev = usb_get_intfdata(interface);
  	if (!dev) {
26c71a79c   Ming Lei   USB: usb-skeleton...
101
  		mutex_unlock(&skel_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
  		retval = -ENODEV;
  		goto exit;
  	}
5b0647081   Oliver Neukum   USB: fix autosusp...
105
106
  	/* increment our usage count for the device */
  	kref_get(&dev->kref);
26c71a79c   Ming Lei   USB: usb-skeleton...
107
  	mutex_unlock(&skel_mutex);
5b0647081   Oliver Neukum   USB: fix autosusp...
108

758f7e161   Oliver Neukum   USB: usb-skeleton...
109
110
111
  	/* lock the device to allow correctly handling errors
  	 * in resumption */
  	mutex_lock(&dev->io_mutex);
26c71a79c   Ming Lei   USB: usb-skeleton...
112
113
114
115
  	if (!dev->interface) {
  		retval = -ENODEV;
  		goto out_err;
  	}
758f7e161   Oliver Neukum   USB: usb-skeleton...
116

e28dbb066   Ming Lei   USB: usb-skeleton...
117
118
119
  	retval = usb_autopm_get_interface(interface);
  	if (retval)
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
122
  
  	/* save our object in the file's private structure */
  	file->private_data = dev;
26c71a79c   Ming Lei   USB: usb-skeleton...
123
124
  
  out_err:
f7294055a   Mark Gross   USB: usb-skeleton...
125
  	mutex_unlock(&dev->io_mutex);
26c71a79c   Ming Lei   USB: usb-skeleton...
126
127
  	if (retval)
  		kref_put(&dev->kref, skel_delete);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
131
132
133
134
135
  
  exit:
  	return retval;
  }
  
  static int skel_release(struct inode *inode, struct file *file)
  {
  	struct usb_skel *dev;
e53e841d4   Joe Perches   USB: usb-skeleton...
136
  	dev = file->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
  	if (dev == NULL)
  		return -ENODEV;
01d883d44   Alan Stern   usbcore: non-hub-...
139
140
  	/* allow the device to be autosuspended */
  	mutex_lock(&dev->io_mutex);
e28dbb066   Ming Lei   USB: usb-skeleton...
141
  	if (dev->interface)
01d883d44   Alan Stern   usbcore: non-hub-...
142
143
  		usb_autopm_put_interface(dev->interface);
  	mutex_unlock(&dev->io_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
147
  	/* decrement the count on our device */
  	kref_put(&dev->kref, skel_delete);
  	return 0;
  }
403dfb58c   Oliver Neukum   USB: usb-skeleton...
148
149
150
151
  static int skel_flush(struct file *file, fl_owner_t id)
  {
  	struct usb_skel *dev;
  	int res;
e53e841d4   Joe Perches   USB: usb-skeleton...
152
  	dev = file->private_data;
403dfb58c   Oliver Neukum   USB: usb-skeleton...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
  	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;
  }
e7389cc9a   Oliver Neukum   USB: skel_read re...
170
171
172
173
174
175
176
177
178
  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) {
3ae9da1c9   Greg Kroah-Hartman   USB: skeleton: fi...
179
  		if (!(urb->status == -ENOENT ||
e7389cc9a   Oliver Neukum   USB: skel_read re...
180
181
182
183
184
185
186
187
188
189
190
191
192
193
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
  		    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;
  }
3ae9da1c9   Greg Kroah-Hartman   USB: skeleton: fi...
227
228
  static ssize_t skel_read(struct file *file, char *buffer, size_t count,
  			 loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
  {
  	struct usb_skel *dev;
e7389cc9a   Oliver Neukum   USB: skel_read re...
231
232
  	int rv;
  	bool ongoing_io;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233

e53e841d4   Joe Perches   USB: usb-skeleton...
234
  	dev = file->private_data;
121e287cb   Alan Stern   usb-skeleton: don...
235

e7389cc9a   Oliver Neukum   USB: skel_read re...
236
237
238
239
240
241
242
243
  	/* 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;
121e287cb   Alan Stern   usb-skeleton: don...
244
  	if (!dev->interface) {		/* disconnect() was called */
e7389cc9a   Oliver Neukum   USB: skel_read re...
245
  		rv = -ENODEV;
121e287cb   Alan Stern   usb-skeleton: don...
246
247
  		goto exit;
  	}
e7389cc9a   Oliver Neukum   USB: skel_read re...
248
249
250
251
252
253
254
  	/* 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) {
8cd016643   Oliver Neukum   USB: O_NONBLOCK i...
255
256
257
258
259
  		/* nonblocking IO shall not wait */
  		if (file->f_flags & O_NONBLOCK) {
  			rv = -EAGAIN;
  			goto exit;
  		}
e7389cc9a   Oliver Neukum   USB: skel_read re...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  		/*
  		 * 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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  	}
e7389cc9a   Oliver Neukum   USB: skel_read re...
284
  	/* errors must be reported */
3ae9da1c9   Greg Kroah-Hartman   USB: skeleton: fi...
285
286
  	rv = dev->errors;
  	if (rv < 0) {
e7389cc9a   Oliver Neukum   USB: skel_read re...
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
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
  		/* 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;
4de840575   Julia Lawall   USB: skeleton: Co...
343
  		else if (!(file->f_flags & O_NONBLOCK))
e7389cc9a   Oliver Neukum   USB: skel_read re...
344
  			goto retry;
8cd016643   Oliver Neukum   USB: O_NONBLOCK i...
345
  		rv = -EAGAIN;
e7389cc9a   Oliver Neukum   USB: skel_read re...
346
  	}
121e287cb   Alan Stern   usb-skeleton: don...
347
348
  exit:
  	mutex_unlock(&dev->io_mutex);
e7389cc9a   Oliver Neukum   USB: skel_read re...
349
  	return rv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
  }
7d12e780e   David Howells   IRQ: Maintain reg...
351
  static void skel_write_bulk_callback(struct urb *urb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
  {
  	struct usb_skel *dev;
cdc977922   Ming Lei   USB: remove unnec...
354
  	dev = urb->context;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
  
  	/* sync/async unlink faults aren't errors */
403dfb58c   Oliver Neukum   USB: usb-skeleton...
357
  	if (urb->status) {
3ae9da1c9   Greg Kroah-Hartman   USB: skeleton: fi...
358
  		if (!(urb->status == -ENOENT ||
403dfb58c   Oliver Neukum   USB: usb-skeleton...
359
360
361
  		    urb->status == -ECONNRESET ||
  		    urb->status == -ESHUTDOWN))
  			err("%s - nonzero write bulk status received: %d",
441b62c1e   Harvey Harrison   USB: replace rema...
362
  			    __func__, urb->status);
403dfb58c   Oliver Neukum   USB: usb-skeleton...
363
364
365
366
  
  		spin_lock(&dev->err_lock);
  		dev->errors = urb->status;
  		spin_unlock(&dev->err_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
  	}
  
  	/* free up our allocated buffer */
997ea58eb   Daniel Mack   USB: rename usb_b...
370
371
  	usb_free_coherent(urb->dev, urb->transfer_buffer_length,
  			  urb->transfer_buffer, urb->transfer_dma);
ff9065188   Oliver Neukum   [PATCH] USB: Limi...
372
  	up(&dev->limit_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
  }
3ae9da1c9   Greg Kroah-Hartman   USB: skeleton: fi...
374
375
  static ssize_t skel_write(struct file *file, const char *user_buffer,
  			  size_t count, loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
377
378
379
380
  {
  	struct usb_skel *dev;
  	int retval = 0;
  	struct urb *urb = NULL;
  	char *buf = NULL;
c8dd7709c   Sam Bishop   [PATCH] USB: fix ...
381
  	size_t writesize = min(count, (size_t)MAX_TRANSFER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382

e53e841d4   Joe Perches   USB: usb-skeleton...
383
  	dev = file->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
386
387
  
  	/* verify that we actually have some data to write */
  	if (count == 0)
  		goto exit;
3ae9da1c9   Greg Kroah-Hartman   USB: skeleton: fi...
388
389
390
391
  	/*
  	 * limit the number of URBs in flight to stop a user from using up all
  	 * RAM
  	 */
4de840575   Julia Lawall   USB: skeleton: Co...
392
  	if (!(file->f_flags & O_NONBLOCK)) {
798199867   Oliver Neukum   USB: make usb-ske...
393
394
395
396
397
398
399
400
401
  		if (down_interruptible(&dev->limit_sem)) {
  			retval = -ERESTARTSYS;
  			goto exit;
  		}
  	} else {
  		if (down_trylock(&dev->limit_sem)) {
  			retval = -EAGAIN;
  			goto exit;
  		}
c8dd7709c   Sam Bishop   [PATCH] USB: fix ...
402
  	}
ff9065188   Oliver Neukum   [PATCH] USB: Limi...
403

403dfb58c   Oliver Neukum   USB: usb-skeleton...
404
  	spin_lock_irq(&dev->err_lock);
3ae9da1c9   Greg Kroah-Hartman   USB: skeleton: fi...
405
406
  	retval = dev->errors;
  	if (retval < 0) {
403dfb58c   Oliver Neukum   USB: usb-skeleton...
407
408
409
410
411
412
413
414
  		/* 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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
418
419
420
  	/* 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;
  	}
997ea58eb   Daniel Mack   USB: rename usb_b...
421
422
  	buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL,
  				 &urb->transfer_dma);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
424
425
426
  	if (!buf) {
  		retval = -ENOMEM;
  		goto error;
  	}
ff9065188   Oliver Neukum   [PATCH] USB: Limi...
427
  	if (copy_from_user(buf, user_buffer, writesize)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
429
430
  		retval = -EFAULT;
  		goto error;
  	}
ba35e02bd   Oliver Neukum   USB: fix skeleton...
431
432
433
434
435
436
437
  	/* 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;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
440
  	/* initialize the urb properly */
  	usb_fill_bulk_urb(urb, dev->udev,
  			  usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
ff9065188   Oliver Neukum   [PATCH] USB: Limi...
441
  			  buf, writesize, skel_write_bulk_callback, dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
403dfb58c   Oliver Neukum   USB: usb-skeleton...
443
  	usb_anchor_urb(urb, &dev->submitted);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
445
446
  
  	/* send the data out the bulk port */
  	retval = usb_submit_urb(urb, GFP_KERNEL);
ba35e02bd   Oliver Neukum   USB: fix skeleton...
447
  	mutex_unlock(&dev->io_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
  	if (retval) {
3ae9da1c9   Greg Kroah-Hartman   USB: skeleton: fi...
449
450
  		err("%s - failed submitting write urb, error %d", __func__,
  		    retval);
403dfb58c   Oliver Neukum   USB: usb-skeleton...
451
  		goto error_unanchor;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
  	}
3ae9da1c9   Greg Kroah-Hartman   USB: skeleton: fi...
453
454
455
456
  	/*
  	 * release our reference to this urb, the USB core will eventually free
  	 * it entirely
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
  	usb_free_urb(urb);
ba35e02bd   Oliver Neukum   USB: fix skeleton...
458

ff9065188   Oliver Neukum   [PATCH] USB: Limi...
459
  	return writesize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460

403dfb58c   Oliver Neukum   USB: usb-skeleton...
461
462
  error_unanchor:
  	usb_unanchor_urb(urb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
  error:
121e287cb   Alan Stern   usb-skeleton: don...
464
  	if (urb) {
997ea58eb   Daniel Mack   USB: rename usb_b...
465
  		usb_free_coherent(dev->udev, writesize, buf, urb->transfer_dma);
121e287cb   Alan Stern   usb-skeleton: don...
466
467
  		usb_free_urb(urb);
  	}
ff9065188   Oliver Neukum   [PATCH] USB: Limi...
468
  	up(&dev->limit_sem);
121e287cb   Alan Stern   usb-skeleton: don...
469
470
  
  exit:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
  	return retval;
  }
066202dd4   Luiz Fernando N. Capitulino   USB: Make file op...
473
  static const struct file_operations skel_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
476
477
478
  	.owner =	THIS_MODULE,
  	.read =		skel_read,
  	.write =	skel_write,
  	.open =		skel_open,
  	.release =	skel_release,
403dfb58c   Oliver Neukum   USB: usb-skeleton...
479
  	.flush =	skel_flush,
6038f373a   Arnd Bergmann   llseek: automatic...
480
  	.llseek =	noop_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
  };
c07045412   Luiz Fernando N. Capitulino   usb-skeleton: sma...
482
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
   * usb class driver info in order to get a minor number from the usb core,
595b14cbc   Greg Kroah-Hartman   [PATCH] USB: remo...
484
   * and to have the device registered with the driver core
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
   */
  static struct usb_class_driver skel_class = {
d6e5bcf4a   Greg Kroah-Hartman   [PATCH] devfs: Re...
487
  	.name =		"skel%d",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
  	.fops =		&skel_fops,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
490
  	.minor_base =	USB_SKEL_MINOR_BASE,
  };
3ae9da1c9   Greg Kroah-Hartman   USB: skeleton: fi...
491
492
  static int skel_probe(struct usb_interface *interface,
  		      const struct usb_device_id *id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
  {
c07045412   Luiz Fernando N. Capitulino   usb-skeleton: sma...
494
  	struct usb_skel *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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 */
ff9065188   Oliver Neukum   [PATCH] USB: Limi...
502
  	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
c07045412   Luiz Fernando N. Capitulino   usb-skeleton: sma...
503
  	if (!dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
506
  		err("Out of memory");
  		goto error;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
  	kref_init(&dev->kref);
ff9065188   Oliver Neukum   [PATCH] USB: Limi...
508
  	sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
121e287cb   Alan Stern   usb-skeleton: don...
509
  	mutex_init(&dev->io_mutex);
403dfb58c   Oliver Neukum   USB: usb-skeleton...
510
511
  	spin_lock_init(&dev->err_lock);
  	init_usb_anchor(&dev->submitted);
e7389cc9a   Oliver Neukum   USB: skel_read re...
512
  	init_completion(&dev->bulk_in_completion);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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 &&
c07045412   Luiz Fernando N. Capitulino   usb-skeleton: sma...
524
  		    usb_endpoint_is_bulk_in(endpoint)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
  			/* we found a bulk in endpoint */
29cc88979   Kuninori Morimoto   USB: use usb_endp...
526
  			buffer_size = usb_endpoint_maxp(endpoint);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
528
529
530
531
532
533
  			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;
  			}
e7389cc9a   Oliver Neukum   USB: skel_read re...
534
535
536
537
538
  			dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);
  			if (!dev->bulk_in_urb) {
  				err("Could not allocate bulk_in_urb");
  				goto error;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
541
  		}
  
  		if (!dev->bulk_out_endpointAddr &&
c07045412   Luiz Fernando N. Capitulino   usb-skeleton: sma...
542
  		    usb_endpoint_is_bulk_out(endpoint)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
  			/* 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 */
a5f5ea230   Matt Kraai   USB: skeleton: Us...
565
566
567
  	dev_info(&interface->dev,
  		 "USB Skeleton device now attached to USBSkel-%d",
  		 interface->minor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
570
571
  	return 0;
  
  error:
  	if (dev)
ba35e02bd   Oliver Neukum   USB: fix skeleton...
572
  		/* this frees allocated memory */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
574
575
576
577
578
579
580
  		kref_put(&dev->kref, skel_delete);
  	return retval;
  }
  
  static void skel_disconnect(struct usb_interface *interface)
  {
  	struct usb_skel *dev;
  	int minor = interface->minor;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
  	dev = usb_get_intfdata(interface);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
584
  
  	/* give back our minor */
  	usb_deregister_dev(interface, &skel_class);
121e287cb   Alan Stern   usb-skeleton: don...
585
586
587
588
  	/* prevent more I/O from starting */
  	mutex_lock(&dev->io_mutex);
  	dev->interface = NULL;
  	mutex_unlock(&dev->io_mutex);
e73c7247b   Oliver Neukum   USB: usb-skeleton...
589
  	usb_kill_anchored_urbs(&dev->submitted);
26c71a79c   Ming Lei   USB: usb-skeleton...
590
591
  	mutex_lock(&skel_mutex);
  	usb_set_intfdata(interface, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
  	/* decrement our usage count */
  	kref_put(&dev->kref, skel_delete);
26c71a79c   Ming Lei   USB: usb-skeleton...
594
  	mutex_unlock(&skel_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595

a5f5ea230   Matt Kraai   USB: skeleton: Us...
596
  	dev_info(&interface->dev, "USB Skeleton #%d now disconnected", minor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
  }
403dfb58c   Oliver Neukum   USB: usb-skeleton...
598
599
600
601
602
603
604
  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);
e7389cc9a   Oliver Neukum   USB: skel_read re...
605
  	usb_kill_urb(dev->bulk_in_urb);
403dfb58c   Oliver Neukum   USB: usb-skeleton...
606
  }
758f7e161   Oliver Neukum   USB: usb-skeleton...
607
608
609
610
611
612
613
614
615
  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;
  }
3ae9da1c9   Greg Kroah-Hartman   USB: skeleton: fi...
616
  static int skel_resume(struct usb_interface *intf)
758f7e161   Oliver Neukum   USB: usb-skeleton...
617
618
619
  {
  	return 0;
  }
87d093e25   Oliver Neukum   USB: usb-skeleton...
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
  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;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
  static struct usb_driver skel_driver = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
  	.name =		"skeleton",
  	.probe =	skel_probe,
  	.disconnect =	skel_disconnect,
758f7e161   Oliver Neukum   USB: usb-skeleton...
644
645
  	.suspend =	skel_suspend,
  	.resume =	skel_resume,
87d093e25   Oliver Neukum   USB: usb-skeleton...
646
647
  	.pre_reset =	skel_pre_reset,
  	.post_reset =	skel_post_reset,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
  	.id_table =	skel_table,
ba35e02bd   Oliver Neukum   USB: fix skeleton...
649
  	.supports_autosuspend = 1,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  };
65db43054   Greg Kroah-Hartman   USB: convert driv...
651
  module_usb_driver(skel_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
653
  
  MODULE_LICENSE("GPL");