forked from microsoft/WSL2-Linux-Kernel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinode.c
2148 lines (1845 loc) · 52.4 KB
/
inode.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
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
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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
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
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
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* inode.c -- user mode filesystem api for usb gadget controllers
*
* Copyright (C) 2003-2004 David Brownell
* Copyright (C) 2003 Agilent Technologies
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* #define VERBOSE_DEBUG */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/uts.h>
#include <linux/wait.h>
#include <linux/compiler.h>
#include <asm/uaccess.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <linux/usb/gadgetfs.h>
#include <linux/usb/gadget.h>
/*
* The gadgetfs API maps each endpoint to a file descriptor so that you
* can use standard synchronous read/write calls for I/O. There's some
* O_NONBLOCK and O_ASYNC/FASYNC style i/o support. Example usermode
* drivers show how this works in practice. You can also use AIO to
* eliminate I/O gaps between requests, to help when streaming data.
*
* Key parts that must be USB-specific are protocols defining how the
* read/write operations relate to the hardware state machines. There
* are two types of files. One type is for the device, implementing ep0.
* The other type is for each IN or OUT endpoint. In both cases, the
* user mode driver must configure the hardware before using it.
*
* - First, dev_config() is called when /dev/gadget/$CHIP is configured
* (by writing configuration and device descriptors). Afterwards it
* may serve as a source of device events, used to handle all control
* requests other than basic enumeration.
*
* - Then, after a SET_CONFIGURATION control request, ep_config() is
* called when each /dev/gadget/ep* file is configured (by writing
* endpoint descriptors). Afterwards these files are used to write()
* IN data or to read() OUT data. To halt the endpoint, a "wrong
* direction" request is issued (like reading an IN endpoint).
*
* Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe
* not possible on all hardware. For example, precise fault handling with
* respect to data left in endpoint fifos after aborted operations; or
* selective clearing of endpoint halts, to implement SET_INTERFACE.
*/
#define DRIVER_DESC "USB Gadget filesystem"
#define DRIVER_VERSION "24 Aug 2004"
static const char driver_desc [] = DRIVER_DESC;
static const char shortname [] = "gadgetfs";
MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_AUTHOR ("David Brownell");
MODULE_LICENSE ("GPL");
/*----------------------------------------------------------------------*/
#define GADGETFS_MAGIC 0xaee71ee7
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
/* /dev/gadget/$CHIP represents ep0 and the whole device */
enum ep0_state {
/* DISBLED is the initial state.
*/
STATE_DEV_DISABLED = 0,
/* Only one open() of /dev/gadget/$CHIP; only one file tracks
* ep0/device i/o modes and binding to the controller. Driver
* must always write descriptors to initialize the device, then
* the device becomes UNCONNECTED until enumeration.
*/
STATE_DEV_OPENED,
/* From then on, ep0 fd is in either of two basic modes:
* - (UN)CONNECTED: read usb_gadgetfs_event(s) from it
* - SETUP: read/write will transfer control data and succeed;
* or if "wrong direction", performs protocol stall
*/
STATE_DEV_UNCONNECTED,
STATE_DEV_CONNECTED,
STATE_DEV_SETUP,
/* UNBOUND means the driver closed ep0, so the device won't be
* accessible again (DEV_DISABLED) until all fds are closed.
*/
STATE_DEV_UNBOUND,
};
/* enough for the whole queue: most events invalidate others */
#define N_EVENT 5
struct dev_data {
spinlock_t lock;
atomic_t count;
enum ep0_state state; /* P: lock */
struct usb_gadgetfs_event event [N_EVENT];
unsigned ev_next;
struct fasync_struct *fasync;
u8 current_config;
/* drivers reading ep0 MUST handle control requests (SETUP)
* reported that way; else the host will time out.
*/
unsigned usermode_setup : 1,
setup_in : 1,
setup_can_stall : 1,
setup_out_ready : 1,
setup_out_error : 1,
setup_abort : 1;
unsigned setup_wLength;
/* the rest is basically write-once */
struct usb_config_descriptor *config, *hs_config;
struct usb_device_descriptor *dev;
struct usb_request *req;
struct usb_gadget *gadget;
struct list_head epfiles;
void *buf;
wait_queue_head_t wait;
struct super_block *sb;
struct dentry *dentry;
/* except this scratch i/o buffer for ep0 */
u8 rbuf [256];
};
static inline void get_dev (struct dev_data *data)
{
atomic_inc (&data->count);
}
static void put_dev (struct dev_data *data)
{
if (likely (!atomic_dec_and_test (&data->count)))
return;
/* needs no more cleanup */
BUG_ON (waitqueue_active (&data->wait));
kfree (data);
}
static struct dev_data *dev_new (void)
{
struct dev_data *dev;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
dev->state = STATE_DEV_DISABLED;
atomic_set (&dev->count, 1);
spin_lock_init (&dev->lock);
INIT_LIST_HEAD (&dev->epfiles);
init_waitqueue_head (&dev->wait);
return dev;
}
/*----------------------------------------------------------------------*/
/* other /dev/gadget/$ENDPOINT files represent endpoints */
enum ep_state {
STATE_EP_DISABLED = 0,
STATE_EP_READY,
STATE_EP_ENABLED,
STATE_EP_UNBOUND,
};
struct ep_data {
struct mutex lock;
enum ep_state state;
atomic_t count;
struct dev_data *dev;
/* must hold dev->lock before accessing ep or req */
struct usb_ep *ep;
struct usb_request *req;
ssize_t status;
char name [16];
struct usb_endpoint_descriptor desc, hs_desc;
struct list_head epfiles;
wait_queue_head_t wait;
struct dentry *dentry;
struct inode *inode;
};
static inline void get_ep (struct ep_data *data)
{
atomic_inc (&data->count);
}
static void put_ep (struct ep_data *data)
{
if (likely (!atomic_dec_and_test (&data->count)))
return;
put_dev (data->dev);
/* needs no more cleanup */
BUG_ON (!list_empty (&data->epfiles));
BUG_ON (waitqueue_active (&data->wait));
kfree (data);
}
/*----------------------------------------------------------------------*/
/* most "how to use the hardware" policy choices are in userspace:
* mapping endpoint roles (which the driver needs) to the capabilities
* which the usb controller has. most of those capabilities are exposed
* implicitly, starting with the driver name and then endpoint names.
*/
static const char *CHIP;
/*----------------------------------------------------------------------*/
/* NOTE: don't use dev_printk calls before binding to the gadget
* at the end of ep0 configuration, or after unbind.
*/
/* too wordy: dev_printk(level , &(d)->gadget->dev , fmt , ## args) */
#define xprintk(d,level,fmt,args...) \
printk(level "%s: " fmt , shortname , ## args)
#ifdef DEBUG
#define DBG(dev,fmt,args...) \
xprintk(dev , KERN_DEBUG , fmt , ## args)
#else
#define DBG(dev,fmt,args...) \
do { } while (0)
#endif /* DEBUG */
#ifdef VERBOSE_DEBUG
#define VDEBUG DBG
#else
#define VDEBUG(dev,fmt,args...) \
do { } while (0)
#endif /* DEBUG */
#define ERROR(dev,fmt,args...) \
xprintk(dev , KERN_ERR , fmt , ## args)
#define INFO(dev,fmt,args...) \
xprintk(dev , KERN_INFO , fmt , ## args)
/*----------------------------------------------------------------------*/
/* SYNCHRONOUS ENDPOINT OPERATIONS (bulk/intr/iso)
*
* After opening, configure non-control endpoints. Then use normal
* stream read() and write() requests; and maybe ioctl() to get more
* precise FIFO status when recovering from cancellation.
*/
static void epio_complete (struct usb_ep *ep, struct usb_request *req)
{
struct ep_data *epdata = ep->driver_data;
if (!req->context)
return;
if (req->status)
epdata->status = req->status;
else
epdata->status = req->actual;
complete ((struct completion *)req->context);
}
/* tasklock endpoint, returning when it's connected.
* still need dev->lock to use epdata->ep.
*/
static int
get_ready_ep (unsigned f_flags, struct ep_data *epdata)
{
int val;
if (f_flags & O_NONBLOCK) {
if (!mutex_trylock(&epdata->lock))
goto nonblock;
if (epdata->state != STATE_EP_ENABLED) {
mutex_unlock(&epdata->lock);
nonblock:
val = -EAGAIN;
} else
val = 0;
return val;
}
val = mutex_lock_interruptible(&epdata->lock);
if (val < 0)
return val;
switch (epdata->state) {
case STATE_EP_ENABLED:
break;
// case STATE_EP_DISABLED: /* "can't happen" */
// case STATE_EP_READY: /* "can't happen" */
default: /* error! */
pr_debug ("%s: ep %p not available, state %d\n",
shortname, epdata, epdata->state);
// FALLTHROUGH
case STATE_EP_UNBOUND: /* clean disconnect */
val = -ENODEV;
mutex_unlock(&epdata->lock);
}
return val;
}
static ssize_t
ep_io (struct ep_data *epdata, void *buf, unsigned len)
{
DECLARE_COMPLETION_ONSTACK (done);
int value;
spin_lock_irq (&epdata->dev->lock);
if (likely (epdata->ep != NULL)) {
struct usb_request *req = epdata->req;
req->context = &done;
req->complete = epio_complete;
req->buf = buf;
req->length = len;
value = usb_ep_queue (epdata->ep, req, GFP_ATOMIC);
} else
value = -ENODEV;
spin_unlock_irq (&epdata->dev->lock);
if (likely (value == 0)) {
value = wait_event_interruptible (done.wait, done.done);
if (value != 0) {
spin_lock_irq (&epdata->dev->lock);
if (likely (epdata->ep != NULL)) {
DBG (epdata->dev, "%s i/o interrupted\n",
epdata->name);
usb_ep_dequeue (epdata->ep, epdata->req);
spin_unlock_irq (&epdata->dev->lock);
wait_event (done.wait, done.done);
if (epdata->status == -ECONNRESET)
epdata->status = -EINTR;
} else {
spin_unlock_irq (&epdata->dev->lock);
DBG (epdata->dev, "endpoint gone\n");
epdata->status = -ENODEV;
}
}
return epdata->status;
}
return value;
}
/* handle a synchronous OUT bulk/intr/iso transfer */
static ssize_t
ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
{
struct ep_data *data = fd->private_data;
void *kbuf;
ssize_t value;
if ((value = get_ready_ep (fd->f_flags, data)) < 0)
return value;
/* halt any endpoint by doing a "wrong direction" i/o call */
if (usb_endpoint_dir_in(&data->desc)) {
if (usb_endpoint_xfer_isoc(&data->desc)) {
mutex_unlock(&data->lock);
return -EINVAL;
}
DBG (data->dev, "%s halt\n", data->name);
spin_lock_irq (&data->dev->lock);
if (likely (data->ep != NULL))
usb_ep_set_halt (data->ep);
spin_unlock_irq (&data->dev->lock);
mutex_unlock(&data->lock);
return -EBADMSG;
}
/* FIXME readahead for O_NONBLOCK and poll(); careful with ZLPs */
value = -ENOMEM;
kbuf = kmalloc (len, GFP_KERNEL);
if (unlikely (!kbuf))
goto free1;
value = ep_io (data, kbuf, len);
VDEBUG (data->dev, "%s read %zu OUT, status %d\n",
data->name, len, (int) value);
if (value >= 0 && copy_to_user (buf, kbuf, value))
value = -EFAULT;
free1:
mutex_unlock(&data->lock);
kfree (kbuf);
return value;
}
/* handle a synchronous IN bulk/intr/iso transfer */
static ssize_t
ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
{
struct ep_data *data = fd->private_data;
void *kbuf;
ssize_t value;
if ((value = get_ready_ep (fd->f_flags, data)) < 0)
return value;
/* halt any endpoint by doing a "wrong direction" i/o call */
if (!usb_endpoint_dir_in(&data->desc)) {
if (usb_endpoint_xfer_isoc(&data->desc))
return -EINVAL;
DBG (data->dev, "%s halt\n", data->name);
spin_lock_irq (&data->dev->lock);
if (likely (data->ep != NULL))
usb_ep_set_halt (data->ep);
spin_unlock_irq (&data->dev->lock);
mutex_unlock(&data->lock);
return -EBADMSG;
}
/* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */
value = -ENOMEM;
kbuf = kmalloc (len, GFP_KERNEL);
if (!kbuf)
goto free1;
if (copy_from_user (kbuf, buf, len)) {
value = -EFAULT;
goto free1;
}
value = ep_io (data, kbuf, len);
VDEBUG (data->dev, "%s write %zu IN, status %d\n",
data->name, len, (int) value);
free1:
mutex_unlock(&data->lock);
kfree (kbuf);
return value;
}
static int
ep_release (struct inode *inode, struct file *fd)
{
struct ep_data *data = fd->private_data;
int value;
value = mutex_lock_interruptible(&data->lock);
if (value < 0)
return value;
/* clean up if this can be reopened */
if (data->state != STATE_EP_UNBOUND) {
data->state = STATE_EP_DISABLED;
data->desc.bDescriptorType = 0;
data->hs_desc.bDescriptorType = 0;
usb_ep_disable(data->ep);
}
mutex_unlock(&data->lock);
put_ep (data);
return 0;
}
static long ep_ioctl(struct file *fd, unsigned code, unsigned long value)
{
struct ep_data *data = fd->private_data;
int status;
if ((status = get_ready_ep (fd->f_flags, data)) < 0)
return status;
spin_lock_irq (&data->dev->lock);
if (likely (data->ep != NULL)) {
switch (code) {
case GADGETFS_FIFO_STATUS:
status = usb_ep_fifo_status (data->ep);
break;
case GADGETFS_FIFO_FLUSH:
usb_ep_fifo_flush (data->ep);
break;
case GADGETFS_CLEAR_HALT:
status = usb_ep_clear_halt (data->ep);
break;
default:
status = -ENOTTY;
}
} else
status = -ENODEV;
spin_unlock_irq (&data->dev->lock);
mutex_unlock(&data->lock);
return status;
}
/*----------------------------------------------------------------------*/
/* ASYNCHRONOUS ENDPOINT I/O OPERATIONS (bulk/intr/iso) */
struct kiocb_priv {
struct usb_request *req;
struct ep_data *epdata;
void *buf;
const struct iovec *iv;
unsigned long nr_segs;
unsigned actual;
};
static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e)
{
struct kiocb_priv *priv = iocb->private;
struct ep_data *epdata;
int value;
local_irq_disable();
epdata = priv->epdata;
// spin_lock(&epdata->dev->lock);
kiocbSetCancelled(iocb);
if (likely(epdata && epdata->ep && priv->req))
value = usb_ep_dequeue (epdata->ep, priv->req);
else
value = -EINVAL;
// spin_unlock(&epdata->dev->lock);
local_irq_enable();
aio_put_req(iocb);
return value;
}
static ssize_t ep_aio_read_retry(struct kiocb *iocb)
{
struct kiocb_priv *priv = iocb->private;
ssize_t len, total;
void *to_copy;
int i;
/* we "retry" to get the right mm context for this: */
/* copy stuff into user buffers */
total = priv->actual;
len = 0;
to_copy = priv->buf;
for (i=0; i < priv->nr_segs; i++) {
ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
if (copy_to_user(priv->iv[i].iov_base, to_copy, this)) {
if (len == 0)
len = -EFAULT;
break;
}
total -= this;
len += this;
to_copy += this;
if (total == 0)
break;
}
kfree(priv->buf);
kfree(priv);
return len;
}
static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
{
struct kiocb *iocb = req->context;
struct kiocb_priv *priv = iocb->private;
struct ep_data *epdata = priv->epdata;
/* lock against disconnect (and ideally, cancel) */
spin_lock(&epdata->dev->lock);
priv->req = NULL;
priv->epdata = NULL;
/* if this was a write or a read returning no data then we
* don't need to copy anything to userspace, so we can
* complete the aio request immediately.
*/
if (priv->iv == NULL || unlikely(req->actual == 0)) {
kfree(req->buf);
kfree(priv);
iocb->private = NULL;
/* aio_complete() reports bytes-transferred _and_ faults */
aio_complete(iocb, req->actual ? req->actual : req->status,
req->status);
} else {
/* retry() won't report both; so we hide some faults */
if (unlikely(0 != req->status))
DBG(epdata->dev, "%s fault %d len %d\n",
ep->name, req->status, req->actual);
priv->buf = req->buf;
priv->actual = req->actual;
kick_iocb(iocb);
}
spin_unlock(&epdata->dev->lock);
usb_ep_free_request(ep, req);
put_ep(epdata);
}
static ssize_t
ep_aio_rwtail(
struct kiocb *iocb,
char *buf,
size_t len,
struct ep_data *epdata,
const struct iovec *iv,
unsigned long nr_segs
)
{
struct kiocb_priv *priv;
struct usb_request *req;
ssize_t value;
priv = kmalloc(sizeof *priv, GFP_KERNEL);
if (!priv) {
value = -ENOMEM;
fail:
kfree(buf);
return value;
}
iocb->private = priv;
priv->iv = iv;
priv->nr_segs = nr_segs;
value = get_ready_ep(iocb->ki_filp->f_flags, epdata);
if (unlikely(value < 0)) {
kfree(priv);
goto fail;
}
iocb->ki_cancel = ep_aio_cancel;
get_ep(epdata);
priv->epdata = epdata;
priv->actual = 0;
/* each kiocb is coupled to one usb_request, but we can't
* allocate or submit those if the host disconnected.
*/
spin_lock_irq(&epdata->dev->lock);
if (likely(epdata->ep)) {
req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC);
if (likely(req)) {
priv->req = req;
req->buf = buf;
req->length = len;
req->complete = ep_aio_complete;
req->context = iocb;
value = usb_ep_queue(epdata->ep, req, GFP_ATOMIC);
if (unlikely(0 != value))
usb_ep_free_request(epdata->ep, req);
} else
value = -EAGAIN;
} else
value = -ENODEV;
spin_unlock_irq(&epdata->dev->lock);
mutex_unlock(&epdata->lock);
if (unlikely(value)) {
kfree(priv);
put_ep(epdata);
} else
value = (iv ? -EIOCBRETRY : -EIOCBQUEUED);
return value;
}
static ssize_t
ep_aio_read(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t o)
{
struct ep_data *epdata = iocb->ki_filp->private_data;
char *buf;
if (unlikely(usb_endpoint_dir_in(&epdata->desc)))
return -EINVAL;
buf = kmalloc(iocb->ki_left, GFP_KERNEL);
if (unlikely(!buf))
return -ENOMEM;
iocb->ki_retry = ep_aio_read_retry;
return ep_aio_rwtail(iocb, buf, iocb->ki_left, epdata, iov, nr_segs);
}
static ssize_t
ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t o)
{
struct ep_data *epdata = iocb->ki_filp->private_data;
char *buf;
size_t len = 0;
int i = 0;
if (unlikely(!usb_endpoint_dir_in(&epdata->desc)))
return -EINVAL;
buf = kmalloc(iocb->ki_left, GFP_KERNEL);
if (unlikely(!buf))
return -ENOMEM;
for (i=0; i < nr_segs; i++) {
if (unlikely(copy_from_user(&buf[len], iov[i].iov_base,
iov[i].iov_len) != 0)) {
kfree(buf);
return -EFAULT;
}
len += iov[i].iov_len;
}
return ep_aio_rwtail(iocb, buf, len, epdata, NULL, 0);
}
/*----------------------------------------------------------------------*/
/* used after endpoint configuration */
static const struct file_operations ep_io_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = ep_read,
.write = ep_write,
.unlocked_ioctl = ep_ioctl,
.release = ep_release,
.aio_read = ep_aio_read,
.aio_write = ep_aio_write,
};
/* ENDPOINT INITIALIZATION
*
* fd = open ("/dev/gadget/$ENDPOINT", O_RDWR)
* status = write (fd, descriptors, sizeof descriptors)
*
* That write establishes the endpoint configuration, configuring
* the controller to process bulk, interrupt, or isochronous transfers
* at the right maxpacket size, and so on.
*
* The descriptors are message type 1, identified by a host order u32
* at the beginning of what's written. Descriptor order is: full/low
* speed descriptor, then optional high speed descriptor.
*/
static ssize_t
ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
{
struct ep_data *data = fd->private_data;
struct usb_ep *ep;
u32 tag;
int value, length = len;
value = mutex_lock_interruptible(&data->lock);
if (value < 0)
return value;
if (data->state != STATE_EP_READY) {
value = -EL2HLT;
goto fail;
}
value = len;
if (len < USB_DT_ENDPOINT_SIZE + 4)
goto fail0;
/* we might need to change message format someday */
if (copy_from_user (&tag, buf, 4)) {
goto fail1;
}
if (tag != 1) {
DBG(data->dev, "config %s, bad tag %d\n", data->name, tag);
goto fail0;
}
buf += 4;
len -= 4;
/* NOTE: audio endpoint extensions not accepted here;
* just don't include the extra bytes.
*/
/* full/low speed descriptor, then high speed */
if (copy_from_user (&data->desc, buf, USB_DT_ENDPOINT_SIZE)) {
goto fail1;
}
if (data->desc.bLength != USB_DT_ENDPOINT_SIZE
|| data->desc.bDescriptorType != USB_DT_ENDPOINT)
goto fail0;
if (len != USB_DT_ENDPOINT_SIZE) {
if (len != 2 * USB_DT_ENDPOINT_SIZE)
goto fail0;
if (copy_from_user (&data->hs_desc, buf + USB_DT_ENDPOINT_SIZE,
USB_DT_ENDPOINT_SIZE)) {
goto fail1;
}
if (data->hs_desc.bLength != USB_DT_ENDPOINT_SIZE
|| data->hs_desc.bDescriptorType
!= USB_DT_ENDPOINT) {
DBG(data->dev, "config %s, bad hs length or type\n",
data->name);
goto fail0;
}
}
spin_lock_irq (&data->dev->lock);
if (data->dev->state == STATE_DEV_UNBOUND) {
value = -ENOENT;
goto gone;
} else if ((ep = data->ep) == NULL) {
value = -ENODEV;
goto gone;
}
switch (data->dev->gadget->speed) {
case USB_SPEED_LOW:
case USB_SPEED_FULL:
value = usb_ep_enable (ep, &data->desc);
if (value == 0)
data->state = STATE_EP_ENABLED;
break;
#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_SPEED_HIGH:
/* fails if caller didn't provide that descriptor... */
value = usb_ep_enable (ep, &data->hs_desc);
if (value == 0)
data->state = STATE_EP_ENABLED;
break;
#endif
default:
DBG(data->dev, "unconnected, %s init abandoned\n",
data->name);
value = -EINVAL;
}
if (value == 0) {
fd->f_op = &ep_io_operations;
value = length;
}
gone:
spin_unlock_irq (&data->dev->lock);
if (value < 0) {
fail:
data->desc.bDescriptorType = 0;
data->hs_desc.bDescriptorType = 0;
}
mutex_unlock(&data->lock);
return value;
fail0:
value = -EINVAL;
goto fail;
fail1:
value = -EFAULT;
goto fail;
}
static int
ep_open (struct inode *inode, struct file *fd)
{
struct ep_data *data = inode->i_private;
int value = -EBUSY;
if (mutex_lock_interruptible(&data->lock) != 0)
return -EINTR;
spin_lock_irq (&data->dev->lock);
if (data->dev->state == STATE_DEV_UNBOUND)
value = -ENOENT;
else if (data->state == STATE_EP_DISABLED) {
value = 0;
data->state = STATE_EP_READY;
get_ep (data);
fd->private_data = data;
VDEBUG (data->dev, "%s ready\n", data->name);
} else
DBG (data->dev, "%s state %d\n",
data->name, data->state);
spin_unlock_irq (&data->dev->lock);
mutex_unlock(&data->lock);
return value;
}
/* used before endpoint configuration */
static const struct file_operations ep_config_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.open = ep_open,
.write = ep_config,
.release = ep_release,
};
/*----------------------------------------------------------------------*/
/* EP0 IMPLEMENTATION can be partly in userspace.
*
* Drivers that use this facility receive various events, including
* control requests the kernel doesn't handle. Drivers that don't
* use this facility may be too simple-minded for real applications.
*/
static inline void ep0_readable (struct dev_data *dev)
{
wake_up (&dev->wait);
kill_fasync (&dev->fasync, SIGIO, POLL_IN);
}
static void clean_req (struct usb_ep *ep, struct usb_request *req)
{
struct dev_data *dev = ep->driver_data;
if (req->buf != dev->rbuf) {
kfree(req->buf);
req->buf = dev->rbuf;
req->dma = DMA_ADDR_INVALID;
}
req->complete = epio_complete;
dev->setup_out_ready = 0;
}
static void ep0_complete (struct usb_ep *ep, struct usb_request *req)
{
struct dev_data *dev = ep->driver_data;
unsigned long flags;
int free = 1;
/* for control OUT, data must still get to userspace */
spin_lock_irqsave(&dev->lock, flags);
if (!dev->setup_in) {
dev->setup_out_error = (req->status != 0);
if (!dev->setup_out_error)
free = 0;
dev->setup_out_ready = 1;
ep0_readable (dev);
}
/* clean up as appropriate */
if (free && req->buf != &dev->rbuf)
clean_req (ep, req);
req->complete = epio_complete;
spin_unlock_irqrestore(&dev->lock, flags);
}
static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
{
struct dev_data *dev = ep->driver_data;
if (dev->setup_out_ready) {
DBG (dev, "ep0 request busy!\n");
return -EBUSY;
}
if (len > sizeof (dev->rbuf))
req->buf = kmalloc(len, GFP_ATOMIC);
if (req->buf == NULL) {
req->buf = dev->rbuf;
return -ENOMEM;
}
req->complete = ep0_complete;
req->length = len;
req->zero = 0;
return 0;
}
static ssize_t
ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
{
struct dev_data *dev = fd->private_data;
ssize_t retval;
enum ep0_state state;
spin_lock_irq (&dev->lock);
/* report fd mode change before acting on it */
if (dev->setup_abort) {
dev->setup_abort = 0;
retval = -EIDRM;
goto done;
}
/* control DATA stage */
if ((state = dev->state) == STATE_DEV_SETUP) {
if (dev->setup_in) { /* stall IN */
VDEBUG(dev, "ep0in stall\n");
(void) usb_ep_set_halt (dev->gadget->ep0);
retval = -EL2HLT;
dev->state = STATE_DEV_CONNECTED;