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