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