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