Deleted Added
sdiff udiff text old ( 111753 ) new ( 111815 )
full compact
1/*
2 * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the acknowledgement as bellow:
15 *
16 * This product includes software developed by K. Kobayashi and H. Shimokawa
17 *
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $FreeBSD: head/sys/dev/firewire/fwdev.c 111753 2003-03-02 18:51:46Z phk $
34 *
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/types.h>
40#include <sys/mbuf.h>
41
42#include <sys/kernel.h>
43#include <sys/malloc.h>
44#include <sys/conf.h>
45#include <sys/uio.h>
46#include <sys/poll.h>
47
48#include <sys/bus.h>
49
50#include <sys/ioccom.h>
51
52#include <dev/firewire/firewire.h>
53#include <dev/firewire/firewirereg.h>
54#include <dev/firewire/fwmem.h>
55#include <dev/firewire/iec68113.h>
56
57#define CDEV_MAJOR 127
58#define FWNODE_INVAL 0xffff
59
60static d_open_t fw_open;
61static d_close_t fw_close;
62static d_ioctl_t fw_ioctl;
63static d_poll_t fw_poll;
64static d_read_t fw_read; /* for Isochronous packet */
65static d_write_t fw_write;
66static d_mmap_t fw_mmap;
67
68struct cdevsw firewire_cdevsw =
69{
70 /* open */ fw_open,
71 /* close */ fw_close,
72 /* read */ fw_read,
73 /* write */ fw_write,
74 /* ioctl */ fw_ioctl,
75 /* poll */ fw_poll,
76 /* mmap */ fw_mmap,
77 /* strategy */ nostrategy,
78 /* name */ "fw",
79 /* maj */ CDEV_MAJOR,
80 /* dump */ nodump,
81 /* psize */ nopsize,
82 /* flags */ D_MEM
83};
84
85static int
86fw_open (dev_t dev, int flags, int fmt, fw_proc *td)
87{
88 struct firewire_softc *sc;
89 int unit = DEV2UNIT(dev);
90 int sub = DEV2DMACH(dev);
91
92 int err = 0;
93
94 if (DEV_FWMEM(dev))
95 return fwmem_open(dev, flags, fmt, td);
96
97 sc = devclass_get_softc(firewire_devclass, unit);
98 if(sc->fc->ir[sub]->flag & FWXFERQ_OPEN){
99 err = EBUSY;
100 return err;
101 }
102 if(sc->fc->it[sub]->flag & FWXFERQ_OPEN){
103 err = EBUSY;
104 return err;
105 }
106 if(sc->fc->ir[sub]->flag & FWXFERQ_MODEMASK){
107 err = EBUSY;
108 return err;
109 }
110/* Default is per packet mode */
111 sc->fc->ir[sub]->flag |= FWXFERQ_OPEN;
112 sc->fc->it[sub]->flag |= FWXFERQ_OPEN;
113 sc->fc->ir[sub]->flag |= FWXFERQ_PACKET;
114 return err;
115}
116
117static int
118fw_close (dev_t dev, int flags, int fmt, fw_proc *td)
119{
120 struct firewire_softc *sc;
121 int unit = DEV2UNIT(dev);
122 int sub = DEV2DMACH(dev);
123 struct fw_xfer *xfer;
124 struct fw_bind *fwb;
125 int err = 0;
126
127 if (DEV_FWMEM(dev))
128 return fwmem_close(dev, flags, fmt, td);
129
130 sc = devclass_get_softc(firewire_devclass, unit);
131 if(!(sc->fc->ir[sub]->flag & FWXFERQ_OPEN)){
132 err = EINVAL;
133 return err;
134 }
135 sc->fc->ir[sub]->flag &= ~FWXFERQ_OPEN;
136 if(!(sc->fc->it[sub]->flag & FWXFERQ_OPEN)){
137 err = EINVAL;
138 return err;
139 }
140 sc->fc->it[sub]->flag &= ~FWXFERQ_OPEN;
141
142 if(sc->fc->ir[sub]->flag & FWXFERQ_RUNNING){
143 sc->fc->irx_disable(sc->fc, sub);
144 }
145 if(sc->fc->it[sub]->flag & FWXFERQ_RUNNING){
146 sc->fc->it[sub]->flag &= ~FWXFERQ_RUNNING;
147 sc->fc->itx_disable(sc->fc, sub);
148 }
149#ifdef FWXFERQ_DV
150 if(sc->fc->it[sub]->flag & FWXFERQ_DV){
151 struct fw_dvbuf *dvbuf;
152
153 if((dvbuf = sc->fc->it[sub]->dvproc) != NULL){
154 free(dvbuf->buf, M_FW);
155 sc->fc->it[sub]->dvproc = NULL;
156 }
157 if((dvbuf = sc->fc->it[sub]->dvdma) != NULL){
158 free(dvbuf->buf, M_FW);
159 sc->fc->it[sub]->dvdma = NULL;
160 }
161 while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvvalid)) != NULL){
162 STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvvalid, link);
163 free(dvbuf->buf, M_FW);
164 }
165 while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvfree)) != NULL){
166 STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvfree, link);
167 free(dvbuf->buf, M_FW);
168 }
169 free(sc->fc->it[sub]->dvbuf, M_FW);
170 sc->fc->it[sub]->dvbuf = NULL;
171 }
172#endif
173 if(sc->fc->ir[sub]->flag & FWXFERQ_EXTBUF){
174 free(sc->fc->ir[sub]->buf, M_FW);
175 sc->fc->ir[sub]->buf = NULL;
176 free(sc->fc->ir[sub]->bulkxfer, M_FW);
177 sc->fc->ir[sub]->bulkxfer = NULL;
178 sc->fc->ir[sub]->flag &= ~FWXFERQ_EXTBUF;
179 sc->fc->ir[sub]->psize = PAGE_SIZE;
180 sc->fc->ir[sub]->maxq = FWMAXQUEUE;
181 }
182 if(sc->fc->it[sub]->flag & FWXFERQ_EXTBUF){
183 free(sc->fc->it[sub]->buf, M_FW);
184 sc->fc->it[sub]->buf = NULL;
185 free(sc->fc->it[sub]->bulkxfer, M_FW);
186 sc->fc->it[sub]->bulkxfer = NULL;
187#ifdef FWXFERQ_DV
188 sc->fc->it[sub]->dvbuf = NULL;
189#endif
190 sc->fc->it[sub]->flag &= ~FWXFERQ_EXTBUF;
191 sc->fc->it[sub]->psize = 0;
192 sc->fc->it[sub]->maxq = FWMAXQUEUE;
193 }
194 for(xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q);
195 xfer != NULL; xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q)){
196 sc->fc->ir[sub]->queued--;
197 STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->q, link);
198
199 xfer->resp = 0;
200 switch(xfer->act_type){
201 case FWACT_XFER:
202 fw_xfer_done(xfer);
203 break;
204 default:
205 break;
206 }
207 fw_xfer_free(xfer);
208 }
209 for(fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds); fwb != NULL;
210 fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds)){
211 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
212 STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->binds, chlist);
213 free(fwb, M_FW);
214 }
215 sc->fc->ir[sub]->flag &= ~FWXFERQ_MODEMASK;
216 sc->fc->it[sub]->flag &= ~FWXFERQ_MODEMASK;
217 return err;
218}
219
220/*
221 * read request.
222 */
223static int
224fw_read (dev_t dev, struct uio *uio, int ioflag)
225{
226 struct firewire_softc *sc;
227 struct fw_xferq *ir;
228 struct fw_xfer *xfer;
229 int err = 0, s, slept = 0;
230 int unit = DEV2UNIT(dev);
231 int sub = DEV2DMACH(dev);
232 struct fw_pkt *fp;
233
234 if (DEV_FWMEM(dev))
235 return fwmem_read(dev, uio, ioflag);
236
237 sc = devclass_get_softc(firewire_devclass, unit);
238
239 ir = sc->fc->ir[sub];
240
241 if (ir->flag & FWXFERQ_PACKET) {
242 ir->stproc = NULL;
243 }
244readloop:
245 xfer = STAILQ_FIRST(&ir->q);
246 if ((ir->flag & FWXFERQ_PACKET) == 0 && ir->stproc == NULL) {
247 /* iso bulkxfer */
248 ir->stproc = STAILQ_FIRST(&ir->stvalid);
249 if (ir->stproc != NULL) {
250 s = splfw();
251 STAILQ_REMOVE_HEAD(&ir->stvalid, link);
252 splx(s);
253 ir->queued = 0;
254 }
255 }
256 if (xfer == NULL && ir->stproc == NULL) {
257 /* no data avaliable */
258 if (slept == 0) {
259 slept = 1;
260 if ((ir->flag & FWXFERQ_RUNNING) == 0
261 && (ir->flag & FWXFERQ_PACKET)) {
262 err = sc->fc->irx_enable(sc->fc, sub);
263 if (err)
264 return err;
265 }
266 ir->flag |= FWXFERQ_WAKEUP;
267 err = tsleep(ir, FWPRI, "fw_read", hz);
268 ir->flag &= ~FWXFERQ_WAKEUP;
269 if (err == 0)
270 goto readloop;
271 } else if (slept == 1)
272 err = EIO;
273 return err;
274 } else if(xfer != NULL) {
275 /* per packet mode */
276 s = splfw();
277 ir->queued --;
278 STAILQ_REMOVE_HEAD(&ir->q, link);
279 splx(s);
280 fp = (struct fw_pkt *)(xfer->recv.buf + xfer->recv.off);
281 if(sc->fc->irx_post != NULL)
282 sc->fc->irx_post(sc->fc, fp->mode.ld);
283 err = uiomove(xfer->recv.buf + xfer->recv.off, xfer->recv.len, uio);
284 fw_xfer_free( xfer);
285 } else if(ir->stproc != NULL) {
286 /* iso bulkxfer */
287 fp = (struct fw_pkt *)(ir->stproc->buf + ir->queued * ir->psize);
288 if(sc->fc->irx_post != NULL)
289 sc->fc->irx_post(sc->fc, fp->mode.ld);
290 if(ntohs(fp->mode.stream.len) == 0){
291 err = EIO;
292 return err;
293 }
294 err = uiomove((caddr_t)fp,
295 ntohs(fp->mode.stream.len) + sizeof(u_int32_t), uio);
296#if 0
297 fp->mode.stream.len = 0;
298#endif
299 ir->queued ++;
300 if(ir->queued >= ir->bnpacket){
301 s = splfw();
302 STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link);
303 splx(s);
304 sc->fc->irx_enable(sc->fc, sub);
305 ir->stproc = NULL;
306 }
307 if (uio->uio_resid >= ir->psize) {
308 slept = -1;
309 goto readloop;
310 }
311 }
312 return err;
313}
314
315static int
316fw_write (dev_t dev, struct uio *uio, int ioflag)
317{
318 int err = 0;
319 struct firewire_softc *sc;
320 int unit = DEV2UNIT(dev);
321 int sub = DEV2DMACH(dev);
322 int s, slept = 0;
323 struct fw_pkt *fp;
324 struct fw_xfer *xfer;
325 struct fw_xferq *xferq;
326 struct firewire_comm *fc;
327 struct fw_xferq *it;
328
329 if (DEV_FWMEM(dev))
330 return fwmem_write(dev, uio, ioflag);
331
332 sc = devclass_get_softc(firewire_devclass, unit);
333 fc = sc->fc;
334 it = sc->fc->it[sub];
335
336 fp = (struct fw_pkt *)uio->uio_iov->iov_base;
337 switch(fp->mode.common.tcode){
338 case FWTCODE_RREQQ:
339 case FWTCODE_RREQB:
340 case FWTCODE_LREQ:
341 err = EINVAL;
342 return err;
343 case FWTCODE_WREQQ:
344 case FWTCODE_WREQB:
345 xferq = fc->atq;
346 break;
347 case FWTCODE_STREAM:
348 if(it->flag & FWXFERQ_PACKET){
349 xferq = fc->atq;
350 }else{
351 xferq = NULL;
352 }
353 break;
354 case FWTCODE_WRES:
355 case FWTCODE_RRESQ:
356 case FWTCODE_RRESB:
357 case FWTCODE_LRES:
358 xferq = fc->ats;
359 break;
360 default:
361 err = EINVAL;
362 return err;
363 }
364 /* Discard unsent buffered stream packet, when sending Asyrequrst */
365 if(xferq != NULL && it->stproc != NULL){
366 s = splfw();
367 STAILQ_INSERT_TAIL(&it->stfree, it->stproc, link);
368 splx(s);
369 it->stproc = NULL;
370 }
371#ifdef FWXFERQ_DV
372 if(xferq == NULL && !(it->flag & FWXFERQ_DV)){
373#else
374 if (xferq == NULL) {
375#endif
376isoloop:
377 if (it->stproc == NULL) {
378 it->stproc = STAILQ_FIRST(&it->stfree);
379 if (it->stproc != NULL) {
380 s = splfw();
381 STAILQ_REMOVE_HEAD(&it->stfree, link);
382 splx(s);
383 it->queued = 0;
384 } else if (slept == 0) {
385 slept = 1;
386 err = sc->fc->itx_enable(sc->fc, sub);
387 if (err)
388 return err;
389 err = tsleep(it, FWPRI,
390 "fw_write", hz);
391 if (err)
392 return err;
393 goto isoloop;
394 } else {
395 err = EIO;
396 return err;
397 }
398 }
399 fp = (struct fw_pkt *)
400 (it->stproc->buf + it->queued * it->psize);
401 err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio);
402 err = uiomove((caddr_t)fp->mode.stream.payload,
403 ntohs(fp->mode.stream.len), uio);
404 it->queued ++;
405 if (it->queued >= it->bnpacket) {
406 s = splfw();
407 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
408 splx(s);
409 it->stproc = NULL;
410 err = sc->fc->itx_enable(sc->fc, sub);
411 }
412 if (uio->uio_resid >= sizeof(struct fw_isohdr)) {
413 slept = 0;
414 goto isoloop;
415 }
416 return err;
417 }
418#ifdef FWXFERQ_DV
419 if(xferq == NULL && it->flag & FWXFERQ_DV){
420dvloop:
421 if(it->dvproc == NULL){
422 it->dvproc = STAILQ_FIRST(&it->dvfree);
423 if(it->dvproc != NULL){
424 s = splfw();
425 STAILQ_REMOVE_HEAD(&it->dvfree, link);
426 splx(s);
427 it->dvptr = 0;
428 }else if(slept == 0){
429 slept = 1;
430 err = sc->fc->itx_enable(sc->fc, sub);
431 if(err){
432 return err;
433 }
434 err = tsleep(it, FWPRI, "fw_write", hz);
435 if(err){
436 return err;
437 }
438 goto dvloop;
439 }else{
440 err = EIO;
441 return err;
442 }
443 }
444#if 0 /* What's this for? (it->dvptr? overwritten by the following uiomove)*/
445 fp = (struct fw_pkt *)(it->dvproc->buf + it->queued * it->psize);
446 fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t));
447#endif
448 err = uiomove(it->dvproc->buf + it->dvptr,
449 uio->uio_resid, uio);
450 it->dvptr += it->psize;
451 if(err){
452 return err;
453 }
454 if(it->dvptr >= it->psize * it->dvpacket){
455 s = splfw();
456 STAILQ_INSERT_TAIL(&it->dvvalid, it->dvproc, link);
457 splx(s);
458 it->dvproc = NULL;
459 err = fw_tbuf_update(sc->fc, sub, 0);
460 if(err){
461 return err;
462 }
463 err = sc->fc->itx_enable(sc->fc, sub);
464 }
465 return err;
466 }
467#endif
468 if(xferq != NULL){
469 xfer = fw_xfer_alloc(M_FWXFER);
470 if(xfer == NULL){
471 err = ENOMEM;
472 return err;
473 }
474 xfer->send.buf = malloc(uio->uio_resid, M_FW, M_NOWAIT);
475 if(xfer->send.buf == NULL){
476 fw_xfer_free( xfer);
477 err = ENOBUFS;
478 return err;
479 }
480 xfer->dst = ntohs(fp->mode.hdr.dst);
481#if 0
482 switch(fp->mode.common.tcode){
483 case FWTCODE_WREQQ:
484 case FWTCODE_WREQB:
485 if((tl = fw_get_tlabel(fc, xfer)) == -1 ){
486 fw_xfer_free( xfer);
487 err = EAGAIN;
488 return err;
489 }
490 fp->mode.hdr.tlrt = tl << 2;
491 default:
492 break;
493 }
494
495 xfer->tl = fp->mode.hdr.tlrt >> 2;
496 xfer->tcode = fp->mode.common.tcode;
497 xfer->fc = fc;
498 xfer->q = xferq;
499 xfer->act_type = FWACT_XFER;
500 xfer->retry_req = fw_asybusy;
501#endif
502 xfer->send.len = uio->uio_resid;
503 xfer->send.off = 0;
504 xfer->spd = 0;/* XXX: how to setup it */
505 xfer->act.hand = fw_asy_callback;
506
507 err = uiomove(xfer->send.buf, uio->uio_resid, uio);
508 if(err){
509 fw_xfer_free( xfer);
510 return err;
511 }
512#if 0
513 fw_asystart(xfer);
514#else
515 fw_asyreq(fc, -1, xfer);
516#endif
517 err = tsleep(xfer, FWPRI, "fw_write", hz);
518 if(xfer->resp == EBUSY)
519 return EBUSY;
520 fw_xfer_free( xfer);
521 return err;
522 }
523 return EINVAL;
524}
525
526/*
527 * ioctl support.
528 */
529int
530fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
531{
532 struct firewire_softc *sc;
533 int unit = DEV2UNIT(dev);
534 int sub = DEV2DMACH(dev);
535 int i, len, err = 0;
536 struct fw_device *fwdev;
537 struct fw_bind *fwb;
538 struct fw_xferq *ir, *it;
539 struct fw_xfer *xfer;
540 struct fw_pkt *fp;
541 struct fw_devinfo *devinfo;
542
543 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data;
544 struct fw_asyreq *asyreq = (struct fw_asyreq *)data;
545 struct fw_isochreq *ichreq = (struct fw_isochreq *)data;
546 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data;
547 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data;
548 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data;
549
550 if (DEV_FWMEM(dev))
551 return fwmem_ioctl(dev, cmd, data, flag, td);
552
553 sc = devclass_get_softc(firewire_devclass, unit);
554 if (!data)
555 return(EINVAL);
556
557 switch (cmd) {
558 case FW_STSTREAM:
559 sc->fc->it[sub]->flag &= ~0xff;
560 sc->fc->it[sub]->flag |= (0x3f & ichreq->ch);
561 sc->fc->it[sub]->flag |= ((0x3 & ichreq->tag) << 6);
562 err = 0;
563 break;
564 case FW_GTSTREAM:
565 ichreq->ch = sc->fc->it[sub]->flag & 0x3f;
566 ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3;
567 err = 0;
568 break;
569 case FW_SRSTREAM:
570 sc->fc->ir[sub]->flag &= ~0xff;
571 sc->fc->ir[sub]->flag |= (0x3f & ichreq->ch);
572 sc->fc->ir[sub]->flag |= ((0x3 & ichreq->tag) << 6);
573 err = sc->fc->irx_enable(sc->fc, sub);
574 break;
575 case FW_GRSTREAM:
576 ichreq->ch = sc->fc->ir[sub]->flag & 0x3f;
577 ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3;
578 err = 0;
579 break;
580#ifdef FWXFERQ_DV
581 case FW_SSTDV:
582 ibufreq = (struct fw_isobufreq *)
583 malloc(sizeof(struct fw_isobufreq), M_FW, M_NOWAIT);
584 if(ibufreq == NULL){
585 err = ENOMEM;
586 break;
587 }
588#if DV_PAL
589#define FWDVPACKET 300
590#else
591#define FWDVPACKET 250
592#endif
593#define FWDVPMAX 512
594 ibufreq->rx.nchunk = 8;
595 ibufreq->rx.npacket = 50;
596 ibufreq->rx.psize = FWDVPMAX;
597
598 ibufreq->tx.nchunk = 5;
599 ibufreq->tx.npacket = FWDVPACKET + 30; /* > 320 or 267 */
600 ibufreq->tx.psize = FWDVPMAX;
601
602 err = fw_ioctl(dev, FW_SSTBUF, (caddr_t)ibufreq, flag, td);
603 sc->fc->it[sub]->dvpacket = FWDVPACKET;
604 free(ibufreq, M_FW);
605/* reserve a buffer space */
606#define NDVCHUNK 8
607 sc->fc->it[sub]->dvproc = NULL;
608 sc->fc->it[sub]->dvdma = NULL;
609 sc->fc->it[sub]->flag |= FWXFERQ_DV;
610 /* XXX check malloc failure */
611 sc->fc->it[sub]->dvbuf
612 = (struct fw_dvbuf *)malloc(sizeof(struct fw_dvbuf) * NDVCHUNK, M_FW, M_NOWAIT);
613 STAILQ_INIT(&sc->fc->it[sub]->dvvalid);
614 STAILQ_INIT(&sc->fc->it[sub]->dvfree);
615 for( i = 0 ; i < NDVCHUNK ; i++){
616 /* XXX check malloc failure */
617 sc->fc->it[sub]->dvbuf[i].buf
618 = malloc(FWDVPMAX * sc->fc->it[sub]->dvpacket, M_FW, M_NOWAIT);
619 STAILQ_INSERT_TAIL(&sc->fc->it[sub]->dvfree,
620 &sc->fc->it[sub]->dvbuf[i], link);
621 }
622 break;
623#endif
624 case FW_SSTBUF:
625 ir = sc->fc->ir[sub];
626 it = sc->fc->it[sub];
627
628 if(ir->flag & FWXFERQ_RUNNING || it->flag & FWXFERQ_RUNNING){
629 return(EBUSY);
630 }
631 if((ir->flag & FWXFERQ_EXTBUF) || (it->flag & FWXFERQ_EXTBUF)){
632 return(EBUSY);
633 }
634 if((ibufreq->rx.nchunk *
635 ibufreq->rx.psize * ibufreq->rx.npacket) +
636 (ibufreq->tx.nchunk *
637 ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){
638 return(EINVAL);
639 }
640 if(ibufreq->rx.nchunk > FWSTMAXCHUNK ||
641 ibufreq->tx.nchunk > FWSTMAXCHUNK){
642 return(EINVAL);
643 }
644 ir->bulkxfer
645 = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_FW, 0);
646 if(ir->bulkxfer == NULL){
647 return(ENOMEM);
648 }
649 it->bulkxfer
650 = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_FW, 0);
651 if(it->bulkxfer == NULL){
652 return(ENOMEM);
653 }
654 ir->buf = malloc(
655 ibufreq->rx.nchunk * ibufreq->rx.npacket
656 /* XXX psize must be 2^n and less or
657 equal to PAGE_SIZE */
658 * ((ibufreq->rx.psize + 3) &~3),
659 M_FW, 0);
660 if(ir->buf == NULL){
661 free(ir->bulkxfer, M_FW);
662 free(it->bulkxfer, M_FW);
663 ir->bulkxfer = NULL;
664 it->bulkxfer = NULL;
665 it->buf = NULL;
666 return(ENOMEM);
667 }
668 it->buf = malloc(
669 ibufreq->tx.nchunk * ibufreq->tx.npacket
670 /* XXX psize must be 2^n and less or
671 equal to PAGE_SIZE */
672 * ((ibufreq->tx.psize + 3) &~3),
673 M_FW, 0);
674 if(it->buf == NULL){
675 free(ir->bulkxfer, M_FW);
676 free(it->bulkxfer, M_FW);
677 free(ir->buf, M_FW);
678 ir->bulkxfer = NULL;
679 it->bulkxfer = NULL;
680 it->buf = NULL;
681 return(ENOMEM);
682 }
683
684 ir->bnchunk = ibufreq->rx.nchunk;
685 ir->bnpacket = ibufreq->rx.npacket;
686 ir->psize = (ibufreq->rx.psize + 3) & ~3;
687 ir->queued = 0;
688
689 it->bnchunk = ibufreq->tx.nchunk;
690 it->bnpacket = ibufreq->tx.npacket;
691 it->psize = (ibufreq->tx.psize + 3) & ~3;
692 it->queued = 0;
693
694#ifdef FWXFERQ_DV
695 it->dvdbc = 0;
696 it->dvdiff = 0;
697 it->dvsync = 0;
698 it->dvoffset = 0;
699#endif
700
701 STAILQ_INIT(&ir->stvalid);
702 STAILQ_INIT(&ir->stfree);
703 STAILQ_INIT(&ir->stdma);
704 ir->stproc = NULL;
705
706 STAILQ_INIT(&it->stvalid);
707 STAILQ_INIT(&it->stfree);
708 STAILQ_INIT(&it->stdma);
709 it->stproc = NULL;
710
711 for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){
712 ir->bulkxfer[i].buf =
713 ir->buf +
714 i * sc->fc->ir[sub]->bnpacket *
715 sc->fc->ir[sub]->psize;
716 STAILQ_INSERT_TAIL(&ir->stfree,
717 &ir->bulkxfer[i], link);
718 ir->bulkxfer[i].npacket = ir->bnpacket;
719 }
720 for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){
721 it->bulkxfer[i].buf =
722 it->buf +
723 i * sc->fc->it[sub]->bnpacket *
724 sc->fc->it[sub]->psize;
725 STAILQ_INSERT_TAIL(&it->stfree,
726 &it->bulkxfer[i], link);
727 it->bulkxfer[i].npacket = it->bnpacket;
728 }
729 ir->flag &= ~FWXFERQ_MODEMASK;
730 ir->flag |= FWXFERQ_STREAM;
731 ir->flag |= FWXFERQ_EXTBUF;
732
733 it->flag &= ~FWXFERQ_MODEMASK;
734 it->flag |= FWXFERQ_STREAM;
735 it->flag |= FWXFERQ_EXTBUF;
736 err = 0;
737 break;
738 case FW_GSTBUF:
739 ibufreq->rx.nchunk = sc->fc->ir[sub]->bnchunk;
740 ibufreq->rx.npacket = sc->fc->ir[sub]->bnpacket;
741 ibufreq->rx.psize = sc->fc->ir[sub]->psize;
742
743 ibufreq->tx.nchunk = sc->fc->it[sub]->bnchunk;
744 ibufreq->tx.npacket = sc->fc->it[sub]->bnpacket;
745 ibufreq->tx.psize = sc->fc->it[sub]->psize;
746 break;
747 case FW_ASYREQ:
748 xfer = fw_xfer_alloc(M_FWXFER);
749 if(xfer == NULL){
750 err = ENOMEM;
751 return err;
752 }
753 fp = &asyreq->pkt;
754 switch (asyreq->req.type) {
755 case FWASREQNODE:
756 xfer->dst = ntohs(fp->mode.hdr.dst);
757 break;
758 case FWASREQEUI:
759 fwdev = fw_noderesolve_eui64(sc->fc,
760 &asyreq->req.dst.eui);
761 if (fwdev == NULL) {
762 device_printf(sc->fc->bdev,
763 "cannot find node\n");
764 err = EINVAL;
765 goto error;
766 }
767 xfer->dst = fwdev->dst;
768 fp->mode.hdr.dst = htons(FWLOCALBUS | xfer->dst);
769 break;
770 case FWASRESTL:
771 /* XXX what's this? */
772 break;
773 case FWASREQSTREAM:
774 /* nothing to do */
775 break;
776 }
777 xfer->spd = asyreq->req.sped;
778 xfer->send.len = asyreq->req.len;
779 xfer->send.buf = malloc(xfer->send.len, M_FW, M_NOWAIT);
780 if(xfer->send.buf == NULL){
781 return ENOMEM;
782 }
783 xfer->send.off = 0;
784 bcopy(fp, xfer->send.buf, xfer->send.len);
785 xfer->act.hand = fw_asy_callback;
786 err = fw_asyreq(sc->fc, sub, xfer);
787 if(err){
788 fw_xfer_free( xfer);
789 return err;
790 }
791 err = tsleep(xfer, FWPRI, "asyreq", hz);
792 if(err == 0){
793 if(asyreq->req.len >= xfer->recv.len){
794 asyreq->req.len = xfer->recv.len;
795 }else{
796 err = EINVAL;
797 }
798 bcopy(xfer->recv.buf + xfer->recv.off, fp, asyreq->req.len);
799 }
800error:
801 fw_xfer_free( xfer);
802 break;
803 case FW_IBUSRST:
804 sc->fc->ibr(sc->fc);
805 break;
806 case FW_CBINDADDR:
807 fwb = fw_bindlookup(sc->fc,
808 bindreq->start.hi, bindreq->start.lo);
809 if(fwb == NULL){
810 err = EINVAL;
811 break;
812 }
813 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
814 STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist);
815 free(fwb, M_FW);
816 break;
817 case FW_SBINDADDR:
818 if(bindreq->len <= 0 ){
819 err = EINVAL;
820 break;
821 }
822 if(bindreq->start.hi > 0xffff ){
823 err = EINVAL;
824 break;
825 }
826 fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT);
827 if(fwb == NULL){
828 err = ENOMEM;
829 break;
830 }
831 fwb->start_hi = bindreq->start.hi;
832 fwb->start_lo = bindreq->start.lo;
833 fwb->addrlen = bindreq->len;
834
835 xfer = fw_xfer_alloc(M_FWXFER);
836 if(xfer == NULL){
837 err = ENOMEM;
838 return err;
839 }
840 xfer->act_type = FWACT_CH;
841 xfer->sub = sub;
842 xfer->fc = sc->fc;
843
844 fwb->xfer = xfer;
845 err = fw_bindadd(sc->fc, fwb);
846 break;
847 case FW_GDEVLST:
848 i = len = 1;
849 /* myself */
850 devinfo = &fwdevlst->dev[0];
851 devinfo->dst = sc->fc->nodeid;
852 devinfo->status = 0; /* XXX */
853 devinfo->eui.hi = sc->fc->eui.hi;
854 devinfo->eui.lo = sc->fc->eui.lo;
855 STAILQ_FOREACH(fwdev, &sc->fc->devices, link) {
856 if(len < FW_MAX_DEVLST){
857 devinfo = &fwdevlst->dev[len++];
858 devinfo->dst = fwdev->dst;
859 devinfo->status =
860 (fwdev->status == FWDEVINVAL)?0:1;
861 devinfo->eui.hi = fwdev->eui.hi;
862 devinfo->eui.lo = fwdev->eui.lo;
863 }
864 i++;
865 }
866 fwdevlst->n = i;
867 fwdevlst->info_len = len;
868 break;
869 case FW_GTPMAP:
870 bcopy(sc->fc->topology_map, data,
871 (sc->fc->topology_map->crc_len + 1) * 4);
872 break;
873 case FW_GCROM:
874 STAILQ_FOREACH(fwdev, &sc->fc->devices, link)
875 if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui))
876 break;
877 if (fwdev == NULL) {
878 err = FWNODE_INVAL;
879 break;
880 }
881#if 0
882 if (fwdev->csrrom[0] >> 24 == 1)
883 len = 4;
884 else
885 len = (1 + ((fwdev->csrrom[0] >> 16) & 0xff)) * 4;
886#else
887 if (fwdev->rommax < CSRROMOFF)
888 len = 0;
889 else
890 len = fwdev->rommax - CSRROMOFF + 4;
891#endif
892 if (crom_buf->len < len)
893 len = crom_buf->len;
894 else
895 crom_buf->len = len;
896 err = copyout(&fwdev->csrrom[0], crom_buf->ptr, len);
897 break;
898 default:
899 sc->fc->ioctl (dev, cmd, data, flag, td);
900 break;
901 }
902 return err;
903}
904int
905fw_poll(dev_t dev, int events, fw_proc *td)
906{
907 int revents;
908 int tmp;
909 int unit = DEV2UNIT(dev);
910 int sub = DEV2DMACH(dev);
911 struct firewire_softc *sc;
912
913 if (DEV_FWMEM(dev))
914 return fwmem_poll(dev, events, td);
915
916 sc = devclass_get_softc(firewire_devclass, unit);
917 revents = 0;
918 tmp = POLLIN | POLLRDNORM;
919 if (events & tmp) {
920 if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL)
921 revents |= tmp;
922 else
923 selrecord(td, &sc->fc->ir[sub]->rsel);
924 }
925 tmp = POLLOUT | POLLWRNORM;
926 if (events & tmp) {
927 /* XXX should be fixed */
928 revents |= tmp;
929 }
930
931 return revents;
932}
933
934static int
935#if __FreeBSD_version < 500000
936fw_mmap (dev_t dev, vm_offset_t offset, int nproto)
937#else
938fw_mmap (dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nproto)
939#endif
940{
941 struct firewire_softc *fc;
942 int unit = DEV2UNIT(dev);
943
944 if (DEV_FWMEM(dev))
945#if __FreeBSD_version < 500000
946 return fwmem_mmap(dev, offset, nproto);
947#else
948 return fwmem_mmap(dev, offset, paddr, nproto);
949#endif
950
951 fc = devclass_get_softc(firewire_devclass, unit);
952
953 return EINVAL;
954}