xref: /freebsd/sys/dev/firewire/fwdev.c (revision 17faeefca6ed8711eba311873ba918eb1df61f9a)
117821895SHidetoshi Shimokawa /*
217821895SHidetoshi Shimokawa  * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
317821895SHidetoshi Shimokawa  * All rights reserved.
417821895SHidetoshi Shimokawa  *
517821895SHidetoshi Shimokawa  * Redistribution and use in source and binary forms, with or without
617821895SHidetoshi Shimokawa  * modification, are permitted provided that the following conditions
717821895SHidetoshi Shimokawa  * are met:
817821895SHidetoshi Shimokawa  * 1. Redistributions of source code must retain the above copyright
917821895SHidetoshi Shimokawa  *    notice, this list of conditions and the following disclaimer.
1017821895SHidetoshi Shimokawa  * 2. Redistributions in binary form must reproduce the above copyright
1117821895SHidetoshi Shimokawa  *    notice, this list of conditions and the following disclaimer in the
1217821895SHidetoshi Shimokawa  *    documentation and/or other materials provided with the distribution.
1317821895SHidetoshi Shimokawa  * 3. All advertising materials mentioning features or use of this software
1417821895SHidetoshi Shimokawa  *    must display the acknowledgement as bellow:
1517821895SHidetoshi Shimokawa  *
1617821895SHidetoshi Shimokawa  *    This product includes software developed by K. Kobayashi and H. Shimokawa
1717821895SHidetoshi Shimokawa  *
1817821895SHidetoshi Shimokawa  * 4. The name of the author may not be used to endorse or promote products
1917821895SHidetoshi Shimokawa  *    derived from this software without specific prior written permission.
2017821895SHidetoshi Shimokawa  *
2117821895SHidetoshi Shimokawa  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2217821895SHidetoshi Shimokawa  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2317821895SHidetoshi Shimokawa  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2417821895SHidetoshi Shimokawa  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2517821895SHidetoshi Shimokawa  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2617821895SHidetoshi Shimokawa  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2717821895SHidetoshi Shimokawa  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2817821895SHidetoshi Shimokawa  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2917821895SHidetoshi Shimokawa  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3017821895SHidetoshi Shimokawa  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3117821895SHidetoshi Shimokawa  * POSSIBILITY OF SUCH DAMAGE.
3217821895SHidetoshi Shimokawa  *
3317821895SHidetoshi Shimokawa  * $FreeBSD$
3417821895SHidetoshi Shimokawa  *
3517821895SHidetoshi Shimokawa  */
3617821895SHidetoshi Shimokawa 
3717821895SHidetoshi Shimokawa #include <sys/param.h>
3817821895SHidetoshi Shimokawa #include <sys/systm.h>
3917821895SHidetoshi Shimokawa #include <sys/types.h>
4017821895SHidetoshi Shimokawa #include <sys/mbuf.h>
4117821895SHidetoshi Shimokawa 
4217821895SHidetoshi Shimokawa #include <sys/kernel.h>
4317821895SHidetoshi Shimokawa #include <sys/malloc.h>
4417821895SHidetoshi Shimokawa #include <sys/conf.h>
4517821895SHidetoshi Shimokawa #include <sys/uio.h>
4617821895SHidetoshi Shimokawa #include <sys/poll.h>
4717821895SHidetoshi Shimokawa 
4817821895SHidetoshi Shimokawa #include <sys/bus.h>
4917821895SHidetoshi Shimokawa 
5017821895SHidetoshi Shimokawa #include <sys/ioccom.h>
5117821895SHidetoshi Shimokawa 
5217821895SHidetoshi Shimokawa #include <dev/firewire/firewire.h>
5317821895SHidetoshi Shimokawa #include <dev/firewire/firewirereg.h>
5417821895SHidetoshi Shimokawa #include <dev/firewire/fwmem.h>
5517821895SHidetoshi Shimokawa 
5617821895SHidetoshi Shimokawa #define CDEV_MAJOR 127
5717821895SHidetoshi Shimokawa #define	FWNODE_INVAL 0xffff
5817821895SHidetoshi Shimokawa 
5917821895SHidetoshi Shimokawa static	d_open_t	fw_open;
6017821895SHidetoshi Shimokawa static	d_close_t	fw_close;
6117821895SHidetoshi Shimokawa static	d_ioctl_t	fw_ioctl;
6217821895SHidetoshi Shimokawa static	d_poll_t	fw_poll;
6317821895SHidetoshi Shimokawa static	d_read_t	fw_read;	/* for Isochronous packet */
6417821895SHidetoshi Shimokawa static	d_write_t	fw_write;
6517821895SHidetoshi Shimokawa static	d_mmap_t	fw_mmap;
6617821895SHidetoshi Shimokawa 
6717821895SHidetoshi Shimokawa struct cdevsw firewire_cdevsw =
6817821895SHidetoshi Shimokawa {
6917821895SHidetoshi Shimokawa 	fw_open, fw_close, fw_read, fw_write, fw_ioctl,
7017821895SHidetoshi Shimokawa 	fw_poll, fw_mmap, nostrategy, "fw", CDEV_MAJOR, nodump, nopsize, D_MEM
7117821895SHidetoshi Shimokawa };
7217821895SHidetoshi Shimokawa 
7317821895SHidetoshi Shimokawa static int
7417821895SHidetoshi Shimokawa fw_open (dev_t dev, int flags, int fmt, fw_proc *td)
7517821895SHidetoshi Shimokawa {
7617821895SHidetoshi Shimokawa 	struct firewire_softc *sc;
7717821895SHidetoshi Shimokawa 	int unit = DEV2UNIT(dev);
7817821895SHidetoshi Shimokawa 	int sub = DEV2DMACH(dev);
7917821895SHidetoshi Shimokawa 
8017821895SHidetoshi Shimokawa 	int err = 0;
8117821895SHidetoshi Shimokawa 
8217821895SHidetoshi Shimokawa 	if (DEV_FWMEM(dev))
8317821895SHidetoshi Shimokawa 		return fwmem_open(dev, flags, fmt, td);
8417821895SHidetoshi Shimokawa 
8517821895SHidetoshi Shimokawa 	sc = devclass_get_softc(firewire_devclass, unit);
8617821895SHidetoshi Shimokawa 	if(sc->fc->ir[sub]->flag & FWXFERQ_OPEN){
8717821895SHidetoshi Shimokawa 		err = EBUSY;
8817821895SHidetoshi Shimokawa 		return err;
8917821895SHidetoshi Shimokawa 	}
9017821895SHidetoshi Shimokawa 	if(sc->fc->it[sub]->flag & FWXFERQ_OPEN){
9117821895SHidetoshi Shimokawa 		err = EBUSY;
9217821895SHidetoshi Shimokawa 		return err;
9317821895SHidetoshi Shimokawa 	}
9417821895SHidetoshi Shimokawa 	if(sc->fc->ir[sub]->flag & FWXFERQ_MODEMASK){
9517821895SHidetoshi Shimokawa 		err = EBUSY;
9617821895SHidetoshi Shimokawa 		return err;
9717821895SHidetoshi Shimokawa 	}
9817821895SHidetoshi Shimokawa /* Default is per packet mode */
9917821895SHidetoshi Shimokawa 	sc->fc->ir[sub]->flag |= FWXFERQ_OPEN;
10017821895SHidetoshi Shimokawa 	sc->fc->it[sub]->flag |= FWXFERQ_OPEN;
10117821895SHidetoshi Shimokawa 	sc->fc->ir[sub]->flag |= FWXFERQ_PACKET;
10217821895SHidetoshi Shimokawa 	return err;
10317821895SHidetoshi Shimokawa }
10417821895SHidetoshi Shimokawa 
10517821895SHidetoshi Shimokawa static int
10617821895SHidetoshi Shimokawa fw_close (dev_t dev, int flags, int fmt, fw_proc *td)
10717821895SHidetoshi Shimokawa {
10817821895SHidetoshi Shimokawa 	struct firewire_softc *sc;
10917821895SHidetoshi Shimokawa 	int unit = DEV2UNIT(dev);
11017821895SHidetoshi Shimokawa 	int sub = DEV2DMACH(dev);
11117821895SHidetoshi Shimokawa 	struct fw_xfer *xfer;
11217821895SHidetoshi Shimokawa 	struct fw_dvbuf *dvbuf;
11317821895SHidetoshi Shimokawa 	struct fw_bind *fwb;
11417821895SHidetoshi Shimokawa 	int err = 0;
11517821895SHidetoshi Shimokawa 
11617821895SHidetoshi Shimokawa 	if (DEV_FWMEM(dev))
11717821895SHidetoshi Shimokawa 		return fwmem_close(dev, flags, fmt, td);
11817821895SHidetoshi Shimokawa 
11917821895SHidetoshi Shimokawa 	sc = devclass_get_softc(firewire_devclass, unit);
12017821895SHidetoshi Shimokawa 	if(!(sc->fc->ir[sub]->flag & FWXFERQ_OPEN)){
12117821895SHidetoshi Shimokawa 		err = EINVAL;
12217821895SHidetoshi Shimokawa 		return err;
12317821895SHidetoshi Shimokawa 	}
12417821895SHidetoshi Shimokawa 	sc->fc->ir[sub]->flag &= ~FWXFERQ_OPEN;
12517821895SHidetoshi Shimokawa 	if(!(sc->fc->it[sub]->flag & FWXFERQ_OPEN)){
12617821895SHidetoshi Shimokawa 		err = EINVAL;
12717821895SHidetoshi Shimokawa 		return err;
12817821895SHidetoshi Shimokawa 	}
12917821895SHidetoshi Shimokawa 	sc->fc->it[sub]->flag &= ~FWXFERQ_OPEN;
13017821895SHidetoshi Shimokawa 
13117821895SHidetoshi Shimokawa 	if(sc->fc->ir[sub]->flag & FWXFERQ_RUNNING){
13217821895SHidetoshi Shimokawa 		sc->fc->irx_disable(sc->fc, sub);
13317821895SHidetoshi Shimokawa 	}
13417821895SHidetoshi Shimokawa 	if(sc->fc->it[sub]->flag & FWXFERQ_RUNNING){
13517821895SHidetoshi Shimokawa 		sc->fc->it[sub]->flag &= ~FWXFERQ_RUNNING;
13617821895SHidetoshi Shimokawa 		sc->fc->itx_disable(sc->fc, sub);
13717821895SHidetoshi Shimokawa 	}
13817821895SHidetoshi Shimokawa 	if(sc->fc->it[sub]->flag & FWXFERQ_DV){
13917821895SHidetoshi Shimokawa 		if((dvbuf = sc->fc->it[sub]->dvproc) != NULL){
14017821895SHidetoshi Shimokawa 			free(dvbuf->buf, M_DEVBUF);
14117821895SHidetoshi Shimokawa 			sc->fc->it[sub]->dvproc = NULL;
14217821895SHidetoshi Shimokawa 		}
14317821895SHidetoshi Shimokawa 		if((dvbuf = sc->fc->it[sub]->dvdma) != NULL){
14417821895SHidetoshi Shimokawa 			free(dvbuf->buf, M_DEVBUF);
14517821895SHidetoshi Shimokawa 			sc->fc->it[sub]->dvdma = NULL;
14617821895SHidetoshi Shimokawa 		}
14717821895SHidetoshi Shimokawa 		while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvvalid)) != NULL){
14817821895SHidetoshi Shimokawa 			STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvvalid, link);
14917821895SHidetoshi Shimokawa 			free(dvbuf->buf, M_DEVBUF);
15017821895SHidetoshi Shimokawa 		}
15117821895SHidetoshi Shimokawa 		while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvfree)) != NULL){
15217821895SHidetoshi Shimokawa 			STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvfree, link);
15317821895SHidetoshi Shimokawa 			free(dvbuf->buf, M_DEVBUF);
15417821895SHidetoshi Shimokawa 		}
15517821895SHidetoshi Shimokawa 		free(sc->fc->it[sub]->dvbuf, M_DEVBUF);
15617821895SHidetoshi Shimokawa 		sc->fc->it[sub]->dvbuf = NULL;
15717821895SHidetoshi Shimokawa 	}
15817821895SHidetoshi Shimokawa 	if(sc->fc->ir[sub]->flag & FWXFERQ_EXTBUF){
15917821895SHidetoshi Shimokawa 		free(sc->fc->ir[sub]->buf, M_DEVBUF);
16017821895SHidetoshi Shimokawa 		sc->fc->ir[sub]->buf = NULL;
16117821895SHidetoshi Shimokawa 		free(sc->fc->ir[sub]->bulkxfer, M_DEVBUF);
16217821895SHidetoshi Shimokawa 		sc->fc->ir[sub]->bulkxfer = NULL;
16317821895SHidetoshi Shimokawa 		sc->fc->ir[sub]->flag &= ~FWXFERQ_EXTBUF;
16417821895SHidetoshi Shimokawa 		sc->fc->ir[sub]->psize = FWPMAX_S400;
16517821895SHidetoshi Shimokawa 		sc->fc->ir[sub]->maxq = FWMAXQUEUE;
16617821895SHidetoshi Shimokawa 	}
16717821895SHidetoshi Shimokawa 	if(sc->fc->it[sub]->flag & FWXFERQ_EXTBUF){
16817821895SHidetoshi Shimokawa 		free(sc->fc->it[sub]->buf, M_DEVBUF);
16917821895SHidetoshi Shimokawa 		sc->fc->it[sub]->buf = NULL;
17017821895SHidetoshi Shimokawa 		free(sc->fc->it[sub]->bulkxfer, M_DEVBUF);
17117821895SHidetoshi Shimokawa 		sc->fc->it[sub]->bulkxfer = NULL;
17217821895SHidetoshi Shimokawa 		sc->fc->it[sub]->dvbuf = NULL;
17317821895SHidetoshi Shimokawa 		sc->fc->it[sub]->flag &= ~FWXFERQ_EXTBUF;
17417821895SHidetoshi Shimokawa 		sc->fc->it[sub]->psize = FWPMAX_S400;
17517821895SHidetoshi Shimokawa 		sc->fc->it[sub]->maxq = FWMAXQUEUE;
17617821895SHidetoshi Shimokawa 	}
17717821895SHidetoshi Shimokawa 	for(xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q);
17817821895SHidetoshi Shimokawa 		xfer != NULL; xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q)){
17917821895SHidetoshi Shimokawa 		sc->fc->ir[sub]->queued--;
18017821895SHidetoshi Shimokawa 		STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->q, link);
18117821895SHidetoshi Shimokawa 
18217821895SHidetoshi Shimokawa 		xfer->resp = 0;
18317821895SHidetoshi Shimokawa 		switch(xfer->act_type){
18417821895SHidetoshi Shimokawa 		case FWACT_XFER:
18517821895SHidetoshi Shimokawa 			fw_xfer_done(xfer);
18617821895SHidetoshi Shimokawa 			break;
18717821895SHidetoshi Shimokawa 		default:
18817821895SHidetoshi Shimokawa 			break;
18917821895SHidetoshi Shimokawa 		}
19017821895SHidetoshi Shimokawa 		fw_xfer_free(xfer);
19117821895SHidetoshi Shimokawa 	}
19217821895SHidetoshi Shimokawa 	for(fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds); fwb != NULL;
19317821895SHidetoshi Shimokawa 		fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds)){
19417821895SHidetoshi Shimokawa 		STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
19517821895SHidetoshi Shimokawa 		STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->binds, chlist);
19617821895SHidetoshi Shimokawa 		free(fwb, M_DEVBUF);
19717821895SHidetoshi Shimokawa 	}
19817821895SHidetoshi Shimokawa 	sc->fc->ir[sub]->flag &= ~FWXFERQ_MODEMASK;
19917821895SHidetoshi Shimokawa 	sc->fc->it[sub]->flag &= ~FWXFERQ_MODEMASK;
20017821895SHidetoshi Shimokawa 	return err;
20117821895SHidetoshi Shimokawa }
20217821895SHidetoshi Shimokawa 
20317821895SHidetoshi Shimokawa /*
20417821895SHidetoshi Shimokawa  * read request.
20517821895SHidetoshi Shimokawa  */
20617821895SHidetoshi Shimokawa static int
20717821895SHidetoshi Shimokawa fw_read (dev_t dev, struct uio *uio, int ioflag)
20817821895SHidetoshi Shimokawa {
20917821895SHidetoshi Shimokawa 	struct firewire_softc *sc;
21017821895SHidetoshi Shimokawa 	struct fw_xferq *ir;
21117821895SHidetoshi Shimokawa 	struct fw_xfer *xfer;
21217821895SHidetoshi Shimokawa 	int err = 0, s, slept = 0;
21317821895SHidetoshi Shimokawa 	int unit = DEV2UNIT(dev);
21417821895SHidetoshi Shimokawa 	int sub = DEV2DMACH(dev);
21517821895SHidetoshi Shimokawa 	struct fw_pkt *fp;
21617821895SHidetoshi Shimokawa 
21717821895SHidetoshi Shimokawa 	if (DEV_FWMEM(dev))
21817821895SHidetoshi Shimokawa 		return fwmem_read(dev, uio, ioflag);
21917821895SHidetoshi Shimokawa 
22017821895SHidetoshi Shimokawa 	sc = devclass_get_softc(firewire_devclass, unit);
22117821895SHidetoshi Shimokawa 
22217821895SHidetoshi Shimokawa 	ir = sc->fc->ir[sub];
22317821895SHidetoshi Shimokawa 
22417821895SHidetoshi Shimokawa 	if(ir->flag & FWXFERQ_PACKET){
22517821895SHidetoshi Shimokawa 		ir->stproc = NULL;
22617821895SHidetoshi Shimokawa 	}
22717821895SHidetoshi Shimokawa readloop:
22817821895SHidetoshi Shimokawa 	xfer = STAILQ_FIRST(&ir->q);
22917821895SHidetoshi Shimokawa 	if(!(ir->flag & FWXFERQ_PACKET) && ir->stproc == NULL){
23017821895SHidetoshi Shimokawa 		ir->stproc = STAILQ_FIRST(&ir->stvalid);
23117821895SHidetoshi Shimokawa 		if(ir->stproc != NULL){
23217821895SHidetoshi Shimokawa 			s = splfw();
23317821895SHidetoshi Shimokawa 			STAILQ_REMOVE_HEAD(&ir->stvalid, link);
23417821895SHidetoshi Shimokawa 			splx(s);
23517821895SHidetoshi Shimokawa 			ir->queued = 0;
23617821895SHidetoshi Shimokawa 		}
23717821895SHidetoshi Shimokawa 	}
23817821895SHidetoshi Shimokawa 
23917821895SHidetoshi Shimokawa 	if(xfer == NULL && ir->stproc == NULL){
24017821895SHidetoshi Shimokawa 		if(slept == 0){
24117821895SHidetoshi Shimokawa 			slept = 1;
24217821895SHidetoshi Shimokawa 			if(!(ir->flag & FWXFERQ_RUNNING)
24317821895SHidetoshi Shimokawa 				&& (ir->flag & FWXFERQ_PACKET)){
24417821895SHidetoshi Shimokawa 				err = sc->fc->irx_enable(sc->fc, sub);
24517821895SHidetoshi Shimokawa 			}
24617821895SHidetoshi Shimokawa 			if(err){
24717821895SHidetoshi Shimokawa 				return err;
24817821895SHidetoshi Shimokawa 			}
24917821895SHidetoshi Shimokawa 			ir->flag |= FWXFERQ_WAKEUP;
25017821895SHidetoshi Shimokawa 			err = tsleep((caddr_t)ir, FWPRI, "fw_read", hz);
25117821895SHidetoshi Shimokawa 			if(err){
25217821895SHidetoshi Shimokawa 				ir->flag &= ~FWXFERQ_WAKEUP;
25317821895SHidetoshi Shimokawa 				return err;
25417821895SHidetoshi Shimokawa 			}
25517821895SHidetoshi Shimokawa 			goto readloop;
25617821895SHidetoshi Shimokawa 		}else{
25717821895SHidetoshi Shimokawa 			err = EIO;
25817821895SHidetoshi Shimokawa 			return err;
25917821895SHidetoshi Shimokawa 		}
26017821895SHidetoshi Shimokawa 	}else if(xfer != NULL){
26117821895SHidetoshi Shimokawa 		s = splfw();
26217821895SHidetoshi Shimokawa 		ir->queued --;
26317821895SHidetoshi Shimokawa 		STAILQ_REMOVE_HEAD(&ir->q, link);
26417821895SHidetoshi Shimokawa 		splx(s);
26517821895SHidetoshi Shimokawa 		fp = (struct fw_pkt *)(xfer->recv.buf + xfer->recv.off);
26617821895SHidetoshi Shimokawa 		if(sc->fc->irx_post != NULL)
26717821895SHidetoshi Shimokawa 			sc->fc->irx_post(sc->fc, fp->mode.ld);
26817821895SHidetoshi Shimokawa 		err = uiomove(xfer->recv.buf + xfer->recv.off, xfer->recv.len, uio);
26917821895SHidetoshi Shimokawa 		fw_xfer_free( xfer);
27017821895SHidetoshi Shimokawa 	}else if(ir->stproc != NULL){
27117821895SHidetoshi Shimokawa 		fp = (struct fw_pkt *)(ir->stproc->buf + ir->queued * ir->psize);
27217821895SHidetoshi Shimokawa 		if(sc->fc->irx_post != NULL)
27317821895SHidetoshi Shimokawa 			sc->fc->irx_post(sc->fc, fp->mode.ld);
27417821895SHidetoshi Shimokawa 		if(ntohs(fp->mode.stream.len) == 0){
27517821895SHidetoshi Shimokawa 			err = EIO;
27617821895SHidetoshi Shimokawa 			return err;
27717821895SHidetoshi Shimokawa 		}
27817821895SHidetoshi Shimokawa 		err = uiomove((caddr_t)fp, ntohs(fp->mode.stream.len) + sizeof(u_int32_t), uio);
27917821895SHidetoshi Shimokawa 		fp->mode.stream.len = 0;
28017821895SHidetoshi Shimokawa 		ir->queued ++;
28117821895SHidetoshi Shimokawa 		if(ir->queued >= ir->bnpacket){
28217821895SHidetoshi Shimokawa 			s = splfw();
28317821895SHidetoshi Shimokawa 			ir->stproc->flag = 0;
28417821895SHidetoshi Shimokawa 			STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link);
28517821895SHidetoshi Shimokawa 			splx(s);
28617821895SHidetoshi Shimokawa 			ir->stproc = NULL;
28717821895SHidetoshi Shimokawa 		}
28817821895SHidetoshi Shimokawa 	}
28917821895SHidetoshi Shimokawa #if 0
29017821895SHidetoshi Shimokawa 	if(STAILQ_FIRST(&ir->q) == NULL &&
29117821895SHidetoshi Shimokawa 		(ir->flag & FWXFERQ_RUNNING) && (ir->flag & FWXFERQ_PACKET)){
29217821895SHidetoshi Shimokawa 		err = sc->fc->irx_enable(sc->fc, sub);
29317821895SHidetoshi Shimokawa 	}
29417821895SHidetoshi Shimokawa #endif
29517821895SHidetoshi Shimokawa #if 0
29617821895SHidetoshi Shimokawa 	if(STAILQ_FIRST(&ir->stvalid) == NULL &&
29717821895SHidetoshi Shimokawa 		(ir->flag & FWXFERQ_RUNNING) && !(ir->flag & FWXFERQ_PACKET)){
29817821895SHidetoshi Shimokawa 		err = sc->fc->irx_enable(sc->fc, sub);
29917821895SHidetoshi Shimokawa 	}
30017821895SHidetoshi Shimokawa #endif
30117821895SHidetoshi Shimokawa 	return err;
30217821895SHidetoshi Shimokawa }
30317821895SHidetoshi Shimokawa 
30417821895SHidetoshi Shimokawa static int
30517821895SHidetoshi Shimokawa fw_write (dev_t dev, struct uio *uio, int ioflag)
30617821895SHidetoshi Shimokawa {
30717821895SHidetoshi Shimokawa 	int err = 0;
30817821895SHidetoshi Shimokawa 	struct firewire_softc *sc;
30917821895SHidetoshi Shimokawa 	int unit = DEV2UNIT(dev);
31017821895SHidetoshi Shimokawa 	int sub = DEV2DMACH(dev);
31117821895SHidetoshi Shimokawa 	int s, slept = 0;
31217821895SHidetoshi Shimokawa 	struct fw_pkt *fp;
31317821895SHidetoshi Shimokawa 	struct fw_xfer *xfer;
31417821895SHidetoshi Shimokawa 	struct fw_xferq *xferq;
31517821895SHidetoshi Shimokawa 	struct firewire_comm *fc;
31617821895SHidetoshi Shimokawa 	struct fw_xferq *it;
31717821895SHidetoshi Shimokawa 
31817821895SHidetoshi Shimokawa 	if (DEV_FWMEM(dev))
31917821895SHidetoshi Shimokawa 		return fwmem_write(dev, uio, ioflag);
32017821895SHidetoshi Shimokawa 
32117821895SHidetoshi Shimokawa 	sc = devclass_get_softc(firewire_devclass, unit);
32217821895SHidetoshi Shimokawa 	fc = sc->fc;
32317821895SHidetoshi Shimokawa 	it = sc->fc->it[sub];
32417821895SHidetoshi Shimokawa 
32517821895SHidetoshi Shimokawa 	fp = (struct fw_pkt *)uio->uio_iov->iov_base;
32617821895SHidetoshi Shimokawa 	switch(fp->mode.common.tcode){
32717821895SHidetoshi Shimokawa 	case FWTCODE_RREQQ:
32817821895SHidetoshi Shimokawa 	case FWTCODE_RREQB:
32917821895SHidetoshi Shimokawa 	case FWTCODE_LREQ:
33017821895SHidetoshi Shimokawa 		err = EINVAL;
33117821895SHidetoshi Shimokawa 		return err;
33217821895SHidetoshi Shimokawa 	case FWTCODE_WREQQ:
33317821895SHidetoshi Shimokawa 	case FWTCODE_WREQB:
33417821895SHidetoshi Shimokawa 		xferq = fc->atq;
33517821895SHidetoshi Shimokawa 		break;
33617821895SHidetoshi Shimokawa 	case FWTCODE_STREAM:
33717821895SHidetoshi Shimokawa 		if(it->flag & FWXFERQ_PACKET){
33817821895SHidetoshi Shimokawa 			xferq = fc->atq;
33917821895SHidetoshi Shimokawa 		}else{
34017821895SHidetoshi Shimokawa 			xferq = NULL;
34117821895SHidetoshi Shimokawa 		}
34217821895SHidetoshi Shimokawa 		break;
34317821895SHidetoshi Shimokawa 	case FWTCODE_WRES:
34417821895SHidetoshi Shimokawa 	case FWTCODE_RRESQ:
34517821895SHidetoshi Shimokawa 	case FWTCODE_RRESB:
34617821895SHidetoshi Shimokawa 	case FWTCODE_LRES:
34717821895SHidetoshi Shimokawa 		xferq = fc->ats;
34817821895SHidetoshi Shimokawa 		break;
34917821895SHidetoshi Shimokawa 	default:
35017821895SHidetoshi Shimokawa 		err = EINVAL;
35117821895SHidetoshi Shimokawa 		return err;
35217821895SHidetoshi Shimokawa 	}
35317821895SHidetoshi Shimokawa 	/* Discard unsent buffered stream packet, when sending Asyrequrst */
35417821895SHidetoshi Shimokawa 	if(xferq != NULL && it->stproc != NULL){
35517821895SHidetoshi Shimokawa 		s = splfw();
35617821895SHidetoshi Shimokawa 		it->stproc->flag = 0;
35717821895SHidetoshi Shimokawa 		STAILQ_INSERT_TAIL(&it->stfree, it->stproc, link);
35817821895SHidetoshi Shimokawa 		splx(s);
35917821895SHidetoshi Shimokawa 		it->stproc = NULL;
36017821895SHidetoshi Shimokawa 	}
36117821895SHidetoshi Shimokawa 	if(xferq == NULL && !(it->flag & FWXFERQ_DV)){
36217821895SHidetoshi Shimokawa isoloop:
36317821895SHidetoshi Shimokawa 		if(it->stproc == NULL){
36417821895SHidetoshi Shimokawa 			it->stproc = STAILQ_FIRST(&it->stfree);
36517821895SHidetoshi Shimokawa 			if(it->stproc != NULL){
36617821895SHidetoshi Shimokawa 				s = splfw();
36717821895SHidetoshi Shimokawa 				STAILQ_REMOVE_HEAD(&it->stfree, link);
36817821895SHidetoshi Shimokawa 				splx(s);
36917821895SHidetoshi Shimokawa 				it->queued = 0;
37017821895SHidetoshi Shimokawa 			}else if(slept == 0){
37117821895SHidetoshi Shimokawa 				slept = 1;
37217821895SHidetoshi Shimokawa 				err = sc->fc->itx_enable(sc->fc, sub);
37317821895SHidetoshi Shimokawa 				if(err){
37417821895SHidetoshi Shimokawa 					return err;
37517821895SHidetoshi Shimokawa 				}
37617821895SHidetoshi Shimokawa 				err = tsleep((caddr_t)it, FWPRI, "fw_write", hz);
37717821895SHidetoshi Shimokawa 				if(err){
37817821895SHidetoshi Shimokawa 					return err;
37917821895SHidetoshi Shimokawa 				}
38017821895SHidetoshi Shimokawa 				goto isoloop;
38117821895SHidetoshi Shimokawa 			}else{
38217821895SHidetoshi Shimokawa 				err = EIO;
38317821895SHidetoshi Shimokawa 				return err;
38417821895SHidetoshi Shimokawa 			}
38517821895SHidetoshi Shimokawa 		}
38617821895SHidetoshi Shimokawa 		fp = (struct fw_pkt *)(it->stproc->buf + it->queued * it->psize);
38717821895SHidetoshi Shimokawa 		fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t));
38817821895SHidetoshi Shimokawa 		err = uiomove(it->stproc->buf + it->queued * it->psize,
38917821895SHidetoshi Shimokawa 							uio->uio_resid, uio);
39017821895SHidetoshi Shimokawa 		it->queued ++;
39117821895SHidetoshi Shimokawa 		if(it->queued >= it->btpacket){
39217821895SHidetoshi Shimokawa 			s = splfw();
39317821895SHidetoshi Shimokawa 			STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
39417821895SHidetoshi Shimokawa 			splx(s);
39517821895SHidetoshi Shimokawa 			it->stproc = NULL;
39617821895SHidetoshi Shimokawa 			fw_tbuf_update(sc->fc, sub, 0);
39717821895SHidetoshi Shimokawa 			err = sc->fc->itx_enable(sc->fc, sub);
39817821895SHidetoshi Shimokawa 		}
39917821895SHidetoshi Shimokawa 		return err;
40017821895SHidetoshi Shimokawa 	} if(xferq == NULL && it->flag & FWXFERQ_DV){
40117821895SHidetoshi Shimokawa dvloop:
40217821895SHidetoshi Shimokawa 		if(it->dvproc == NULL){
40317821895SHidetoshi Shimokawa 			it->dvproc = STAILQ_FIRST(&it->dvfree);
40417821895SHidetoshi Shimokawa 			if(it->dvproc != NULL){
40517821895SHidetoshi Shimokawa 				s = splfw();
40617821895SHidetoshi Shimokawa 				STAILQ_REMOVE_HEAD(&it->dvfree, link);
40717821895SHidetoshi Shimokawa 				splx(s);
40817821895SHidetoshi Shimokawa 				it->dvptr = 0;
40917821895SHidetoshi Shimokawa 			}else if(slept == 0){
41017821895SHidetoshi Shimokawa 				slept = 1;
41117821895SHidetoshi Shimokawa 				err = sc->fc->itx_enable(sc->fc, sub);
41217821895SHidetoshi Shimokawa 				if(err){
41317821895SHidetoshi Shimokawa 					return err;
41417821895SHidetoshi Shimokawa 				}
41517821895SHidetoshi Shimokawa 				err = tsleep((caddr_t)it, FWPRI, "fw_write", hz);
41617821895SHidetoshi Shimokawa 				if(err){
41717821895SHidetoshi Shimokawa 					return err;
41817821895SHidetoshi Shimokawa 				}
41917821895SHidetoshi Shimokawa 				goto dvloop;
42017821895SHidetoshi Shimokawa 			}else{
42117821895SHidetoshi Shimokawa 				err = EIO;
42217821895SHidetoshi Shimokawa 				return err;
42317821895SHidetoshi Shimokawa 			}
42417821895SHidetoshi Shimokawa 		}
42517821895SHidetoshi Shimokawa 		fp = (struct fw_pkt *)(it->dvproc->buf + it->queued * it->psize);
42617821895SHidetoshi Shimokawa 		fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t));
42717821895SHidetoshi Shimokawa 		err = uiomove(it->dvproc->buf + it->dvptr,
42817821895SHidetoshi Shimokawa 							uio->uio_resid, uio);
42917821895SHidetoshi Shimokawa 		it->dvptr += it->psize;
43017821895SHidetoshi Shimokawa 		if(err){
43117821895SHidetoshi Shimokawa 			return err;
43217821895SHidetoshi Shimokawa 		}
43317821895SHidetoshi Shimokawa 		if(it->dvptr >= it->psize * it->dvpacket){
43417821895SHidetoshi Shimokawa 			s = splfw();
43517821895SHidetoshi Shimokawa 			STAILQ_INSERT_TAIL(&it->dvvalid, it->dvproc, link);
43617821895SHidetoshi Shimokawa 			splx(s);
43717821895SHidetoshi Shimokawa 			it->dvproc = NULL;
43817821895SHidetoshi Shimokawa 			err = fw_tbuf_update(sc->fc, sub, 0);
43917821895SHidetoshi Shimokawa 			if(err){
44017821895SHidetoshi Shimokawa 				return err;
44117821895SHidetoshi Shimokawa 			}
44217821895SHidetoshi Shimokawa 			err = sc->fc->itx_enable(sc->fc, sub);
44317821895SHidetoshi Shimokawa 		}
44417821895SHidetoshi Shimokawa 		return err;
44517821895SHidetoshi Shimokawa 	}
44617821895SHidetoshi Shimokawa 	if(xferq != NULL){
44717821895SHidetoshi Shimokawa 		xfer = fw_xfer_alloc();
44817821895SHidetoshi Shimokawa 		if(xfer == NULL){
44917821895SHidetoshi Shimokawa 			err = ENOMEM;
45017821895SHidetoshi Shimokawa 			return err;
45117821895SHidetoshi Shimokawa 		}
45217821895SHidetoshi Shimokawa 		xfer->send.buf = malloc(uio->uio_resid, M_DEVBUF, M_NOWAIT);
45317821895SHidetoshi Shimokawa 		if(xfer->send.buf == NULL){
45417821895SHidetoshi Shimokawa 			fw_xfer_free( xfer);
45517821895SHidetoshi Shimokawa 			err = ENOBUFS;
45617821895SHidetoshi Shimokawa 			return err;
45717821895SHidetoshi Shimokawa 		}
45817821895SHidetoshi Shimokawa 		xfer->dst = ntohs(fp->mode.hdr.dst);
45917821895SHidetoshi Shimokawa #if 0
46017821895SHidetoshi Shimokawa 		switch(fp->mode.common.tcode){
46117821895SHidetoshi Shimokawa 		case FWTCODE_WREQQ:
46217821895SHidetoshi Shimokawa 		case FWTCODE_WREQB:
46317821895SHidetoshi Shimokawa 			if((tl = fw_get_tlabel(fc, xfer)) == -1 ){
46417821895SHidetoshi Shimokawa 				fw_xfer_free( xfer);
46517821895SHidetoshi Shimokawa 				err = EAGAIN;
46617821895SHidetoshi Shimokawa 				return err;
46717821895SHidetoshi Shimokawa 			}
46817821895SHidetoshi Shimokawa 			fp->mode.hdr.tlrt = tl << 2;
46917821895SHidetoshi Shimokawa 		default:
47017821895SHidetoshi Shimokawa 			break;
47117821895SHidetoshi Shimokawa 		}
47217821895SHidetoshi Shimokawa 
47317821895SHidetoshi Shimokawa 		xfer->tl = fp->mode.hdr.tlrt >> 2;
47417821895SHidetoshi Shimokawa 		xfer->tcode = fp->mode.common.tcode;
47517821895SHidetoshi Shimokawa 		xfer->fc = fc;
47617821895SHidetoshi Shimokawa 		xfer->q = xferq;
47717821895SHidetoshi Shimokawa 		xfer->act_type = FWACT_XFER;
47817821895SHidetoshi Shimokawa 		xfer->retry_req = fw_asybusy;
47917821895SHidetoshi Shimokawa #endif
48017821895SHidetoshi Shimokawa 		xfer->send.len = uio->uio_resid;
48117821895SHidetoshi Shimokawa 		xfer->send.off = 0;
48217821895SHidetoshi Shimokawa 		xfer->spd = 0;/* XXX: how to setup it */
48317821895SHidetoshi Shimokawa 		xfer->act.hand = fw_asy_callback;
48417821895SHidetoshi Shimokawa 
48517821895SHidetoshi Shimokawa 		err = uiomove(xfer->send.buf, uio->uio_resid, uio);
48617821895SHidetoshi Shimokawa 		if(err){
48717821895SHidetoshi Shimokawa 			fw_xfer_free( xfer);
48817821895SHidetoshi Shimokawa 			return err;
48917821895SHidetoshi Shimokawa 		}
49017821895SHidetoshi Shimokawa #if 0
49117821895SHidetoshi Shimokawa 		fw_asystart(xfer);
49217821895SHidetoshi Shimokawa #else
49317821895SHidetoshi Shimokawa 		fw_asyreq(fc, -1, xfer);
49417821895SHidetoshi Shimokawa #endif
49517821895SHidetoshi Shimokawa 		err = tsleep((caddr_t)xfer, FWPRI, "fw_write", hz);
49617821895SHidetoshi Shimokawa 		if(xfer->resp == EBUSY)
49717821895SHidetoshi Shimokawa 			return EBUSY;
49817821895SHidetoshi Shimokawa 		fw_xfer_free( xfer);
49917821895SHidetoshi Shimokawa 		return err;
50017821895SHidetoshi Shimokawa 	}
50117821895SHidetoshi Shimokawa 	return EINVAL;
50217821895SHidetoshi Shimokawa }
50317821895SHidetoshi Shimokawa 
50417821895SHidetoshi Shimokawa /*
50517821895SHidetoshi Shimokawa  * ioctl support.
50617821895SHidetoshi Shimokawa  */
50717821895SHidetoshi Shimokawa int
50817821895SHidetoshi Shimokawa fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
50917821895SHidetoshi Shimokawa {
51017821895SHidetoshi Shimokawa 	struct firewire_softc *sc;
51117821895SHidetoshi Shimokawa 	int unit = DEV2UNIT(dev);
51217821895SHidetoshi Shimokawa 	int sub = DEV2DMACH(dev);
51317821895SHidetoshi Shimokawa 	int i, len, err = 0;
51417821895SHidetoshi Shimokawa 	struct fw_device *fwdev;
51517821895SHidetoshi Shimokawa 	struct fw_bind *fwb;
51617821895SHidetoshi Shimokawa 	struct fw_xferq *ir, *it;
51717821895SHidetoshi Shimokawa 	struct fw_xfer *xfer;
51817821895SHidetoshi Shimokawa 	struct fw_pkt *fp;
51917821895SHidetoshi Shimokawa 
52017821895SHidetoshi Shimokawa 	struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data;
52117821895SHidetoshi Shimokawa 	struct fw_asyreq *asyreq = (struct fw_asyreq *)data;
52217821895SHidetoshi Shimokawa 	struct fw_isochreq *ichreq = (struct fw_isochreq *)data;
52317821895SHidetoshi Shimokawa 	struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data;
52417821895SHidetoshi Shimokawa 	struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data;
52517821895SHidetoshi Shimokawa #if 0
52617821895SHidetoshi Shimokawa 	struct fw_map_buf *map_buf = (struct fw_map_buf *)data;
52717821895SHidetoshi Shimokawa #endif
52817821895SHidetoshi Shimokawa 	struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data;
52917821895SHidetoshi Shimokawa 
53017821895SHidetoshi Shimokawa 	if (DEV_FWMEM(dev))
53117821895SHidetoshi Shimokawa 		return fwmem_ioctl(dev, cmd, data, flag, td);
53217821895SHidetoshi Shimokawa 
53317821895SHidetoshi Shimokawa 	sc = devclass_get_softc(firewire_devclass, unit);
53417821895SHidetoshi Shimokawa 	if (!data)
53517821895SHidetoshi Shimokawa 		return(EINVAL);
53617821895SHidetoshi Shimokawa 
53717821895SHidetoshi Shimokawa 	switch (cmd) {
53817821895SHidetoshi Shimokawa 	case FW_STSTREAM:
53917821895SHidetoshi Shimokawa 		sc->fc->it[sub]->flag &= ~0xff;
54017821895SHidetoshi Shimokawa 		sc->fc->it[sub]->flag |= (0x3f & ichreq->ch);
54117821895SHidetoshi Shimokawa 		sc->fc->it[sub]->flag |= ((0x3 & ichreq->tag) << 6);
54217821895SHidetoshi Shimokawa 		err = 0;
54317821895SHidetoshi Shimokawa 		break;
54417821895SHidetoshi Shimokawa 	case FW_GTSTREAM:
54517821895SHidetoshi Shimokawa 		ichreq->ch = sc->fc->it[sub]->flag & 0x3f;
54617821895SHidetoshi Shimokawa 		ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3;
54717821895SHidetoshi Shimokawa 		err = 0;
54817821895SHidetoshi Shimokawa 		break;
54917821895SHidetoshi Shimokawa 	case FW_SRSTREAM:
55017821895SHidetoshi Shimokawa 		sc->fc->ir[sub]->flag &= ~0xff;
55117821895SHidetoshi Shimokawa 		sc->fc->ir[sub]->flag |= (0x3f & ichreq->ch);
55217821895SHidetoshi Shimokawa 		sc->fc->ir[sub]->flag |= ((0x3 & ichreq->tag) << 6);
55317821895SHidetoshi Shimokawa 		err = sc->fc->irx_enable(sc->fc, sub);
55417821895SHidetoshi Shimokawa 		break;
55517821895SHidetoshi Shimokawa 	case FW_GRSTREAM:
55617821895SHidetoshi Shimokawa 		ichreq->ch = sc->fc->ir[sub]->flag & 0x3f;
55717821895SHidetoshi Shimokawa 		ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3;
55817821895SHidetoshi Shimokawa 		err = 0;
55917821895SHidetoshi Shimokawa 		break;
56017821895SHidetoshi Shimokawa 	case FW_SSTDV:
56117821895SHidetoshi Shimokawa 		ibufreq = (struct fw_isobufreq *)
56217821895SHidetoshi Shimokawa 			malloc(sizeof(struct fw_isobufreq), M_DEVBUF, M_NOWAIT);
56317821895SHidetoshi Shimokawa 		if(ibufreq == NULL){
56417821895SHidetoshi Shimokawa 			err = ENOMEM;
56517821895SHidetoshi Shimokawa 			break;
56617821895SHidetoshi Shimokawa 		}
56717821895SHidetoshi Shimokawa #define FWDVPACKET 250
56817821895SHidetoshi Shimokawa #define FWDVPMAX 512
56917821895SHidetoshi Shimokawa 		ibufreq->rx.nchunk = 8;
57017821895SHidetoshi Shimokawa 		ibufreq->rx.npacket = 50;
57117821895SHidetoshi Shimokawa 		ibufreq->rx.psize = FWDVPMAX;
57217821895SHidetoshi Shimokawa 
57317821895SHidetoshi Shimokawa 		ibufreq->tx.nchunk = 5;
57417821895SHidetoshi Shimokawa 		ibufreq->tx.npacket = 300;
57517821895SHidetoshi Shimokawa 		ibufreq->tx.psize = FWDVPMAX;
57617821895SHidetoshi Shimokawa 
57717821895SHidetoshi Shimokawa 		err = fw_ioctl(dev, FW_SSTBUF, (caddr_t)ibufreq, flag, td);
57817821895SHidetoshi Shimokawa 		sc->fc->it[sub]->dvpacket = FWDVPACKET;
57917821895SHidetoshi Shimokawa 		free(ibufreq, M_DEVBUF);
58017821895SHidetoshi Shimokawa /* reserve a buffer space */
58117821895SHidetoshi Shimokawa #define NDVCHUNK 8
58217821895SHidetoshi Shimokawa 		sc->fc->it[sub]->dvproc = NULL;
58317821895SHidetoshi Shimokawa 		sc->fc->it[sub]->dvdma = NULL;
58417821895SHidetoshi Shimokawa 		sc->fc->it[sub]->flag |= FWXFERQ_DV;
58517821895SHidetoshi Shimokawa 		sc->fc->it[sub]->dvbuf
58617821895SHidetoshi Shimokawa 			= (struct fw_dvbuf *)malloc(sizeof(struct fw_dvbuf) * NDVCHUNK, M_DEVBUF, M_DONTWAIT);
58717821895SHidetoshi Shimokawa 		STAILQ_INIT(&sc->fc->it[sub]->dvvalid);
58817821895SHidetoshi Shimokawa 		STAILQ_INIT(&sc->fc->it[sub]->dvfree);
58917821895SHidetoshi Shimokawa 		for( i = 0 ; i < NDVCHUNK ; i++){
59017821895SHidetoshi Shimokawa 			sc->fc->it[sub]->dvbuf[i].buf
59117821895SHidetoshi Shimokawa 				= malloc(FWDVPMAX * sc->fc->it[sub]->dvpacket, M_DEVBUF, M_DONTWAIT);
59217821895SHidetoshi Shimokawa 			STAILQ_INSERT_TAIL(&sc->fc->it[sub]->dvfree,
59317821895SHidetoshi Shimokawa 					&sc->fc->it[sub]->dvbuf[i], link);
59417821895SHidetoshi Shimokawa 		}
59517821895SHidetoshi Shimokawa 		break;
59617821895SHidetoshi Shimokawa 	case FW_SSTBUF:
59717821895SHidetoshi Shimokawa 		ir = sc->fc->ir[sub];
59817821895SHidetoshi Shimokawa 		it = sc->fc->it[sub];
59917821895SHidetoshi Shimokawa 
60017821895SHidetoshi Shimokawa 		if(ir->flag & FWXFERQ_RUNNING || it->flag & FWXFERQ_RUNNING){
60117821895SHidetoshi Shimokawa 			return(EBUSY);
60217821895SHidetoshi Shimokawa 		}
60317821895SHidetoshi Shimokawa 		if((ir->flag & FWXFERQ_EXTBUF) || (it->flag & FWXFERQ_EXTBUF)){
60417821895SHidetoshi Shimokawa 			return(EBUSY);
60517821895SHidetoshi Shimokawa 		}
60617821895SHidetoshi Shimokawa 		if((ibufreq->rx.nchunk *
60717821895SHidetoshi Shimokawa 			ibufreq->rx.psize * ibufreq->rx.npacket) +
60817821895SHidetoshi Shimokawa 		   (ibufreq->tx.nchunk *
60917821895SHidetoshi Shimokawa 			ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){
61017821895SHidetoshi Shimokawa 				return(EINVAL);
61117821895SHidetoshi Shimokawa 		}
61217821895SHidetoshi Shimokawa 		if(ibufreq->rx.nchunk > FWSTMAXCHUNK ||
61317821895SHidetoshi Shimokawa 				ibufreq->tx.nchunk > FWSTMAXCHUNK){
61417821895SHidetoshi Shimokawa 			return(EINVAL);
61517821895SHidetoshi Shimokawa 		}
61617821895SHidetoshi Shimokawa 		ir->bulkxfer
61717821895SHidetoshi Shimokawa 			= (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_DEVBUF, M_DONTWAIT);
61817821895SHidetoshi Shimokawa 		if(ir->bulkxfer == NULL){
61917821895SHidetoshi Shimokawa 			return(ENOMEM);
62017821895SHidetoshi Shimokawa 		}
62117821895SHidetoshi Shimokawa 		it->bulkxfer
62217821895SHidetoshi Shimokawa 			= (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_DEVBUF, M_DONTWAIT);
62317821895SHidetoshi Shimokawa 		if(it->bulkxfer == NULL){
62417821895SHidetoshi Shimokawa 			return(ENOMEM);
62517821895SHidetoshi Shimokawa 		}
62617821895SHidetoshi Shimokawa 		ir->buf = malloc(
62717821895SHidetoshi Shimokawa 			ibufreq->rx.nchunk * ibufreq->rx.npacket
62817821895SHidetoshi Shimokawa 			* ((ibufreq->rx.psize + 3) &~3),
62917821895SHidetoshi Shimokawa 			M_DEVBUF, M_DONTWAIT);
63017821895SHidetoshi Shimokawa 		if(ir->buf == NULL){
63117821895SHidetoshi Shimokawa 			free(ir->bulkxfer, M_DEVBUF);
63217821895SHidetoshi Shimokawa 			free(it->bulkxfer, M_DEVBUF);
63317821895SHidetoshi Shimokawa 			ir->bulkxfer = NULL;
63417821895SHidetoshi Shimokawa 			it->bulkxfer = NULL;
63517821895SHidetoshi Shimokawa 			it->buf = NULL;
63617821895SHidetoshi Shimokawa 			return(ENOMEM);
63717821895SHidetoshi Shimokawa 		}
63817821895SHidetoshi Shimokawa 		it->buf = malloc(
63917821895SHidetoshi Shimokawa 			ibufreq->tx.nchunk * ibufreq->tx.npacket
64017821895SHidetoshi Shimokawa 			* ((ibufreq->tx.psize + 3) &~3),
64117821895SHidetoshi Shimokawa 			M_DEVBUF, M_DONTWAIT);
64217821895SHidetoshi Shimokawa 		if(it->buf == NULL){
64317821895SHidetoshi Shimokawa 			free(ir->bulkxfer, M_DEVBUF);
64417821895SHidetoshi Shimokawa 			free(it->bulkxfer, M_DEVBUF);
64517821895SHidetoshi Shimokawa 			free(ir->buf, M_DEVBUF);
64617821895SHidetoshi Shimokawa 			ir->bulkxfer = NULL;
64717821895SHidetoshi Shimokawa 			it->bulkxfer = NULL;
64817821895SHidetoshi Shimokawa 			it->buf = NULL;
64917821895SHidetoshi Shimokawa 			return(ENOMEM);
65017821895SHidetoshi Shimokawa 		}
65117821895SHidetoshi Shimokawa 
65217821895SHidetoshi Shimokawa 		ir->bnchunk = ibufreq->rx.nchunk;
65317821895SHidetoshi Shimokawa 		ir->bnpacket = ibufreq->rx.npacket;
65417821895SHidetoshi Shimokawa 		ir->btpacket = ibufreq->rx.npacket;
65517821895SHidetoshi Shimokawa 		ir->psize = (ibufreq->rx.psize + 3) & ~3;
65617821895SHidetoshi Shimokawa 		ir->queued = 0;
65717821895SHidetoshi Shimokawa 
65817821895SHidetoshi Shimokawa 		it->bnchunk = ibufreq->tx.nchunk;
65917821895SHidetoshi Shimokawa 		it->bnpacket = ibufreq->tx.npacket;
66017821895SHidetoshi Shimokawa 		it->btpacket = ibufreq->tx.npacket;
66117821895SHidetoshi Shimokawa 		it->psize = (ibufreq->tx.psize + 3) & ~3;
66217821895SHidetoshi Shimokawa 		ir->queued = 0;
66317821895SHidetoshi Shimokawa 		it->dvdbc = 0;
66417821895SHidetoshi Shimokawa 		it->dvdiff = 0;
66517821895SHidetoshi Shimokawa 		it->dvsync = 0;
66617821895SHidetoshi Shimokawa 
66717821895SHidetoshi Shimokawa 		STAILQ_INIT(&ir->stvalid);
66817821895SHidetoshi Shimokawa 		STAILQ_INIT(&ir->stfree);
66917821895SHidetoshi Shimokawa 		ir->stdma = NULL;
67017821895SHidetoshi Shimokawa 		ir->stdma2 = NULL;
67117821895SHidetoshi Shimokawa 		ir->stproc = NULL;
67217821895SHidetoshi Shimokawa 
67317821895SHidetoshi Shimokawa 		STAILQ_INIT(&it->stvalid);
67417821895SHidetoshi Shimokawa 		STAILQ_INIT(&it->stfree);
67517821895SHidetoshi Shimokawa 		it->stdma = NULL;
67617821895SHidetoshi Shimokawa 		it->stdma2 = NULL;
67717821895SHidetoshi Shimokawa 		it->stproc = NULL;
67817821895SHidetoshi Shimokawa 
67917821895SHidetoshi Shimokawa 		for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){
68017821895SHidetoshi Shimokawa 			ir->bulkxfer[i].buf =
68117821895SHidetoshi Shimokawa 				ir->buf +
68217821895SHidetoshi Shimokawa 				i * sc->fc->ir[sub]->bnpacket *
68317821895SHidetoshi Shimokawa 			  	sc->fc->ir[sub]->psize;
68417821895SHidetoshi Shimokawa 			ir->bulkxfer[i].flag = 0;
68517821895SHidetoshi Shimokawa 			STAILQ_INSERT_TAIL(&ir->stfree,
68617821895SHidetoshi Shimokawa 					&ir->bulkxfer[i], link);
68717821895SHidetoshi Shimokawa 			ir->bulkxfer[i].npacket = ir->bnpacket;
68817821895SHidetoshi Shimokawa 		}
68917821895SHidetoshi Shimokawa 		for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){
69017821895SHidetoshi Shimokawa 			it->bulkxfer[i].buf =
69117821895SHidetoshi Shimokawa 				it->buf +
69217821895SHidetoshi Shimokawa 				i * sc->fc->it[sub]->bnpacket *
69317821895SHidetoshi Shimokawa 			  	sc->fc->it[sub]->psize;
69417821895SHidetoshi Shimokawa 			it->bulkxfer[i].flag = 0;
69517821895SHidetoshi Shimokawa 			STAILQ_INSERT_TAIL(&it->stfree,
69617821895SHidetoshi Shimokawa 					&it->bulkxfer[i], link);
69717821895SHidetoshi Shimokawa 			it->bulkxfer[i].npacket = it->bnpacket;
69817821895SHidetoshi Shimokawa 		}
69917821895SHidetoshi Shimokawa 		ir->flag &= ~FWXFERQ_MODEMASK;
70017821895SHidetoshi Shimokawa 		ir->flag |= FWXFERQ_STREAM;
70117821895SHidetoshi Shimokawa 		ir->flag |= FWXFERQ_EXTBUF;
70217821895SHidetoshi Shimokawa 
70317821895SHidetoshi Shimokawa 		it->flag &= ~FWXFERQ_MODEMASK;
70417821895SHidetoshi Shimokawa 		it->flag |= FWXFERQ_STREAM;
70517821895SHidetoshi Shimokawa 		it->flag |= FWXFERQ_EXTBUF;
70617821895SHidetoshi Shimokawa 		err = 0;
70717821895SHidetoshi Shimokawa 		break;
70817821895SHidetoshi Shimokawa 	case FW_GSTBUF:
70917821895SHidetoshi Shimokawa 		ibufreq->rx.nchunk = sc->fc->ir[sub]->bnchunk;
71017821895SHidetoshi Shimokawa 		ibufreq->rx.npacket = sc->fc->ir[sub]->bnpacket;
71117821895SHidetoshi Shimokawa 		ibufreq->rx.psize = sc->fc->ir[sub]->psize;
71217821895SHidetoshi Shimokawa 
71317821895SHidetoshi Shimokawa 		ibufreq->tx.nchunk = sc->fc->it[sub]->bnchunk;
71417821895SHidetoshi Shimokawa 		ibufreq->tx.npacket = sc->fc->it[sub]->bnpacket;
71517821895SHidetoshi Shimokawa 		ibufreq->tx.psize = sc->fc->it[sub]->psize;
71617821895SHidetoshi Shimokawa 		break;
71717821895SHidetoshi Shimokawa 	case FW_ASYREQ:
71817821895SHidetoshi Shimokawa 		xfer = fw_xfer_alloc();
71917821895SHidetoshi Shimokawa 		if(xfer == NULL){
72017821895SHidetoshi Shimokawa 			err = ENOMEM;
72117821895SHidetoshi Shimokawa 			return err;
72217821895SHidetoshi Shimokawa 		}
72317821895SHidetoshi Shimokawa 		fp = &asyreq->pkt;
72417821895SHidetoshi Shimokawa 		switch (asyreq->req.type) {
72517821895SHidetoshi Shimokawa 		case FWASREQNODE:
72617821895SHidetoshi Shimokawa 			xfer->dst = ntohs(fp->mode.hdr.dst);
72717821895SHidetoshi Shimokawa 			break;
72817821895SHidetoshi Shimokawa 		case FWASREQEUI:
72917821895SHidetoshi Shimokawa 			fwdev = fw_noderesolve(sc->fc, asyreq->req.dst.eui);
73017821895SHidetoshi Shimokawa 			if (fwdev == NULL) {
73117faeefcSHidetoshi Shimokawa 				device_printf(sc->fc->bdev,
73217faeefcSHidetoshi Shimokawa 					"cannot find node\n");
73317821895SHidetoshi Shimokawa 				err = EINVAL;
73417821895SHidetoshi Shimokawa 				goto error;
73517821895SHidetoshi Shimokawa 			}
73617821895SHidetoshi Shimokawa 			xfer->dst = fwdev->dst;
73717821895SHidetoshi Shimokawa 			fp->mode.hdr.dst = htons(FWLOCALBUS | xfer->dst);
73817821895SHidetoshi Shimokawa 			break;
73917821895SHidetoshi Shimokawa 		case FWASRESTL:
74017821895SHidetoshi Shimokawa 			/* XXX what's this? */
74117821895SHidetoshi Shimokawa 			break;
74217821895SHidetoshi Shimokawa 		case FWASREQSTREAM:
74317821895SHidetoshi Shimokawa 			/* nothing to do */
74417821895SHidetoshi Shimokawa 			break;
74517821895SHidetoshi Shimokawa 		}
74617821895SHidetoshi Shimokawa 		xfer->spd = asyreq->req.sped;
74717821895SHidetoshi Shimokawa 		xfer->send.len = asyreq->req.len;
74817821895SHidetoshi Shimokawa 		xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT);
74917821895SHidetoshi Shimokawa 		if(xfer->send.buf == NULL){
75017821895SHidetoshi Shimokawa 			return ENOMEM;
75117821895SHidetoshi Shimokawa 		}
75217821895SHidetoshi Shimokawa 		xfer->send.off = 0;
75317821895SHidetoshi Shimokawa 		bcopy(fp, xfer->send.buf, xfer->send.len);
75417821895SHidetoshi Shimokawa 		xfer->act.hand = fw_asy_callback;
75517821895SHidetoshi Shimokawa 		err = fw_asyreq(sc->fc, sub, xfer);
75617821895SHidetoshi Shimokawa 		if(err){
75717821895SHidetoshi Shimokawa 			fw_xfer_free( xfer);
75817821895SHidetoshi Shimokawa 			return err;
75917821895SHidetoshi Shimokawa 		}
76017821895SHidetoshi Shimokawa 		err = tsleep((caddr_t)xfer, FWPRI, "asyreq", hz);
76117821895SHidetoshi Shimokawa 		if(err == 0){
76217821895SHidetoshi Shimokawa 			if(asyreq->req.len >= xfer->recv.len){
76317821895SHidetoshi Shimokawa 				asyreq->req.len = xfer->recv.len;
76417821895SHidetoshi Shimokawa 			}else{
76517821895SHidetoshi Shimokawa 				err = EINVAL;
76617821895SHidetoshi Shimokawa 			}
76717821895SHidetoshi Shimokawa 			bcopy(xfer->recv.buf + xfer->recv.off, fp, asyreq->req.len);
76817821895SHidetoshi Shimokawa 		}
76917821895SHidetoshi Shimokawa error:
77017821895SHidetoshi Shimokawa 		fw_xfer_free( xfer);
77117821895SHidetoshi Shimokawa 		break;
77217821895SHidetoshi Shimokawa 	case FW_IBUSRST:
77317821895SHidetoshi Shimokawa 		sc->fc->ibr(sc->fc);
77417821895SHidetoshi Shimokawa 		break;
77517821895SHidetoshi Shimokawa 	case FW_CBINDADDR:
77617821895SHidetoshi Shimokawa 		fwb = fw_bindlookup(sc->fc,
77717821895SHidetoshi Shimokawa 				bindreq->start.hi, bindreq->start.lo);
77817821895SHidetoshi Shimokawa 		if(fwb == NULL){
77917821895SHidetoshi Shimokawa 			err = EINVAL;
78017821895SHidetoshi Shimokawa 			break;
78117821895SHidetoshi Shimokawa 		}
78217821895SHidetoshi Shimokawa 		STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
78317821895SHidetoshi Shimokawa 		STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist);
78417821895SHidetoshi Shimokawa 		free(fwb, M_DEVBUF);
78517821895SHidetoshi Shimokawa 		break;
78617821895SHidetoshi Shimokawa 	case FW_SBINDADDR:
78717821895SHidetoshi Shimokawa 		if(bindreq->len <= 0 ){
78817821895SHidetoshi Shimokawa 			err = EINVAL;
78917821895SHidetoshi Shimokawa 			break;
79017821895SHidetoshi Shimokawa 		}
79117821895SHidetoshi Shimokawa 		if(bindreq->start.hi > 0xffff ){
79217821895SHidetoshi Shimokawa 			err = EINVAL;
79317821895SHidetoshi Shimokawa 			break;
79417821895SHidetoshi Shimokawa 		}
79517821895SHidetoshi Shimokawa 		fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_DEVBUF, M_DONTWAIT);
79617821895SHidetoshi Shimokawa 		if(fwb == NULL){
79717821895SHidetoshi Shimokawa 			err = ENOMEM;
79817821895SHidetoshi Shimokawa 			break;
79917821895SHidetoshi Shimokawa 		}
80017821895SHidetoshi Shimokawa 		fwb->start_hi = bindreq->start.hi;
80117821895SHidetoshi Shimokawa 		fwb->start_lo = bindreq->start.lo;
80217821895SHidetoshi Shimokawa 		fwb->addrlen = bindreq->len;
80317821895SHidetoshi Shimokawa 
80417821895SHidetoshi Shimokawa 		xfer = fw_xfer_alloc();
80517821895SHidetoshi Shimokawa 		if(xfer == NULL){
80617821895SHidetoshi Shimokawa 			err = ENOMEM;
80717821895SHidetoshi Shimokawa 			return err;
80817821895SHidetoshi Shimokawa 		}
80917821895SHidetoshi Shimokawa 		xfer->act_type = FWACT_CH;
81017821895SHidetoshi Shimokawa 		xfer->sub = sub;
81117821895SHidetoshi Shimokawa 		xfer->fc = sc->fc;
81217821895SHidetoshi Shimokawa 
81317821895SHidetoshi Shimokawa 		fwb->xfer = xfer;
81417821895SHidetoshi Shimokawa 		err = fw_bindadd(sc->fc, fwb);
81517821895SHidetoshi Shimokawa 		break;
81617821895SHidetoshi Shimokawa 	case FW_GDEVLST:
81717821895SHidetoshi Shimokawa 		i = 0;
81817821895SHidetoshi Shimokawa 		for(fwdev = TAILQ_FIRST(&sc->fc->devices); fwdev != NULL;
81917821895SHidetoshi Shimokawa 			fwdev = TAILQ_NEXT(fwdev, link)){
82017821895SHidetoshi Shimokawa 			if(i < fwdevlst->n){
82117821895SHidetoshi Shimokawa 				fwdevlst->dst[i] = fwdev->dst;
82217821895SHidetoshi Shimokawa 				fwdevlst->status[i] =
82317821895SHidetoshi Shimokawa 					(fwdev->status == FWDEVATTACHED)?1:0;
82417821895SHidetoshi Shimokawa 				fwdevlst->eui[i].hi = fwdev->eui.hi;
82517821895SHidetoshi Shimokawa 				fwdevlst->eui[i].lo = fwdev->eui.lo;
82617821895SHidetoshi Shimokawa 			}
82717821895SHidetoshi Shimokawa 			i++;
82817821895SHidetoshi Shimokawa 		}
82917821895SHidetoshi Shimokawa 		fwdevlst->n = i;
83017821895SHidetoshi Shimokawa 		break;
83117821895SHidetoshi Shimokawa 	case FW_GTPMAP:
83217821895SHidetoshi Shimokawa 		bcopy(sc->fc->topology_map, data,
83317821895SHidetoshi Shimokawa 				(sc->fc->topology_map->crc_len + 1) * 4);
83417821895SHidetoshi Shimokawa 		break;
83517821895SHidetoshi Shimokawa 	case FW_GCROM:
83617821895SHidetoshi Shimokawa 		for (fwdev = TAILQ_FIRST(&sc->fc->devices); fwdev != NULL;
83717821895SHidetoshi Shimokawa 			fwdev = TAILQ_NEXT(fwdev, link)) {
83817821895SHidetoshi Shimokawa 			if (fwdev->eui.hi == crom_buf->eui.hi &&
83917821895SHidetoshi Shimokawa 					fwdev->eui.lo == crom_buf->eui.lo)
84017821895SHidetoshi Shimokawa 				break;
84117821895SHidetoshi Shimokawa 		}
84217821895SHidetoshi Shimokawa 		if (fwdev == NULL) {
84317821895SHidetoshi Shimokawa 			err = FWNODE_INVAL;
84417821895SHidetoshi Shimokawa 			break;
84517821895SHidetoshi Shimokawa 		}
84617821895SHidetoshi Shimokawa #if 0
84717821895SHidetoshi Shimokawa 		if (fwdev->csrrom[0] >> 24 == 1)
84817821895SHidetoshi Shimokawa 			len = 4;
84917821895SHidetoshi Shimokawa 		else
85017821895SHidetoshi Shimokawa 			len = (1 + ((fwdev->csrrom[0] >> 16) & 0xff)) * 4;
85117821895SHidetoshi Shimokawa #else
85217821895SHidetoshi Shimokawa 		if (fwdev->rommax < CSRROMOFF)
85317821895SHidetoshi Shimokawa 			len = 0;
85417821895SHidetoshi Shimokawa 		else
85517821895SHidetoshi Shimokawa 			len = fwdev->rommax - CSRROMOFF + 4;
85617821895SHidetoshi Shimokawa #endif
85717821895SHidetoshi Shimokawa 		if (crom_buf->len < len)
85817821895SHidetoshi Shimokawa 			len = crom_buf->len;
85917821895SHidetoshi Shimokawa 		else
86017821895SHidetoshi Shimokawa 			crom_buf->len = len;
86117821895SHidetoshi Shimokawa 		err = copyout(&fwdev->csrrom[0], crom_buf->ptr, len);
86217821895SHidetoshi Shimokawa 		break;
86317821895SHidetoshi Shimokawa 	default:
86417821895SHidetoshi Shimokawa 		sc->fc->ioctl (dev, cmd, data, flag, td);
86517821895SHidetoshi Shimokawa 		break;
86617821895SHidetoshi Shimokawa 	}
86717821895SHidetoshi Shimokawa 	return err;
86817821895SHidetoshi Shimokawa }
86917821895SHidetoshi Shimokawa int
87017821895SHidetoshi Shimokawa fw_poll(dev_t dev, int events, fw_proc *td)
87117821895SHidetoshi Shimokawa {
87217821895SHidetoshi Shimokawa 	int revents;
87317821895SHidetoshi Shimokawa 	int tmp;
87417821895SHidetoshi Shimokawa 	int unit = DEV2UNIT(dev);
87517821895SHidetoshi Shimokawa 	int sub = DEV2DMACH(dev);
87617821895SHidetoshi Shimokawa 	struct firewire_softc *sc;
87717821895SHidetoshi Shimokawa 
87817821895SHidetoshi Shimokawa 	if (DEV_FWMEM(dev))
87917821895SHidetoshi Shimokawa 		return fwmem_poll(dev, events, td);
88017821895SHidetoshi Shimokawa 
88117821895SHidetoshi Shimokawa 	sc = devclass_get_softc(firewire_devclass, unit);
88217821895SHidetoshi Shimokawa 	revents = 0;
88317821895SHidetoshi Shimokawa 	tmp = POLLIN | POLLRDNORM;
88417821895SHidetoshi Shimokawa 	if (events & tmp) {
88517821895SHidetoshi Shimokawa 		if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL)
88617821895SHidetoshi Shimokawa 			revents |= tmp;
88717821895SHidetoshi Shimokawa 		else
88817821895SHidetoshi Shimokawa 			selrecord(td, &sc->fc->ir[sub]->rsel);
88917821895SHidetoshi Shimokawa 	}
89017821895SHidetoshi Shimokawa 	tmp = POLLOUT | POLLWRNORM;
89117821895SHidetoshi Shimokawa 	if (events & tmp) {
89217821895SHidetoshi Shimokawa 		/* XXX should be fixed */
89317821895SHidetoshi Shimokawa 		revents |= tmp;
89417821895SHidetoshi Shimokawa 	}
89517821895SHidetoshi Shimokawa 
89617821895SHidetoshi Shimokawa 	return revents;
89717821895SHidetoshi Shimokawa }
89817821895SHidetoshi Shimokawa 
89917821895SHidetoshi Shimokawa static int
90017821895SHidetoshi Shimokawa fw_mmap (dev_t dev, vm_offset_t offset, int nproto)
90117821895SHidetoshi Shimokawa {
90217821895SHidetoshi Shimokawa 	struct firewire_softc *fc;
90317821895SHidetoshi Shimokawa 	int unit = DEV2UNIT(dev);
90417821895SHidetoshi Shimokawa 
90517821895SHidetoshi Shimokawa 	if (DEV_FWMEM(dev))
90617821895SHidetoshi Shimokawa 		return fwmem_mmap(dev, offset, nproto);
90717821895SHidetoshi Shimokawa 
90817821895SHidetoshi Shimokawa 	fc = devclass_get_softc(firewire_devclass, unit);
90917821895SHidetoshi Shimokawa 
91017821895SHidetoshi Shimokawa 	return EINVAL;
91117821895SHidetoshi Shimokawa }
912