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