1 /* $NetBSD: fwdev.c,v 1.8 2006/11/16 16:10:43 jdolecek Exp $ */
2 /*-
3 * Copyright (c) 2003 Hidetoshi Shimokawa
4 * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the acknowledgement as bellow:
17 *
18 * This product includes software developed by K. Kobayashi and H. Shimokawa
19 *
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * $FreeBSD: /repoman/r/ncvs/src/sys/dev/firewire/fwdev.c,v 1.46 2005/03/31 12:19:42 phk Exp $
36 *
37 */
38
39 #if defined(__FreeBSD__)
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/types.h>
43 #include <sys/mbuf.h>
44 #if defined(__DragonFly__) || __FreeBSD_version < 500000
45 #include <sys/buf.h>
46 #else
47 #include <sys/bio.h>
48 #endif
49
50 #include <sys/kernel.h>
51 #include <sys/malloc.h>
52 #include <sys/conf.h>
53 #include <sys/poll.h>
54
55 #include <sys/bus.h>
56 #include <sys/ctype.h>
57 #include <machine/bus.h>
58
59 #include <sys/ioccom.h>
60
61 #ifdef __DragonFly__
62 #include "fw_port.h"
63 #include "firewire.h"
64 #include "firewirereg.h"
65 #include "fwdma.h"
66 #include "fwmem.h"
67 #include "iec68113.h"
68 #else
69 #include <dev/firewire/fw_port.h>
70 #include <dev/firewire/firewire.h>
71 #include <dev/firewire/firewirereg.h>
72 #include <dev/firewire/fwdma.h>
73 #include <dev/firewire/fwmem.h>
74 #include <dev/firewire/iec68113.h>
75 #endif
76 #elif defined(__NetBSD__)
77 #include <sys/param.h>
78 #include <sys/device.h>
79 #include <sys/errno.h>
80 #include <sys/buf.h>
81 #include <sys/conf.h>
82 #include <sys/kernel.h>
83 #include <sys/malloc.h>
84 #include <sys/mbuf.h>
85 #include <sys/poll.h>
86 #include <sys/proc.h>
87
88 #include <machine/bus.h>
89
90 #include <dev/ieee1394/fw_port.h>
91 #include <dev/ieee1394/firewire.h>
92 #include <dev/ieee1394/firewirereg.h>
93 #include <dev/ieee1394/fwdma.h>
94 #include <dev/ieee1394/fwmem.h>
95 #include <dev/ieee1394/iec68113.h>
96 #endif
97
98 #define FWNODE_INVAL 0xffff
99
100 #if defined(__FreeBSD__)
101 static d_open_t fw_open;
102 static d_close_t fw_close;
103 static d_ioctl_t fw_ioctl;
104 static d_poll_t fw_poll;
105 static d_read_t fw_read; /* for Isochronous packet */
106 static d_write_t fw_write;
107 static d_mmap_t fw_mmap;
108 static d_strategy_t fw_strategy;
109
110 struct cdevsw firewire_cdevsw = {
111 #ifdef __DragonFly__
112 #define CDEV_MAJOR 127
113 "fw", CDEV_MAJOR, D_MEM, NULL, 0,
114 fw_open, fw_close, fw_read, fw_write, fw_ioctl,
115 fw_poll, fw_mmap, fw_strategy, nodump, nopsize,
116 #elif __FreeBSD_version >= 500104
117 .d_version = D_VERSION,
118 .d_open = fw_open,
119 .d_close = fw_close,
120 .d_read = fw_read,
121 .d_write = fw_write,
122 .d_ioctl = fw_ioctl,
123 .d_poll = fw_poll,
124 .d_mmap = fw_mmap,
125 .d_strategy = fw_strategy,
126 .d_name = "fw",
127 .d_flags = D_MEM | D_NEEDGIANT
128 #else
129 #define CDEV_MAJOR 127
130 fw_open, fw_close, fw_read, fw_write, fw_ioctl,
131 fw_poll, fw_mmap, fw_strategy, "fw", CDEV_MAJOR,
132 nodump, nopsize, D_MEM, -1
133 #endif
134 };
135 #elif defined(__NetBSD__)
136 dev_type_open(fw_open);
137 dev_type_close(fw_close);
138 dev_type_read(fw_read);
139 dev_type_write(fw_write);
140 dev_type_ioctl(fw_ioctl);
141 dev_type_poll(fw_poll);
142 dev_type_mmap(fw_mmap);
143 dev_type_strategy(fw_strategy);
144
145 const struct bdevsw fw_bdevsw = {
146 fw_open, fw_close, fw_strategy, fw_ioctl, nodump, nosize, D_OTHER,
147 };
148
149 const struct cdevsw fw_cdevsw = {
150 fw_open, fw_close, fw_read, fw_write, fw_ioctl,
151 nostop, notty, fw_poll, fw_mmap, nokqfilter, D_OTHER,
152 };
153 #endif
154
155 struct fw_drv1 {
156 struct firewire_comm *fc;
157 struct fw_xferq *ir;
158 struct fw_xferq *it;
159 struct fw_isobufreq bufreq;
160 STAILQ_HEAD(, fw_bind) binds;
161 STAILQ_HEAD(, fw_xfer) rq;
162 };
163
164 static int
165 fwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q,
166 struct fw_bufspec *b)
167 {
168 int i;
169
170 if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF))
171 return(EBUSY);
172
173 q->bulkxfer = (struct fw_bulkxfer *) malloc(
174 sizeof(struct fw_bulkxfer) * b->nchunk,
175 M_FW, M_WAITOK);
176 if (q->bulkxfer == NULL)
177 return(ENOMEM);
178
179 b->psize = roundup2(b->psize, sizeof(uint32_t));
180 q->buf = fwdma_malloc_multiseg(fc, sizeof(uint32_t),
181 b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK);
182
183 if (q->buf == NULL) {
184 free(q->bulkxfer, M_FW);
185 q->bulkxfer = NULL;
186 return(ENOMEM);
187 }
188 q->bnchunk = b->nchunk;
189 q->bnpacket = b->npacket;
190 q->psize = (b->psize + 3) & ~3;
191 q->queued = 0;
192
193 STAILQ_INIT(&q->stvalid);
194 STAILQ_INIT(&q->stfree);
195 STAILQ_INIT(&q->stdma);
196 q->stproc = NULL;
197
198 for(i = 0 ; i < q->bnchunk; i++){
199 q->bulkxfer[i].poffset = i * q->bnpacket;
200 q->bulkxfer[i].mbuf = NULL;
201 STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link);
202 }
203
204 q->flag &= ~FWXFERQ_MODEMASK;
205 q->flag |= FWXFERQ_STREAM;
206 q->flag |= FWXFERQ_EXTBUF;
207
208 return (0);
209 }
210
211 static int
212 fwdev_freebuf(struct fw_xferq *q)
213 {
214 if (q->flag & FWXFERQ_EXTBUF) {
215 if (q->buf != NULL)
216 fwdma_free_multiseg(q->buf);
217 q->buf = NULL;
218 free(q->bulkxfer, M_FW);
219 q->bulkxfer = NULL;
220 q->flag &= ~FWXFERQ_EXTBUF;
221 q->psize = 0;
222 q->maxq = FWMAXQUEUE;
223 }
224 return (0);
225 }
226
227
228 FW_OPEN(fw)
229 {
230 int err = 0;
231 struct fw_drv1 *d;
232 FW_OPEN_START;
233
234 FWDEV_OPEN_START;
235
236 if (dev->si_drv1 != NULL)
237 return (EBUSY);
238
239 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
240 if ((dev->si_flags & SI_NAMED) == 0) {
241 int unit = DEV2UNIT(dev);
242 int sub = DEV2SUB(dev);
243
244 make_dev(&firewire_cdevsw, minor(dev),
245 UID_ROOT, GID_OPERATOR, 0660,
246 "fw%d.%d", unit, sub);
247 }
248 #endif
249
250 dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO);
251 if (dev->si_drv1 == NULL)
252 return (ENOMEM);
253
254 d = (struct fw_drv1 *)dev->si_drv1;
255 d->fc = sc->fc;
256 STAILQ_INIT(&d->binds);
257 STAILQ_INIT(&d->rq);
258
259 return err;
260 }
261
262 FW_CLOSE(fw)
263 {
264 struct firewire_comm *fc;
265 struct fw_drv1 *d;
266 struct fw_xfer *xfer;
267 struct fw_bind *fwb;
268 int err = 0;
269 FW_CLOSE_START;
270
271 FWDEV_CLOSE_START;
272
273 d = (struct fw_drv1 *)dev->si_drv1;
274 fc = d->fc;
275
276 /* remove binding */
277 for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL;
278 fwb = STAILQ_FIRST(&d->binds)) {
279 fw_bindremove(fc, fwb);
280 STAILQ_REMOVE_HEAD(&d->binds, chlist);
281 fw_xferlist_remove(&fwb->xferlist);
282 free(fwb, M_FW);
283 }
284 if (d->ir != NULL) {
285 struct fw_xferq *ir = d->ir;
286
287 if ((ir->flag & FWXFERQ_OPEN) == 0)
288 return (EINVAL);
289 if (ir->flag & FWXFERQ_RUNNING) {
290 ir->flag &= ~FWXFERQ_RUNNING;
291 fc->irx_disable(fc, ir->dmach);
292 }
293 /* free extbuf */
294 fwdev_freebuf(ir);
295 /* drain receiving buffer */
296 for (xfer = STAILQ_FIRST(&ir->q);
297 xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) {
298 ir->queued --;
299 STAILQ_REMOVE_HEAD(&ir->q, link);
300
301 xfer->resp = 0;
302 fw_xfer_done(xfer);
303 }
304 ir->flag &= ~(FWXFERQ_OPEN |
305 FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
306 d->ir = NULL;
307
308 }
309 if (d->it != NULL) {
310 struct fw_xferq *it = d->it;
311
312 if ((it->flag & FWXFERQ_OPEN) == 0)
313 return (EINVAL);
314 if (it->flag & FWXFERQ_RUNNING) {
315 it->flag &= ~FWXFERQ_RUNNING;
316 fc->itx_disable(fc, it->dmach);
317 }
318 /* free extbuf */
319 fwdev_freebuf(it);
320 it->flag &= ~(FWXFERQ_OPEN |
321 FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
322 d->it = NULL;
323 }
324 free(dev->si_drv1, M_FW);
325 dev->si_drv1 = NULL;
326
327 return err;
328 }
329
330 static int
331 fw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag)
332 {
333 int err = 0, s;
334 struct fw_xfer *xfer;
335 struct fw_bind *fwb;
336 struct fw_pkt *fp;
337 const struct tcode_info *tinfo;
338
339 while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == 0)
340 err = tsleep(&d->rq, FWPRI, "fwra", 0);
341
342 if (err != 0)
343 return (err);
344
345 s = splfw();
346 STAILQ_REMOVE_HEAD(&d->rq, link);
347 splx(s);
348 fp = &xfer->recv.hdr;
349 #if 0 /* for GASP ?? */
350 if (fc->irx_post != NULL)
351 fc->irx_post(fc, fp->mode.ld);
352 #endif
353 tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode];
354 err = uiomove((void *)fp, tinfo->hdr_len, uio);
355 if (err)
356 goto out;
357 err = uiomove((void *)xfer->recv.payload, xfer->recv.pay_len, uio);
358
359 out:
360 /* recycle this xfer */
361 fwb = (struct fw_bind *)xfer->sc;
362 fw_xfer_unload(xfer);
363 xfer->recv.pay_len = PAGE_SIZE;
364 STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link);
365 return (err);
366 }
367
368 /*
369 * read request.
370 */
371 FW_READ(fw)
372 {
373 FW_READ_START;
374 struct fw_drv1 *d;
375 struct fw_xferq *ir;
376 struct firewire_comm *fc;
377 int err = 0, s, slept = 0;
378 struct fw_pkt *fp;
379
380 FWDEV_READ_START;
381
382 d = (struct fw_drv1 *)dev->si_drv1;
383 fc = d->fc;
384 ir = d->ir;
385
386 if (ir == NULL)
387 return (fw_read_async(d, uio, ioflag));
388
389 if (ir->buf == NULL)
390 return (EIO);
391
392 readloop:
393 if (ir->stproc == NULL) {
394 /* iso bulkxfer */
395 ir->stproc = STAILQ_FIRST(&ir->stvalid);
396 if (ir->stproc != NULL) {
397 s = splfw();
398 STAILQ_REMOVE_HEAD(&ir->stvalid, link);
399 splx(s);
400 ir->queued = 0;
401 }
402 }
403 if (ir->stproc == NULL) {
404 /* no data avaliable */
405 if (slept == 0) {
406 slept = 1;
407 ir->flag |= FWXFERQ_WAKEUP;
408 err = tsleep(ir, FWPRI, "fw_read", hz);
409 ir->flag &= ~FWXFERQ_WAKEUP;
410 if (err == 0)
411 goto readloop;
412 } else if (slept == 1)
413 err = EIO;
414 return err;
415 } else if(ir->stproc != NULL) {
416 /* iso bulkxfer */
417 fp = (struct fw_pkt *)fwdma_v_addr(ir->buf,
418 ir->stproc->poffset + ir->queued);
419 if(fc->irx_post != NULL)
420 fc->irx_post(fc, fp->mode.ld);
421 if(fp->mode.stream.len == 0){
422 err = EIO;
423 return err;
424 }
425 err = uiomove((caddr_t)fp,
426 fp->mode.stream.len + sizeof(uint32_t), uio);
427 ir->queued ++;
428 if(ir->queued >= ir->bnpacket){
429 s = splfw();
430 STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link);
431 splx(s);
432 fc->irx_enable(fc, ir->dmach);
433 ir->stproc = NULL;
434 }
435 if (uio->uio_resid >= ir->psize) {
436 slept = -1;
437 goto readloop;
438 }
439 }
440 return err;
441 }
442
443 static int
444 fw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag)
445 {
446 struct fw_xfer *xfer;
447 struct fw_pkt pkt;
448 const struct tcode_info *tinfo;
449 int err;
450
451 bzero(&pkt, sizeof(struct fw_pkt));
452 if ((err = uiomove((caddr_t)&pkt, sizeof(uint32_t), uio)))
453 return (err);
454 tinfo = &d->fc->tcode[pkt.mode.hdr.tcode];
455 if ((err = uiomove((caddr_t)&pkt + sizeof(uint32_t),
456 tinfo->hdr_len - sizeof(uint32_t), uio)))
457 return (err);
458
459 if ((xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid,
460 PAGE_SIZE/*XXX*/)) == NULL)
461 return (ENOMEM);
462
463 bcopy(&pkt, &xfer->send.hdr, sizeof(struct fw_pkt));
464 xfer->send.pay_len = uio->uio_resid;
465 if (uio->uio_resid > 0) {
466 if ((err = uiomove((caddr_t)&xfer->send.payload[0],
467 uio->uio_resid, uio)))
468 goto out;
469 }
470
471 xfer->fc = d->fc;
472 xfer->sc = NULL;
473 xfer->hand = fw_asy_callback;
474 xfer->send.spd = 2 /* XXX */;
475
476 if ((err = fw_asyreq(xfer->fc, -1, xfer)))
477 goto out;
478
479 if ((err = tsleep(xfer, FWPRI, "fwwa", 0)))
480 goto out;
481
482 if (xfer->resp != 0) {
483 err = xfer->resp;
484 goto out;
485 }
486
487 if (xfer->state == FWXF_RCVD) {
488 STAILQ_INSERT_TAIL(&d->rq, xfer, link);
489 return (0);
490 }
491
492 out:
493 fw_xfer_free(xfer);
494 return (err);
495 }
496
497 FW_WRITE(fw)
498 {
499 FW_WRITE_START;
500 int err = 0;
501 int s, slept = 0;
502 struct fw_drv1 *d;
503 struct fw_pkt *fp;
504 struct firewire_comm *fc;
505 struct fw_xferq *it;
506
507 FWDEV_WRITE_START;
508 d = (struct fw_drv1 *)dev->si_drv1;
509 fc = d->fc;
510 it = d->it;
511
512 if (it == NULL)
513 return (fw_write_async(d, uio, ioflag));
514
515 if (it->buf == NULL)
516 return (EIO);
517 isoloop:
518 if (it->stproc == NULL) {
519 it->stproc = STAILQ_FIRST(&it->stfree);
520 if (it->stproc != NULL) {
521 s = splfw();
522 STAILQ_REMOVE_HEAD(&it->stfree, link);
523 splx(s);
524 it->queued = 0;
525 } else if (slept == 0) {
526 slept = 1;
527 err = fc->itx_enable(fc, it->dmach);
528 if (err)
529 return err;
530 err = tsleep(it, FWPRI, "fw_write", hz);
531 if (err)
532 return err;
533 goto isoloop;
534 } else {
535 err = EIO;
536 return err;
537 }
538 }
539 fp = (struct fw_pkt *)fwdma_v_addr(it->buf,
540 it->stproc->poffset + it->queued);
541 err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio);
542 err = uiomove((caddr_t)fp->mode.stream.payload,
543 fp->mode.stream.len, uio);
544 it->queued ++;
545 if (it->queued >= it->bnpacket) {
546 s = splfw();
547 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
548 splx(s);
549 it->stproc = NULL;
550 err = fc->itx_enable(fc, it->dmach);
551 }
552 if (uio->uio_resid >= sizeof(struct fw_isohdr)) {
553 slept = 0;
554 goto isoloop;
555 }
556 return err;
557 }
558
559 static void
560 fw_hand(struct fw_xfer *xfer)
561 {
562 struct fw_bind *fwb;
563 struct fw_drv1 *d;
564
565 fwb = (struct fw_bind *)xfer->sc;
566 d = (struct fw_drv1 *)fwb->sc;
567 STAILQ_INSERT_TAIL(&d->rq, xfer, link);
568 wakeup(&d->rq);
569 }
570
571 /*
572 * ioctl support.
573 */
574 FW_IOCTL(fw)
575 {
576 FW_IOCTL_START;
577 struct firewire_comm *fc;
578 struct fw_drv1 *d;
579 int i, len, err = 0;
580 struct fw_device *fwdev;
581 struct fw_bind *fwb;
582 struct fw_xferq *ir, *it;
583 struct fw_xfer *xfer;
584 struct fw_pkt *fp;
585 struct fw_devinfo *devinfo;
586 void *ptr;
587
588 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data;
589 struct fw_asyreq *asyreq = (struct fw_asyreq *)data;
590 struct fw_isochreq *ichreq = (struct fw_isochreq *)data;
591 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data;
592 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data;
593 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data;
594
595 FWDEV_IOCTL_START;
596
597 if (!data)
598 return(EINVAL);
599
600 d = (struct fw_drv1 *)dev->si_drv1;
601 fc = d->fc;
602 ir = d->ir;
603 it = d->it;
604
605 switch (cmd) {
606 case FW_STSTREAM:
607 if (it == NULL) {
608 for (i = 0; i < fc->nisodma; i ++) {
609 it = fc->it[i];
610 if ((it->flag & FWXFERQ_OPEN) == 0)
611 break;
612 }
613 if (i >= fc->nisodma) {
614 err = EBUSY;
615 break;
616 }
617 err = fwdev_allocbuf(fc, it, &d->bufreq.tx);
618 if (err)
619 break;
620 it->flag |= FWXFERQ_OPEN;
621 }
622 it->flag &= ~0xff;
623 it->flag |= (0x3f & ichreq->ch);
624 it->flag |= ((0x3 & ichreq->tag) << 6);
625 d->it = it;
626 break;
627 case FW_GTSTREAM:
628 if (it != NULL) {
629 ichreq->ch = it->flag & 0x3f;
630 ichreq->tag = it->flag >> 2 & 0x3;
631 } else
632 err = EINVAL;
633 break;
634 case FW_SRSTREAM:
635 if (ir == NULL) {
636 for (i = 0; i < fc->nisodma; i ++) {
637 ir = fc->ir[i];
638 if ((ir->flag & FWXFERQ_OPEN) == 0)
639 break;
640 }
641 if (i >= fc->nisodma) {
642 err = EBUSY;
643 break;
644 }
645 err = fwdev_allocbuf(fc, ir, &d->bufreq.rx);
646 if (err)
647 break;
648 ir->flag |= FWXFERQ_OPEN;
649 }
650 ir->flag &= ~0xff;
651 ir->flag |= (0x3f & ichreq->ch);
652 ir->flag |= ((0x3 & ichreq->tag) << 6);
653 d->ir = ir;
654 err = fc->irx_enable(fc, ir->dmach);
655 break;
656 case FW_GRSTREAM:
657 if (d->ir != NULL) {
658 ichreq->ch = ir->flag & 0x3f;
659 ichreq->tag = ir->flag >> 2 & 0x3;
660 } else
661 err = EINVAL;
662 break;
663 case FW_SSTBUF:
664 bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq));
665 break;
666 case FW_GSTBUF:
667 bzero(&ibufreq->rx, sizeof(ibufreq->rx));
668 if (ir != NULL) {
669 ibufreq->rx.nchunk = ir->bnchunk;
670 ibufreq->rx.npacket = ir->bnpacket;
671 ibufreq->rx.psize = ir->psize;
672 }
673 bzero(&ibufreq->tx, sizeof(ibufreq->tx));
674 if (it != NULL) {
675 ibufreq->tx.nchunk = it->bnchunk;
676 ibufreq->tx.npacket = it->bnpacket;
677 ibufreq->tx.psize = it->psize;
678 }
679 break;
680 case FW_ASYREQ:
681 {
682 const struct tcode_info *tinfo;
683 int pay_len = 0;
684
685 fp = &asyreq->pkt;
686 tinfo = &fc->tcode[fp->mode.hdr.tcode];
687
688 if ((tinfo->flag & FWTI_BLOCK_ASY) != 0)
689 pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len);
690
691 xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/);
692 if (xfer == NULL)
693 return (ENOMEM);
694
695 switch (asyreq->req.type) {
696 case FWASREQNODE:
697 break;
698 case FWASREQEUI:
699 fwdev = fw_noderesolve_eui64(fc,
700 &asyreq->req.dst.eui);
701 if (fwdev == NULL) {
702 device_printf(fc->bdev,
703 "cannot find node\n");
704 err = EINVAL;
705 goto out;
706 }
707 fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst;
708 break;
709 case FWASRESTL:
710 /* XXX what's this? */
711 break;
712 case FWASREQSTREAM:
713 /* nothing to do */
714 break;
715 }
716
717 bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len);
718 if (pay_len > 0)
719 bcopy((char *)fp + tinfo->hdr_len,
720 (void *)xfer->send.payload, pay_len);
721 xfer->send.spd = asyreq->req.sped;
722 xfer->hand = fw_asy_callback;
723
724 if ((err = fw_asyreq(fc, -1, xfer)) != 0)
725 goto out;
726 if ((err = tsleep(xfer, FWPRI, "asyreq", hz)) != 0)
727 goto out;
728 if (xfer->resp != 0) {
729 err = EIO;
730 goto out;
731 }
732 if ((tinfo->flag & FWTI_TLABEL) == 0)
733 goto out;
734
735 /* copy response */
736 tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode];
737 if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB ||
738 xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) {
739 pay_len = xfer->recv.pay_len;
740 if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) {
741 asyreq->req.len = xfer->recv.pay_len +
742 tinfo->hdr_len;
743 } else {
744 err = EINVAL;
745 pay_len = 0;
746 }
747 } else {
748 pay_len = 0;
749 }
750 bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len);
751 bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, pay_len);
752 out:
753 fw_xfer_free_buf(xfer);
754 break;
755 }
756 case FW_IBUSRST:
757 fc->ibr(fc);
758 break;
759 case FW_CBINDADDR:
760 fwb = fw_bindlookup(fc,
761 bindreq->start.hi, bindreq->start.lo);
762 if(fwb == NULL){
763 err = EINVAL;
764 break;
765 }
766 fw_bindremove(fc, fwb);
767 STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist);
768 fw_xferlist_remove(&fwb->xferlist);
769 free(fwb, M_FW);
770 break;
771 case FW_SBINDADDR:
772 if(bindreq->len <= 0 ){
773 err = EINVAL;
774 break;
775 }
776 if(bindreq->start.hi > 0xffff ){
777 err = EINVAL;
778 break;
779 }
780 fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT);
781 if(fwb == NULL){
782 err = ENOMEM;
783 break;
784 }
785 fwb->start = ((u_int64_t)bindreq->start.hi << 32) |
786 bindreq->start.lo;
787 fwb->end = fwb->start + bindreq->len;
788 fwb->sc = (void *)d;
789 STAILQ_INIT(&fwb->xferlist);
790 err = fw_bindadd(fc, fwb);
791 if (err == 0) {
792 fw_xferlist_add(&fwb->xferlist, M_FWXFER,
793 /* XXX */
794 PAGE_SIZE, PAGE_SIZE, 5,
795 fc, (void *)fwb, fw_hand);
796 STAILQ_INSERT_TAIL(&d->binds, fwb, chlist);
797 }
798 break;
799 case FW_GDEVLST:
800 i = len = 1;
801 /* myself */
802 devinfo = &fwdevlst->dev[0];
803 devinfo->dst = fc->nodeid;
804 devinfo->status = 0; /* XXX */
805 devinfo->eui.hi = fc->eui.hi;
806 devinfo->eui.lo = fc->eui.lo;
807 STAILQ_FOREACH(fwdev, &fc->devices, link) {
808 if(len < FW_MAX_DEVLST){
809 devinfo = &fwdevlst->dev[len++];
810 devinfo->dst = fwdev->dst;
811 devinfo->status =
812 (fwdev->status == FWDEVINVAL)?0:1;
813 devinfo->eui.hi = fwdev->eui.hi;
814 devinfo->eui.lo = fwdev->eui.lo;
815 }
816 i++;
817 }
818 fwdevlst->n = i;
819 fwdevlst->info_len = len;
820 break;
821 case FW_GTPMAP:
822 bcopy(fc->topology_map, data,
823 (fc->topology_map->crc_len + 1) * 4);
824 break;
825 case FW_GCROM:
826 STAILQ_FOREACH(fwdev, &fc->devices, link)
827 if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui))
828 break;
829 if (fwdev == NULL) {
830 if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) {
831 err = FWNODE_INVAL;
832 break;
833 }
834 /* myself */
835 ptr = malloc(CROMSIZE, M_FW, M_WAITOK);
836 len = CROMSIZE;
837 for (i = 0; i < CROMSIZE/4; i++)
838 ((uint32_t *)ptr)[i]
839 = ntohl(fc->config_rom[i]);
840 } else {
841 /* found */
842 ptr = (void *)&fwdev->csrrom[0];
843 if (fwdev->rommax < CSRROMOFF)
844 len = 0;
845 else
846 len = fwdev->rommax - CSRROMOFF + 4;
847 }
848 if (crom_buf->len < len)
849 len = crom_buf->len;
850 else
851 crom_buf->len = len;
852 err = copyout(ptr, crom_buf->ptr, len);
853 if (fwdev == NULL)
854 /* myself */
855 free(ptr, M_FW);
856 break;
857 default:
858 FWDEV_IOCTL_REDIRECT;
859 break;
860 }
861 return err;
862 }
863
864 FW_POLL(fw)
865 {
866 FW_POLL_START;
867 struct fw_xferq *ir;
868 int revents;
869 int tmp;
870
871 FWDEV_POLL_START;
872
873 ir = ((struct fw_drv1 *)dev->si_drv1)->ir;
874 revents = 0;
875 tmp = POLLIN | POLLRDNORM;
876 if (events & tmp) {
877 if (STAILQ_FIRST(&ir->q) != NULL)
878 revents |= tmp;
879 else
880 selrecord(td, &ir->rsel);
881 }
882 tmp = POLLOUT | POLLWRNORM;
883 if (events & tmp) {
884 /* XXX should be fixed */
885 revents |= tmp;
886 }
887
888 return revents;
889 }
890
891 FW_MMAP(fw)
892 {
893 FW_MMAP_START;
894
895 FWDEV_MMAP_START;
896
897 return EINVAL;
898 }
899
900 void
901 fw_strategy(struct bio *bp)
902 {
903 FW_STRATEGY_START;
904
905 FWDEV_STRATEGY_START;
906
907 bp->bio_error = EOPNOTSUPP;
908 bp->bio_flags |= BIO_ERROR;
909 bp->bio_resid = bp->bio_bcount;
910 biodone(bp);
911 }
912
913 #if defined(__FreeBSD__)
914 int
915 fwdev_makedev(struct firewire_softc *sc)
916 {
917 int err = 0;
918
919 #if defined(__DragonFly__)
920 int unit;
921
922 unit = device_get_unit(sc->fc->bdev);
923 cdevsw_add(&firewire_cdevsw, FW_UNITMASK, FW_UNIT(unit));
924 #elif __FreeBSD_version < 500000
925 cdevsw_add(&firewire_cdevsw);
926 #else
927 DEV_T d;
928 int unit;
929
930 unit = device_get_unit(sc->fc->bdev);
931 sc->dev = make_dev(&firewire_cdevsw, MAKEMINOR(0, unit, 0),
932 UID_ROOT, GID_OPERATOR, 0660,
933 "fw%d.%d", unit, 0);
934 d = make_dev(&firewire_cdevsw,
935 MAKEMINOR(FWMEM_FLAG, unit, 0),
936 UID_ROOT, GID_OPERATOR, 0660,
937 "fwmem%d.%d", unit, 0);
938 dev_depends(sc->dev, d);
939 make_dev_alias(sc->dev, "fw%d", unit);
940 make_dev_alias(d, "fwmem%d", unit);
941 #endif
942
943 return (err);
944 }
945
946 int
947 fwdev_destroydev(struct firewire_softc *sc)
948 {
949 int err = 0;
950
951 #if defined(__DragonFly__)
952 int unit;
953
954 unit = device_get_unit(sc->fc->bdev);
955 cdevsw_remove(&firewire_cdevsw, FW_UNITMASK, FW_UNIT(unit));
956 #elif __FreeBSD_version < 500000
957 cdevsw_remove(&firewire_cdevsw);
958 #else
959 destroy_dev(sc->dev);
960 #endif
961 return (err);
962 }
963
964 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
965 #define NDEVTYPE 2
966 void
967 fwdev_clone(void *arg, char *name, int namelen, DEV_T *dev)
968 {
969 struct firewire_softc *sc;
970 char *devnames[NDEVTYPE] = {"fw", "fwmem"};
971 char *subp = NULL;
972 int devflag[NDEVTYPE] = {0, FWMEM_FLAG};
973 int i, unit = 0, sub = 0;
974
975 if (*dev != NULL)
976 return;
977
978 for (i = 0; i < NDEVTYPE; i++)
979 if (dev_stdclone(name, &subp, devnames[i], &unit) == 2)
980 goto found;
981 /* not match */
982 return;
983 found:
984
985 if (subp == NULL || *subp++ != '.')
986 return;
987
988 /* /dev/fwU.S */
989 while (isdigit(*subp)) {
990 sub *= 10;
991 sub += *subp++ - '';
992 }
993 if (*subp != '\0')
994 return;
995
996 sc = devclass_get_softc(firewire_devclass, unit);
997 if (sc == NULL)
998 return;
999 *dev = make_dev(&firewire_cdevsw, MAKEMINOR(devflag[i], unit, sub),
1000 UID_ROOT, GID_OPERATOR, 0660,
1001 "%s%d.%d", devnames[i], unit, sub);
1002 dev_ref(*dev);
1003 (*dev)->si_flags |= SI_CHEAPCLONE;
1004 dev_depends(sc->dev, *dev);
1005 return;
1006 }
1007 #endif
1008 #endif
Cache object: 65bbfa7985ad5366f8906e7d5069785c
|