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#undef DEBUG
27#include <linux/usb.h>
28#include "auerchar.h"
29#include "auermain.h"
30#include <linux/slab.h>
31#include <asm/uaccess.h>
32
33
34
35
36static void auerchar_disconnect(struct auerscon *scp)
37{
38 struct auerchar *ccp =((struct auerchar *) ((char *) (scp) - (unsigned long) (&((struct auerchar *) 0)->scontext)));
39 dbg("auerchar_disconnect called");
40 ccp->removed = 1;
41 wake_up(&ccp->readwait);
42}
43
44
45
46static void auerchar_ctrlread_dispatch(struct auerscon *scp,
47 struct auerbuf *bp)
48{
49 unsigned long flags;
50 struct auerchar *ccp;
51 struct auerbuf *newbp = NULL;
52 char *charp;
53 dbg("auerchar_ctrlread_dispatch called");
54 ccp =((struct auerchar *) ((char *) (scp) - (unsigned long)(&((struct auerchar *) 0)->scontext)));
55
56
57 newbp = auerbuf_getbuf(&ccp->bufctl);
58 if (!newbp) {
59 dbg("No read buffer available, discard paket!");
60 return;
61 }
62
63
64
65 charp = newbp->bufp;
66 newbp->bufp = bp->bufp;
67 bp->bufp = charp;
68 newbp->len = bp->len;
69
70
71 spin_lock_irqsave(&ccp->bufctl.lock, flags);
72 list_add_tail(&newbp->buff_list, &ccp->bufctl.rec_buff_list);
73 spin_unlock_irqrestore(&ccp->bufctl.lock, flags);
74 dbg("read buffer appended to rec_list");
75
76
77 wake_up(&ccp->readwait);
78}
79
80
81
82void auerchar_delete(struct auerchar *ccp)
83{
84 dbg("auerchar_delete");
85 if (ccp == NULL)
86 return;
87
88
89 ccp->removed = 1;
90 wake_up(&ccp->readwait);
91
92
93 if (ccp->readbuf) {
94 auerbuf_releasebuf(ccp->readbuf);
95 ccp->readbuf = NULL;
96 }
97
98
99 auerbuf_free_buffers(&ccp->bufctl);
100
101
102 kfree(ccp);
103}
104
105
106
107
108
109
110int auerchar_open(struct inode *inode, struct file *file)
111{
112 int dtindex = MINOR(inode->i_rdev) - AUER_MINOR_BASE;
113 struct auerswald *cp = NULL;
114 struct auerchar *ccp = NULL;
115 int ret;
116
117
118 if ((dtindex < 0) || (dtindex >= AUER_MAX_DEVICES)) {
119 return -ENODEV;
120 }
121
122 if (down_interruptible(&auerdev_table_mutex)) {
123 return -ERESTARTSYS;
124 }
125 cp = auerdev_table[dtindex];
126 if (cp == NULL) {
127 up(&auerdev_table_mutex);
128 return -ENODEV;
129 }
130 if (down_interruptible(&cp->mutex)) {
131 up(&auerdev_table_mutex);
132 return -ERESTARTSYS;
133 }
134 up(&auerdev_table_mutex);
135
136
137 ccp = (struct auerchar *) kmalloc(sizeof(struct auerchar), GFP_KERNEL);
138 if (ccp == NULL) {
139 err("out of memory");
140 ret = -ENOMEM;
141 goto ofail;
142 }
143
144
145 memset(ccp, 0, sizeof(struct auerchar));
146 init_MUTEX(&ccp->mutex);
147 init_MUTEX(&ccp->readmutex);
148 auerbuf_init(&ccp->bufctl);
149 ccp->scontext.id = AUH_UNASSIGNED;
150 ccp->scontext.dispatch = auerchar_ctrlread_dispatch;
151 ccp->scontext.disconnect = auerchar_disconnect;
152 init_waitqueue_head(&ccp->readwait);
153
154 ret =
155 auerbuf_setup(&ccp->bufctl, AU_RBUFFERS,
156 cp->maxControlLength + AUH_SIZE);
157 if (ret) {
158 goto ofail;
159 }
160
161 cp->open_count++;
162 ccp->auerdev = cp;
163 dbg("open %s as /dev/usb/%s", cp->dev_desc, cp->name);
164 up(&cp->mutex);
165
166
167 file->f_pos = 0;
168 file->private_data = ccp;
169 return 0;
170
171
172 ofail:up(&cp->mutex);
173 auerchar_delete(ccp);
174 return ret;
175}
176
177
178
179int auerchar_ioctl(struct inode *inode, struct file *file,
180 unsigned int cmd, unsigned long arg)
181{
182 struct auerchar *ccp = (struct auerchar *) file->private_data;
183 int ret = 0;
184 struct audevinfo devinfo;
185 struct auerswald *cp = NULL;
186 unsigned int u;
187 dbg("ioctl");
188
189
190 if (down_interruptible(&ccp->mutex)) {
191 return -ERESTARTSYS;
192 }
193 cp = ccp->auerdev;
194 if (!cp) {
195 up(&ccp->mutex);
196 return -ENODEV;
197 }
198 if (down_interruptible(&cp->mutex)) {
199 up(&ccp->mutex);
200 return -ERESTARTSYS;
201 }
202
203
204 if (!cp->usbdev) {
205 up(&cp->mutex);
206 up(&ccp->mutex);
207 return -ENODEV;
208 }
209
210 switch (cmd) {
211
212
213 case IOCTL_AU_TXREADY:
214 dbg("IOCTL_AU_TXREADY");
215 u = ccp->auerdev && (ccp->scontext.id != AUH_UNASSIGNED)
216 && !list_empty(&cp->bufctl.free_buff_list);
217 ret = put_user(u, (unsigned int *) arg);
218 break;
219
220
221 case IOCTL_AU_CONNECT:
222 dbg("IOCTL_AU_CONNECT");
223 u = (ccp->scontext.id != AUH_UNASSIGNED);
224 ret = put_user(u, (unsigned int *) arg);
225 break;
226
227
228 case IOCTL_AU_RXAVAIL:
229 dbg("IOCTL_AU_RXAVAIL");
230 if (ccp->scontext.id == AUH_UNASSIGNED) {
231 ret = -EIO;
232 break;
233 }
234 u = 0;
235 if (ccp->readbuf) {
236 int restlen = ccp->readbuf->len - ccp->readoffset;
237 if (restlen > 0)
238 u = 1;
239 }
240 if (!u) {
241 if (!list_empty(&ccp->bufctl.rec_buff_list)) {
242 u = 1;
243 }
244 }
245 ret = put_user(u, (unsigned int *) arg);
246 break;
247
248
249 case IOCTL_AU_BUFLEN:
250 dbg("IOCTL_AU_BUFLEN");
251 u = cp->maxControlLength;
252 ret = put_user(u, (unsigned int *) arg);
253 break;
254
255
256 case IOCTL_AU_SERVREQ:
257 dbg("IOCTL_AU_SERVREQ");
258
259 auerswald_removeservice(cp, &ccp->scontext);
260
261 ret = get_user(u, (unsigned int *) arg);
262 if (ret) {
263 break;
264 }
265 if ((u < AUH_FIRSTUSERCH) || (u >= AUH_TYPESIZE)) {
266 ret = -EIO;
267 break;
268 }
269 dbg("auerchar service request parameters are ok");
270 ccp->scontext.id = u;
271
272
273 ret = auerswald_addservice(cp, &ccp->scontext);
274 if (ret) {
275
276 ccp->scontext.id = AUH_UNASSIGNED;
277 }
278 break;
279
280
281 case IOCTL_AU_DEVINFO:
282 dbg("IOCTL_AU_DEVINFO");
283 if (copy_from_user
284 (&devinfo, (void *) arg, sizeof(struct audevinfo))) {
285 ret = -EFAULT;
286 break;
287 }
288 u = strlen(cp->dev_desc) + 1;
289 if (u > devinfo.bsize) {
290 u = devinfo.bsize;
291 }
292 ret = copy_to_user(devinfo.buf, cp->dev_desc, u);
293 break;
294
295
296 case IOCTL_AU_SLEN:
297 dbg("IOCTL_AU_SLEN");
298 u = AUSI_DLEN;
299 ret = put_user(u, (unsigned int *) arg);
300 break;
301
302 default:
303 dbg("IOCTL_AU_UNKNOWN");
304 ret = -ENOIOCTLCMD;
305 break;
306 }
307
308 up(&cp->mutex);
309 up(&ccp->mutex);
310 return ret;
311}
312
313
314
315loff_t auerchar_llseek(struct file * file, loff_t offset, int origin)
316{
317 dbg("auerchar_seek");
318 return -ESPIPE;
319}
320
321
322
323ssize_t auerchar_read(struct file * file, char *buf, size_t count,
324 loff_t * ppos)
325{
326 unsigned long flags;
327 struct auerchar *ccp = (struct auerchar *) file->private_data;
328 struct auerbuf *bp = NULL;
329 wait_queue_t wait;
330
331 dbg("auerchar_read");
332
333
334 if (!ccp)
335 return -EIO;
336 if (*ppos)
337 return -ESPIPE;
338 if (count == 0)
339 return 0;
340
341
342 if (down_interruptible(&ccp->mutex))
343 return -ERESTARTSYS;
344
345
346 if (ccp->scontext.id == AUH_UNASSIGNED) {
347 up(&ccp->mutex);
348 return -EIO;
349 }
350
351
352 if (down_interruptible(&ccp->readmutex)) {
353 up(&ccp->mutex);
354 return -ERESTARTSYS;
355 }
356
357
358 doreadbuf:
359 bp = ccp->readbuf;
360 if (bp) {
361
362 int restlen = bp->len - ccp->readoffset;
363 if (restlen < 0)
364 restlen = 0;
365 if (count > restlen)
366 count = restlen;
367 if (count) {
368 if (copy_to_user
369 (buf, bp->bufp + ccp->readoffset, count)) {
370 dbg("auerswald_read: copy_to_user failed");
371 up(&ccp->readmutex);
372 up(&ccp->mutex);
373 return -EFAULT;
374 }
375 }
376
377 ccp->readoffset += count;
378 restlen -= count;
379
380 if (restlen <= 0) {
381 auerbuf_releasebuf(bp);
382 ccp->readbuf = NULL;
383 }
384
385 if (count) {
386 up(&ccp->readmutex);
387 up(&ccp->mutex);
388 return count;
389 }
390 }
391
392
393 doreadlist:
394
395 init_waitqueue_entry(&wait, current);
396 set_current_state(TASK_INTERRUPTIBLE);
397 add_wait_queue(&ccp->readwait, &wait);
398
399 bp = NULL;
400 spin_lock_irqsave(&ccp->bufctl.lock, flags);
401 if (!list_empty(&ccp->bufctl.rec_buff_list)) {
402
403 struct list_head *tmp = ccp->bufctl.rec_buff_list.next;
404 list_del(tmp);
405 bp = list_entry(tmp, struct auerbuf, buff_list);
406 }
407 spin_unlock_irqrestore(&ccp->bufctl.lock, flags);
408
409
410 if (bp) {
411 ccp->readbuf = bp;
412 ccp->readoffset = AUH_SIZE;
413 set_current_state(TASK_RUNNING);
414 remove_wait_queue(&ccp->readwait, &wait);
415 goto doreadbuf;
416 }
417
418
419 if (file->f_flags & O_NONBLOCK) {
420 dbg("No read buffer available, returning -EAGAIN");
421 set_current_state(TASK_RUNNING);
422 remove_wait_queue(&ccp->readwait, &wait);
423 up(&ccp->readmutex);
424 up(&ccp->mutex);
425 return -EAGAIN;
426 }
427
428
429 up(&ccp->mutex);
430 schedule();
431 remove_wait_queue(&ccp->readwait, &wait);
432 if (signal_pending(current)) {
433
434 up(&ccp->readmutex);
435 return -ERESTARTSYS;
436 }
437
438
439 if ((ccp->scontext.id == AUH_UNASSIGNED) || ccp->removed) {
440 up(&ccp->readmutex);
441 return -EIO;
442 }
443
444 if (down_interruptible(&ccp->mutex)) {
445 up(&ccp->readmutex);
446 return -ERESTARTSYS;
447 }
448
449
450 goto doreadlist;
451}
452
453
454
455ssize_t auerchar_write(struct file *file, const char *buf, size_t len,
456 loff_t * ppos)
457{
458 struct auerchar *ccp = (struct auerchar *) file->private_data;
459 struct auerswald *cp = NULL;
460 struct auerbuf *bp;
461 int ret;
462 wait_queue_t wait;
463
464 dbg("auerchar_write %d bytes", len);
465
466
467 if (!ccp)
468 return -EIO;
469 if (*ppos)
470 return -ESPIPE;
471 if (len == 0)
472 return 0;
473
474 write_again:
475
476 if (down_interruptible(&ccp->mutex))
477 return -ERESTARTSYS;
478
479
480 if (ccp->scontext.id == AUH_UNASSIGNED) {
481 up(&ccp->mutex);
482 return -EIO;
483 }
484
485 cp = ccp->auerdev;
486 if (!cp) {
487 up(&ccp->mutex);
488 return -ERESTARTSYS;
489 }
490 if (down_interruptible(&cp->mutex)) {
491 up(&ccp->mutex);
492 return -ERESTARTSYS;
493 }
494 if (!cp->usbdev) {
495 up(&cp->mutex);
496 up(&ccp->mutex);
497 return -EIO;
498 }
499
500 init_waitqueue_entry(&wait, current);
501 set_current_state(TASK_INTERRUPTIBLE);
502 add_wait_queue(&cp->bufferwait, &wait);
503
504
505
506
507 bp = auerbuf_getbuf(&cp->bufctl);
508
509 if (!bp) {
510 up(&cp->mutex);
511 up(&ccp->mutex);
512
513
514 if (file->f_flags & O_NONBLOCK) {
515 set_current_state(TASK_RUNNING);
516 remove_wait_queue(&cp->bufferwait, &wait);
517 return -EAGAIN;
518 }
519
520
521 schedule();
522 remove_wait_queue(&cp->bufferwait, &wait);
523 if (signal_pending(current)) {
524
525 return -ERESTARTSYS;
526 }
527 goto write_again;
528 } else {
529 set_current_state(TASK_RUNNING);
530 remove_wait_queue(&cp->bufferwait, &wait);
531 }
532
533
534 if (len > cp->maxControlLength)
535 len = cp->maxControlLength;
536
537
538 if (copy_from_user(bp->bufp + AUH_SIZE, buf, len)) {
539 dbg("copy_from_user failed");
540 auerbuf_releasebuf(bp);
541
542 wake_up(&cp->bufferwait);
543 up(&cp->mutex);
544 up(&ccp->mutex);
545 return -EIO;
546 }
547
548
549 *(bp->bufp) = ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT;
550
551
552 bp->len = len + AUH_SIZE;
553 bp->dr->bRequestType = AUT_WREQ;
554 bp->dr->bRequest = AUV_WBLOCK;
555 bp->dr->wValue = cpu_to_le16(0);
556 bp->dr->wIndex =
557 cpu_to_le16(ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT);
558 bp->dr->wLength = cpu_to_le16(len + AUH_SIZE);
559 FILL_CONTROL_URB(bp->urbp, cp->usbdev,
560 usb_sndctrlpipe(cp->usbdev, 0),
561 (unsigned char *) bp->dr, bp->bufp,
562 len + AUH_SIZE, auerchar_ctrlwrite_complete, bp);
563
564 ret = auerchain_submit_urb(&cp->controlchain, bp->urbp);
565 up(&cp->mutex);
566 if (ret) {
567 dbg("auerchar_write: nonzero result of auerchain_submit_urb %d", ret);
568 auerbuf_releasebuf(bp);
569
570 wake_up(&cp->bufferwait);
571 up(&ccp->mutex);
572 return -EIO;
573 } else {
574 dbg("auerchar_write: Write OK");
575 up(&ccp->mutex);
576 return len;
577 }
578}
579
580
581
582int auerchar_release(struct inode *inode, struct file *file)
583{
584 struct auerchar *ccp = (struct auerchar *) file->private_data;
585 struct auerswald *cp;
586 dbg("release");
587
588
589 if (down_interruptible(&ccp->mutex)) {
590 return -ERESTARTSYS;
591 }
592 cp = ccp->auerdev;
593 if (cp) {
594 if (down_interruptible(&cp->mutex)) {
595 up(&ccp->mutex);
596 return -ERESTARTSYS;
597 }
598
599 auerswald_removeservice(cp, &ccp->scontext);
600
601 if ((--cp->open_count <= 0) && (cp->usbdev == NULL)) {
602
603 up(&cp->mutex);
604 auerswald_delete(cp);
605 } else {
606 up(&cp->mutex);
607 }
608 cp = NULL;
609 ccp->auerdev = NULL;
610 }
611 up(&ccp->mutex);
612 auerchar_delete(ccp);
613
614 return 0;
615}
616