fwdev.c revision 111942
1219820Sjeff/*
2219820Sjeff * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
3219820Sjeff * All rights reserved.
4219820Sjeff *
5219820Sjeff * Redistribution and use in source and binary forms, with or without
6219820Sjeff * modification, are permitted provided that the following conditions
7219820Sjeff * are met:
8219820Sjeff * 1. Redistributions of source code must retain the above copyright
9219820Sjeff *    notice, this list of conditions and the following disclaimer.
10219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright
11219820Sjeff *    notice, this list of conditions and the following disclaimer in the
12219820Sjeff *    documentation and/or other materials provided with the distribution.
13219820Sjeff * 3. All advertising materials mentioning features or use of this software
14219820Sjeff *    must display the acknowledgement as bellow:
15219820Sjeff *
16219820Sjeff *    This product includes software developed by K. Kobayashi and H. Shimokawa
17219820Sjeff *
18219820Sjeff * 4. The name of the author may not be used to endorse or promote products
19219820Sjeff *    derived from this software without specific prior written permission.
20219820Sjeff *
21219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22219820Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23219820Sjeff * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24219820Sjeff * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25219820Sjeff * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26219820Sjeff * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27219820Sjeff * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28219820Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29219820Sjeff * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30219820Sjeff * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31219820Sjeff * POSSIBILITY OF SUCH DAMAGE.
32219820Sjeff *
33219820Sjeff * $FreeBSD: head/sys/dev/firewire/fwdev.c 111942 2003-03-06 05:06:44Z simokawa $
34219820Sjeff *
35255932Salfred */
36255932Salfred
37219820Sjeff#include <sys/param.h>
38255932Salfred#include <sys/systm.h>
39306486Shselasky#include <sys/types.h>
40255932Salfred#include <sys/mbuf.h>
41255932Salfred
42219820Sjeff#include <sys/kernel.h>
43219820Sjeff#include <sys/malloc.h>
44219820Sjeff#include <sys/conf.h>
45219820Sjeff#include <sys/uio.h>
46219820Sjeff#include <sys/poll.h>
47219820Sjeff
48219820Sjeff#include <sys/bus.h>
49219820Sjeff
50255932Salfred#include <sys/ioccom.h>
51255932Salfred
52255932Salfred#include <dev/firewire/firewire.h>
53255932Salfred#include <dev/firewire/firewirereg.h>
54255932Salfred#include <dev/firewire/fwmem.h>
55255932Salfred#include <dev/firewire/iec68113.h>
56255932Salfred
57255932Salfred#define CDEV_MAJOR 127
58255932Salfred#define	FWNODE_INVAL 0xffff
59255932Salfred
60255932Salfredstatic	d_open_t	fw_open;
61255932Salfredstatic	d_close_t	fw_close;
62255932Salfredstatic	d_ioctl_t	fw_ioctl;
63255932Salfredstatic	d_poll_t	fw_poll;
64255932Salfredstatic	d_read_t	fw_read;	/* for Isochronous packet */
65255932Salfredstatic	d_write_t	fw_write;
66255932Salfredstatic	d_mmap_t	fw_mmap;
67255932Salfred
68255932Salfredstruct cdevsw firewire_cdevsw =
69255932Salfred{
70255932Salfred#if __FreeBSD_version >= 500104
71255932Salfred	.d_open =	fw_open,
72255932Salfred	.d_close =	fw_close,
73255932Salfred	.d_read =	fw_read,
74255932Salfred	.d_write =	fw_write,
75255932Salfred	.d_ioctl =	fw_ioctl,
76255932Salfred	.d_poll =	fw_poll,
77255932Salfred	.d_mmap =	fw_mmap,
78255932Salfred	.d_name =	"fw",
79255932Salfred	.d_maj =	CDEV_MAJOR,
80255932Salfred	.d_flags =	D_MEM
81255932Salfred#else
82255932Salfred	fw_open, fw_close, fw_read, fw_write, fw_ioctl,
83255932Salfred	fw_poll, fw_mmap, nostrategy, "fw", CDEV_MAJOR, nodump, nopsize, D_MEM
84255932Salfred#endif
85255932Salfred};
86255932Salfred
87255932Salfredstatic int
88255932Salfredfw_open (dev_t dev, int flags, int fmt, fw_proc *td)
89255932Salfred{
90255932Salfred	struct firewire_softc *sc;
91255932Salfred	int unit = DEV2UNIT(dev);
92255932Salfred	int sub = DEV2DMACH(dev);
93255932Salfred
94255932Salfred	int err = 0;
95255932Salfred
96255932Salfred	if (DEV_FWMEM(dev))
97255932Salfred		return fwmem_open(dev, flags, fmt, td);
98255932Salfred
99255932Salfred	sc = devclass_get_softc(firewire_devclass, unit);
100255932Salfred	if(sc->fc->ir[sub]->flag & FWXFERQ_OPEN){
101255932Salfred		err = EBUSY;
102255932Salfred		return err;
103255932Salfred	}
104255932Salfred	if(sc->fc->it[sub]->flag & FWXFERQ_OPEN){
105255932Salfred		err = EBUSY;
106219820Sjeff		return err;
107219820Sjeff	}
108219820Sjeff	if(sc->fc->ir[sub]->flag & FWXFERQ_MODEMASK){
109219820Sjeff		err = EBUSY;
110219820Sjeff		return err;
111219820Sjeff	}
112219820Sjeff/* Default is per packet mode */
113219820Sjeff	sc->fc->ir[sub]->flag |= FWXFERQ_OPEN;
114219820Sjeff	sc->fc->it[sub]->flag |= FWXFERQ_OPEN;
115219820Sjeff	sc->fc->ir[sub]->flag |= FWXFERQ_PACKET;
116219820Sjeff	return err;
117219820Sjeff}
118219820Sjeff
119219820Sjeffstatic int
120219820Sjefffw_close (dev_t dev, int flags, int fmt, fw_proc *td)
121219820Sjeff{
122219820Sjeff	struct firewire_softc *sc;
123219820Sjeff	int unit = DEV2UNIT(dev);
124219820Sjeff	int sub = DEV2DMACH(dev);
125219820Sjeff	struct fw_xfer *xfer;
126219820Sjeff	struct fw_bind *fwb;
127219820Sjeff	int err = 0;
128219820Sjeff
129219820Sjeff	if (DEV_FWMEM(dev))
130219820Sjeff		return fwmem_close(dev, flags, fmt, td);
131219820Sjeff
132255932Salfred	sc = devclass_get_softc(firewire_devclass, unit);
133219820Sjeff	if(!(sc->fc->ir[sub]->flag & FWXFERQ_OPEN)){
134255932Salfred		err = EINVAL;
135219820Sjeff		return err;
136255932Salfred	}
137255932Salfred	sc->fc->ir[sub]->flag &= ~FWXFERQ_OPEN;
138255932Salfred	if(!(sc->fc->it[sub]->flag & FWXFERQ_OPEN)){
139219820Sjeff		err = EINVAL;
140219820Sjeff		return err;
141219820Sjeff	}
142219820Sjeff	sc->fc->it[sub]->flag &= ~FWXFERQ_OPEN;
143219820Sjeff
144219820Sjeff	if(sc->fc->ir[sub]->flag & FWXFERQ_RUNNING){
145219820Sjeff		sc->fc->irx_disable(sc->fc, sub);
146219820Sjeff	}
147219820Sjeff	if(sc->fc->it[sub]->flag & FWXFERQ_RUNNING){
148219820Sjeff		sc->fc->it[sub]->flag &= ~FWXFERQ_RUNNING;
149219820Sjeff		sc->fc->itx_disable(sc->fc, sub);
150219820Sjeff	}
151219820Sjeff#ifdef FWXFERQ_DV
152219820Sjeff	if(sc->fc->it[sub]->flag & FWXFERQ_DV){
153219820Sjeff		struct fw_dvbuf *dvbuf;
154219820Sjeff
155219820Sjeff		if((dvbuf = sc->fc->it[sub]->dvproc) != NULL){
156219820Sjeff			free(dvbuf->buf, M_FW);
157219820Sjeff			sc->fc->it[sub]->dvproc = NULL;
158219820Sjeff		}
159219820Sjeff		if((dvbuf = sc->fc->it[sub]->dvdma) != NULL){
160219820Sjeff			free(dvbuf->buf, M_FW);
161219820Sjeff			sc->fc->it[sub]->dvdma = NULL;
162219820Sjeff		}
163219820Sjeff		while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvvalid)) != NULL){
164219820Sjeff			STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvvalid, link);
165219820Sjeff			free(dvbuf->buf, M_FW);
166219820Sjeff		}
167219820Sjeff		while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvfree)) != NULL){
168219820Sjeff			STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvfree, link);
169219820Sjeff			free(dvbuf->buf, M_FW);
170219820Sjeff		}
171255932Salfred		free(sc->fc->it[sub]->dvbuf, M_FW);
172255932Salfred		sc->fc->it[sub]->dvbuf = NULL;
173255932Salfred	}
174255932Salfred#endif
175219820Sjeff	if(sc->fc->ir[sub]->flag & FWXFERQ_EXTBUF){
176219820Sjeff		free(sc->fc->ir[sub]->buf, M_FW);
177219820Sjeff		sc->fc->ir[sub]->buf = NULL;
178219820Sjeff		free(sc->fc->ir[sub]->bulkxfer, M_FW);
179219820Sjeff		sc->fc->ir[sub]->bulkxfer = NULL;
180219820Sjeff		sc->fc->ir[sub]->flag &= ~FWXFERQ_EXTBUF;
181219820Sjeff		sc->fc->ir[sub]->psize = PAGE_SIZE;
182219820Sjeff		sc->fc->ir[sub]->maxq = FWMAXQUEUE;
183219820Sjeff	}
184219820Sjeff	if(sc->fc->it[sub]->flag & FWXFERQ_EXTBUF){
185219820Sjeff		free(sc->fc->it[sub]->buf, M_FW);
186219820Sjeff		sc->fc->it[sub]->buf = NULL;
187219820Sjeff		free(sc->fc->it[sub]->bulkxfer, M_FW);
188219820Sjeff		sc->fc->it[sub]->bulkxfer = NULL;
189255932Salfred#ifdef FWXFERQ_DV
190219820Sjeff		sc->fc->it[sub]->dvbuf = NULL;
191219820Sjeff#endif
192219820Sjeff		sc->fc->it[sub]->flag &= ~FWXFERQ_EXTBUF;
193219820Sjeff		sc->fc->it[sub]->psize = 0;
194219820Sjeff		sc->fc->it[sub]->maxq = FWMAXQUEUE;
195219820Sjeff	}
196219820Sjeff	for(xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q);
197219820Sjeff		xfer != NULL; xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q)){
198219820Sjeff		sc->fc->ir[sub]->queued--;
199219820Sjeff		STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->q, link);
200219820Sjeff
201219820Sjeff		xfer->resp = 0;
202219820Sjeff		switch(xfer->act_type){
203219820Sjeff		case FWACT_XFER:
204255932Salfred			fw_xfer_done(xfer);
205219820Sjeff			break;
206219820Sjeff		default:
207219820Sjeff			break;
208255932Salfred		}
209219820Sjeff		fw_xfer_free(xfer);
210219820Sjeff	}
211219820Sjeff	for(fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds); fwb != NULL;
212255932Salfred		fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds)){
213255932Salfred		STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
214219820Sjeff		STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->binds, chlist);
215219820Sjeff		free(fwb, M_FW);
216255932Salfred	}
217219820Sjeff	sc->fc->ir[sub]->flag &= ~FWXFERQ_MODEMASK;
218255932Salfred	sc->fc->it[sub]->flag &= ~FWXFERQ_MODEMASK;
219255932Salfred	return err;
220255932Salfred}
221255932Salfred
222255932Salfred/*
223219820Sjeff * read request.
224255932Salfred */
225255932Salfredstatic int
226219820Sjefffw_read (dev_t dev, struct uio *uio, int ioflag)
227219820Sjeff{
228255932Salfred	struct firewire_softc *sc;
229255932Salfred	struct fw_xferq *ir;
230255932Salfred	struct fw_xfer *xfer;
231255932Salfred	int err = 0, s, slept = 0;
232255932Salfred	int unit = DEV2UNIT(dev);
233219820Sjeff	int sub = DEV2DMACH(dev);
234255932Salfred	struct fw_pkt *fp;
235219820Sjeff
236219820Sjeff	if (DEV_FWMEM(dev))
237219820Sjeff		return fwmem_read(dev, uio, ioflag);
238255932Salfred
239255932Salfred	sc = devclass_get_softc(firewire_devclass, unit);
240219820Sjeff
241255932Salfred	ir = sc->fc->ir[sub];
242255932Salfred
243255932Salfred	if (ir->flag & FWXFERQ_PACKET) {
244255932Salfred		ir->stproc = NULL;
245255932Salfred	}
246255932Salfredreadloop:
247255932Salfred	xfer = STAILQ_FIRST(&ir->q);
248255932Salfred	if ((ir->flag & FWXFERQ_PACKET) == 0 && ir->stproc == NULL) {
249255932Salfred		/* iso bulkxfer */
250219820Sjeff		ir->stproc = STAILQ_FIRST(&ir->stvalid);
251219820Sjeff		if (ir->stproc != NULL) {
252255932Salfred			s = splfw();
253255932Salfred			STAILQ_REMOVE_HEAD(&ir->stvalid, link);
254255932Salfred			splx(s);
255255932Salfred			ir->queued = 0;
256255932Salfred		}
257255932Salfred	}
258255932Salfred	if (xfer == NULL && ir->stproc == NULL) {
259255932Salfred		/* no data avaliable */
260255932Salfred		if (slept == 0) {
261255932Salfred			slept = 1;
262255932Salfred			if ((ir->flag & FWXFERQ_RUNNING) == 0
263255932Salfred					&& (ir->flag & FWXFERQ_PACKET)) {
264255932Salfred				err = sc->fc->irx_enable(sc->fc, sub);
265255932Salfred				if (err)
266255932Salfred					return err;
267219820Sjeff			}
268255932Salfred			ir->flag |= FWXFERQ_WAKEUP;
269255932Salfred			err = tsleep(ir, FWPRI, "fw_read", hz);
270255932Salfred			ir->flag &= ~FWXFERQ_WAKEUP;
271255932Salfred			if (err == 0)
272255932Salfred				goto readloop;
273255932Salfred		} else if (slept == 1)
274255932Salfred			err = EIO;
275255932Salfred		return err;
276255932Salfred	} else if(xfer != NULL) {
277255932Salfred		/* per packet mode */
278255932Salfred		s = splfw();
279255932Salfred		ir->queued --;
280255932Salfred		STAILQ_REMOVE_HEAD(&ir->q, link);
281255932Salfred		splx(s);
282255932Salfred		fp = (struct fw_pkt *)(xfer->recv.buf + xfer->recv.off);
283255932Salfred		if(sc->fc->irx_post != NULL)
284255932Salfred			sc->fc->irx_post(sc->fc, fp->mode.ld);
285255932Salfred		err = uiomove(xfer->recv.buf + xfer->recv.off, xfer->recv.len, uio);
286255932Salfred		fw_xfer_free( xfer);
287255932Salfred	} else if(ir->stproc != NULL) {
288255932Salfred		/* iso bulkxfer */
289255932Salfred		fp = (struct fw_pkt *)(ir->stproc->buf + ir->queued * ir->psize);
290255932Salfred		if(sc->fc->irx_post != NULL)
291255932Salfred			sc->fc->irx_post(sc->fc, fp->mode.ld);
292255932Salfred		if(ntohs(fp->mode.stream.len) == 0){
293255932Salfred			err = EIO;
294255932Salfred			return err;
295255932Salfred		}
296255932Salfred		err = uiomove((caddr_t)fp,
297255932Salfred			ntohs(fp->mode.stream.len) + sizeof(u_int32_t), uio);
298255932Salfred#if 0
299219820Sjeff		fp->mode.stream.len = 0;
300255932Salfred#endif
301219820Sjeff		ir->queued ++;
302255932Salfred		if(ir->queued >= ir->bnpacket){
303255932Salfred			s = splfw();
304255932Salfred			STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link);
305255932Salfred			splx(s);
306255932Salfred			sc->fc->irx_enable(sc->fc, sub);
307255932Salfred			ir->stproc = NULL;
308255932Salfred		}
309255932Salfred		if (uio->uio_resid >= ir->psize) {
310255932Salfred			slept = -1;
311255932Salfred			goto readloop;
312255932Salfred		}
313255932Salfred	}
314255932Salfred	return err;
315255932Salfred}
316255932Salfred
317255932Salfredstatic int
318255932Salfredfw_write (dev_t dev, struct uio *uio, int ioflag)
319255932Salfred{
320255932Salfred	int err = 0;
321255932Salfred	struct firewire_softc *sc;
322255932Salfred	int unit = DEV2UNIT(dev);
323255932Salfred	int sub = DEV2DMACH(dev);
324255932Salfred	int s, slept = 0;
325255932Salfred	struct fw_pkt *fp;
326255932Salfred	struct fw_xfer *xfer;
327255932Salfred	struct fw_xferq *xferq;
328255932Salfred	struct firewire_comm *fc;
329255932Salfred	struct fw_xferq *it;
330255932Salfred
331255932Salfred	if (DEV_FWMEM(dev))
332219820Sjeff		return fwmem_write(dev, uio, ioflag);
333219820Sjeff
334219820Sjeff	sc = devclass_get_softc(firewire_devclass, unit);
335219820Sjeff	fc = sc->fc;
336219820Sjeff	it = sc->fc->it[sub];
337219820Sjeff
338219820Sjeff	fp = (struct fw_pkt *)uio->uio_iov->iov_base;
339255932Salfred	switch(fp->mode.common.tcode){
340255932Salfred	case FWTCODE_RREQQ:
341219820Sjeff	case FWTCODE_RREQB:
342219820Sjeff	case FWTCODE_LREQ:
343219820Sjeff		err = EINVAL;
344219820Sjeff		return err;
345255932Salfred	case FWTCODE_WREQQ:
346219820Sjeff	case FWTCODE_WREQB:
347255932Salfred		xferq = fc->atq;
348219820Sjeff		break;
349219820Sjeff	case FWTCODE_STREAM:
350219820Sjeff		if(it->flag & FWXFERQ_PACKET){
351219820Sjeff			xferq = fc->atq;
352219820Sjeff		}else{
353219820Sjeff			xferq = NULL;
354219820Sjeff		}
355219820Sjeff		break;
356219820Sjeff	case FWTCODE_WRES:
357255932Salfred	case FWTCODE_RRESQ:
358219820Sjeff	case FWTCODE_RRESB:
359219820Sjeff	case FWTCODE_LRES:
360219820Sjeff		xferq = fc->ats;
361219820Sjeff		break;
362255932Salfred	default:
363255932Salfred		err = EINVAL;
364219820Sjeff		return err;
365219820Sjeff	}
366219820Sjeff	/* Discard unsent buffered stream packet, when sending Asyrequrst */
367219820Sjeff	if(xferq != NULL && it->stproc != NULL){
368219820Sjeff		s = splfw();
369219820Sjeff		STAILQ_INSERT_TAIL(&it->stfree, it->stproc, link);
370255932Salfred		splx(s);
371219820Sjeff		it->stproc = NULL;
372219820Sjeff	}
373219820Sjeff#ifdef FWXFERQ_DV
374219820Sjeff	if(xferq == NULL && !(it->flag & FWXFERQ_DV)){
375219820Sjeff#else
376255932Salfred	if (xferq == NULL) {
377219820Sjeff#endif
378219820Sjeffisoloop:
379219820Sjeff		if (it->stproc == NULL) {
380219820Sjeff			it->stproc = STAILQ_FIRST(&it->stfree);
381219820Sjeff			if (it->stproc != NULL) {
382219820Sjeff				s = splfw();
383255932Salfred				STAILQ_REMOVE_HEAD(&it->stfree, link);
384255932Salfred				splx(s);
385219820Sjeff				it->queued = 0;
386255932Salfred			} else if (slept == 0) {
387255932Salfred				slept = 1;
388255932Salfred				err = sc->fc->itx_enable(sc->fc, sub);
389255932Salfred				if (err)
390255932Salfred					return err;
391255932Salfred				err = tsleep(it, FWPRI,
392255932Salfred							"fw_write", hz);
393255932Salfred				if (err)
394255932Salfred					return err;
395255932Salfred				goto isoloop;
396255932Salfred			} else {
397219820Sjeff				err = EIO;
398219820Sjeff				return err;
399255932Salfred			}
400219820Sjeff		}
401255932Salfred		fp = (struct fw_pkt *)
402255932Salfred			(it->stproc->buf + it->queued * it->psize);
403255932Salfred		err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio);
404255932Salfred		err = uiomove((caddr_t)fp->mode.stream.payload,
405255932Salfred					ntohs(fp->mode.stream.len), uio);
406255932Salfred		it->queued ++;
407255932Salfred		if (it->queued >= it->bnpacket) {
408255932Salfred			s = splfw();
409219820Sjeff			STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
410219820Sjeff			splx(s);
411255932Salfred			it->stproc = NULL;
412255932Salfred			err = sc->fc->itx_enable(sc->fc, sub);
413255932Salfred		}
414255932Salfred		if (uio->uio_resid >= sizeof(struct fw_isohdr)) {
415255932Salfred			slept = 0;
416255932Salfred			goto isoloop;
417255932Salfred		}
418255932Salfred		return err;
419255932Salfred	}
420255932Salfred#ifdef FWXFERQ_DV
421255932Salfred	if(xferq == NULL && it->flag & FWXFERQ_DV){
422255932Salfreddvloop:
423255932Salfred		if(it->dvproc == NULL){
424255932Salfred			it->dvproc = STAILQ_FIRST(&it->dvfree);
425255932Salfred			if(it->dvproc != NULL){
426255932Salfred				s = splfw();
427255932Salfred				STAILQ_REMOVE_HEAD(&it->dvfree, link);
428255932Salfred				splx(s);
429255932Salfred				it->dvptr = 0;
430255932Salfred			}else if(slept == 0){
431255932Salfred				slept = 1;
432255932Salfred				err = sc->fc->itx_enable(sc->fc, sub);
433255932Salfred				if(err){
434255932Salfred					return err;
435255932Salfred				}
436255932Salfred				err = tsleep(it, FWPRI, "fw_write", hz);
437255932Salfred				if(err){
438255932Salfred					return err;
439255932Salfred				}
440255932Salfred				goto dvloop;
441255932Salfred			}else{
442255932Salfred				err = EIO;
443255932Salfred				return err;
444255932Salfred			}
445255932Salfred		}
446255932Salfred#if 0 /* What's this for? (it->dvptr? overwritten by the following uiomove)*/
447255932Salfred		fp = (struct fw_pkt *)(it->dvproc->buf + it->queued * it->psize);
448255932Salfred		fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t));
449255932Salfred#endif
450255932Salfred		err = uiomove(it->dvproc->buf + it->dvptr,
451255932Salfred							uio->uio_resid, uio);
452255932Salfred		it->dvptr += it->psize;
453255932Salfred		if(err){
454255932Salfred			return err;
455255932Salfred		}
456255932Salfred		if(it->dvptr >= it->psize * it->dvpacket){
457255932Salfred			s = splfw();
458255932Salfred			STAILQ_INSERT_TAIL(&it->dvvalid, it->dvproc, link);
459255932Salfred			splx(s);
460255932Salfred			it->dvproc = NULL;
461255932Salfred			err = fw_tbuf_update(sc->fc, sub, 0);
462255932Salfred			if(err){
463255932Salfred				return err;
464255932Salfred			}
465255932Salfred			err = sc->fc->itx_enable(sc->fc, sub);
466255932Salfred		}
467255932Salfred		return err;
468255932Salfred	}
469255932Salfred#endif
470255932Salfred	if(xferq != NULL){
471255932Salfred		xfer = fw_xfer_alloc(M_FWXFER);
472255932Salfred		if(xfer == NULL){
473255932Salfred			err = ENOMEM;
474255932Salfred			return err;
475255932Salfred		}
476255932Salfred		xfer->send.buf = malloc(uio->uio_resid, M_FW, M_NOWAIT);
477255932Salfred		if(xfer->send.buf == NULL){
478255932Salfred			fw_xfer_free( xfer);
479255932Salfred			err = ENOBUFS;
480255932Salfred			return err;
481255932Salfred		}
482255932Salfred		xfer->dst = ntohs(fp->mode.hdr.dst);
483255932Salfred#if 0
484255932Salfred		switch(fp->mode.common.tcode){
485255932Salfred		case FWTCODE_WREQQ:
486255932Salfred		case FWTCODE_WREQB:
487255932Salfred			if((tl = fw_get_tlabel(fc, xfer)) == -1 ){
488255932Salfred				fw_xfer_free( xfer);
489255932Salfred				err = EAGAIN;
490255932Salfred				return err;
491255932Salfred			}
492255932Salfred			fp->mode.hdr.tlrt = tl << 2;
493255932Salfred		default:
494255932Salfred			break;
495255932Salfred		}
496255932Salfred
497255932Salfred		xfer->tl = fp->mode.hdr.tlrt >> 2;
498255932Salfred		xfer->tcode = fp->mode.common.tcode;
499255932Salfred		xfer->fc = fc;
500255932Salfred		xfer->q = xferq;
501255932Salfred		xfer->act_type = FWACT_XFER;
502255932Salfred		xfer->retry_req = fw_asybusy;
503255932Salfred#endif
504255932Salfred		xfer->send.len = uio->uio_resid;
505255932Salfred		xfer->send.off = 0;
506255932Salfred		xfer->spd = 0;/* XXX: how to setup it */
507255932Salfred		xfer->act.hand = fw_asy_callback;
508255932Salfred
509255932Salfred		err = uiomove(xfer->send.buf, uio->uio_resid, uio);
510255932Salfred		if(err){
511255932Salfred			fw_xfer_free( xfer);
512255932Salfred			return err;
513255932Salfred		}
514255932Salfred#if 0
515255932Salfred		fw_asystart(xfer);
516255932Salfred#else
517255932Salfred		fw_asyreq(fc, -1, xfer);
518255932Salfred#endif
519255932Salfred		err = tsleep(xfer, FWPRI, "fw_write", hz);
520255932Salfred		if(xfer->resp == EBUSY)
521255932Salfred			return EBUSY;
522255932Salfred		fw_xfer_free( xfer);
523255932Salfred		return err;
524255932Salfred	}
525255932Salfred	return EINVAL;
526255932Salfred}
527255932Salfred
528255932Salfred/*
529255932Salfred * ioctl support.
530255932Salfred */
531255932Salfredint
532255932Salfredfw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
533255932Salfred{
534255932Salfred	struct firewire_softc *sc;
535255932Salfred	int unit = DEV2UNIT(dev);
536255932Salfred	int sub = DEV2DMACH(dev);
537255932Salfred	int i, len, err = 0;
538255932Salfred	struct fw_device *fwdev;
539255932Salfred	struct fw_bind *fwb;
540255932Salfred	struct fw_xferq *ir, *it;
541255932Salfred	struct fw_xfer *xfer;
542255932Salfred	struct fw_pkt *fp;
543255932Salfred	struct fw_devinfo *devinfo;
544255932Salfred
545255932Salfred	struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data;
546255932Salfred	struct fw_asyreq *asyreq = (struct fw_asyreq *)data;
547255932Salfred	struct fw_isochreq *ichreq = (struct fw_isochreq *)data;
548255932Salfred	struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data;
549255932Salfred	struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data;
550255932Salfred	struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data;
551278886Shselasky
552278886Shselasky	if (DEV_FWMEM(dev))
553278886Shselasky		return fwmem_ioctl(dev, cmd, data, flag, td);
554278886Shselasky
555278886Shselasky	sc = devclass_get_softc(firewire_devclass, unit);
556278886Shselasky	if (!data)
557278886Shselasky		return(EINVAL);
558278886Shselasky
559278886Shselasky	switch (cmd) {
560278886Shselasky	case FW_STSTREAM:
561278886Shselasky		sc->fc->it[sub]->flag &= ~0xff;
562278886Shselasky		sc->fc->it[sub]->flag |= (0x3f & ichreq->ch);
563278886Shselasky		sc->fc->it[sub]->flag |= ((0x3 & ichreq->tag) << 6);
564278886Shselasky		err = 0;
565278886Shselasky		break;
566278886Shselasky	case FW_GTSTREAM:
567278886Shselasky		ichreq->ch = sc->fc->it[sub]->flag & 0x3f;
568278886Shselasky		ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3;
569278886Shselasky		err = 0;
570278886Shselasky		break;
571278886Shselasky	case FW_SRSTREAM:
572278886Shselasky		sc->fc->ir[sub]->flag &= ~0xff;
573278886Shselasky		sc->fc->ir[sub]->flag |= (0x3f & ichreq->ch);
574255932Salfred		sc->fc->ir[sub]->flag |= ((0x3 & ichreq->tag) << 6);
575255932Salfred		err = sc->fc->irx_enable(sc->fc, sub);
576255932Salfred		break;
577255932Salfred	case FW_GRSTREAM:
578255932Salfred		ichreq->ch = sc->fc->ir[sub]->flag & 0x3f;
579255932Salfred		ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3;
580255932Salfred		err = 0;
581255932Salfred		break;
582255932Salfred#ifdef FWXFERQ_DV
583255932Salfred	case FW_SSTDV:
584255932Salfred		ibufreq = (struct fw_isobufreq *)
585255932Salfred			malloc(sizeof(struct fw_isobufreq), M_FW, M_NOWAIT);
586255932Salfred		if(ibufreq == NULL){
587255932Salfred			err = ENOMEM;
588255932Salfred			break;
589255932Salfred		}
590255932Salfred#if DV_PAL
591255932Salfred#define FWDVPACKET 300
592255932Salfred#else
593255932Salfred#define FWDVPACKET 250
594255932Salfred#endif
595255932Salfred#define FWDVPMAX 512
596255932Salfred		ibufreq->rx.nchunk = 8;
597255932Salfred		ibufreq->rx.npacket = 50;
598255932Salfred		ibufreq->rx.psize = FWDVPMAX;
599255932Salfred
600255932Salfred		ibufreq->tx.nchunk = 5;
601255932Salfred		ibufreq->tx.npacket = FWDVPACKET + 30;	/* > 320 or 267 */
602255932Salfred		ibufreq->tx.psize = FWDVPMAX;
603255932Salfred
604255932Salfred		err = fw_ioctl(dev, FW_SSTBUF, (caddr_t)ibufreq, flag, td);
605255932Salfred		sc->fc->it[sub]->dvpacket = FWDVPACKET;
606255932Salfred		free(ibufreq, M_FW);
607255932Salfred/* reserve a buffer space */
608255932Salfred#define NDVCHUNK 8
609255932Salfred		sc->fc->it[sub]->dvproc = NULL;
610255932Salfred		sc->fc->it[sub]->dvdma = NULL;
611255932Salfred		sc->fc->it[sub]->flag |= FWXFERQ_DV;
612255932Salfred		/* XXX check malloc failure */
613255932Salfred		sc->fc->it[sub]->dvbuf
614255932Salfred			= (struct fw_dvbuf *)malloc(sizeof(struct fw_dvbuf) * NDVCHUNK, M_FW, M_NOWAIT);
615255932Salfred		STAILQ_INIT(&sc->fc->it[sub]->dvvalid);
616255932Salfred		STAILQ_INIT(&sc->fc->it[sub]->dvfree);
617255932Salfred		for( i = 0 ; i < NDVCHUNK ; i++){
618255932Salfred			/* XXX check malloc failure */
619255932Salfred			sc->fc->it[sub]->dvbuf[i].buf
620255932Salfred				= malloc(FWDVPMAX * sc->fc->it[sub]->dvpacket, M_FW, M_NOWAIT);
621255932Salfred			STAILQ_INSERT_TAIL(&sc->fc->it[sub]->dvfree,
622255932Salfred					&sc->fc->it[sub]->dvbuf[i], link);
623255932Salfred		}
624255932Salfred		break;
625255932Salfred#endif
626255932Salfred	case FW_SSTBUF:
627255932Salfred		ir = sc->fc->ir[sub];
628255932Salfred		it = sc->fc->it[sub];
629255932Salfred
630255932Salfred		if(ir->flag & FWXFERQ_RUNNING || it->flag & FWXFERQ_RUNNING){
631255932Salfred			return(EBUSY);
632255932Salfred		}
633255932Salfred		if((ir->flag & FWXFERQ_EXTBUF) || (it->flag & FWXFERQ_EXTBUF)){
634255932Salfred			return(EBUSY);
635255932Salfred		}
636255932Salfred		if((ibufreq->rx.nchunk *
637255932Salfred			ibufreq->rx.psize * ibufreq->rx.npacket) +
638255932Salfred		   (ibufreq->tx.nchunk *
639255932Salfred			ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){
640255932Salfred				return(EINVAL);
641255932Salfred		}
642255932Salfred		if(ibufreq->rx.nchunk > FWSTMAXCHUNK ||
643255932Salfred				ibufreq->tx.nchunk > FWSTMAXCHUNK){
644255932Salfred			return(EINVAL);
645255932Salfred		}
646255932Salfred		ir->bulkxfer
647255932Salfred			= (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_FW, 0);
648255932Salfred		if(ir->bulkxfer == NULL){
649255932Salfred			return(ENOMEM);
650255932Salfred		}
651255932Salfred		it->bulkxfer
652255932Salfred			= (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_FW, 0);
653255932Salfred		if(it->bulkxfer == NULL){
654255932Salfred			return(ENOMEM);
655255932Salfred		}
656255932Salfred		ir->buf = malloc(
657255932Salfred			ibufreq->rx.nchunk * ibufreq->rx.npacket
658255932Salfred			/* XXX psize must be 2^n and less or
659255932Salfred						equal to PAGE_SIZE */
660255932Salfred			* ((ibufreq->rx.psize + 3) &~3),
661255932Salfred			M_FW, 0);
662255932Salfred		if(ir->buf == NULL){
663255932Salfred			free(ir->bulkxfer, M_FW);
664255932Salfred			free(it->bulkxfer, M_FW);
665255932Salfred			ir->bulkxfer = NULL;
666255932Salfred			it->bulkxfer = NULL;
667255932Salfred			it->buf = NULL;
668255932Salfred			return(ENOMEM);
669255932Salfred		}
670255932Salfred		it->buf = malloc(
671255932Salfred			ibufreq->tx.nchunk * ibufreq->tx.npacket
672255932Salfred			/* XXX psize must be 2^n and less or
673255932Salfred						equal to PAGE_SIZE */
674255932Salfred			* ((ibufreq->tx.psize + 3) &~3),
675255932Salfred			M_FW, 0);
676255932Salfred		if(it->buf == NULL){
677255932Salfred			free(ir->bulkxfer, M_FW);
678255932Salfred			free(it->bulkxfer, M_FW);
679255932Salfred			free(ir->buf, M_FW);
680255932Salfred			ir->bulkxfer = NULL;
681255932Salfred			it->bulkxfer = NULL;
682255932Salfred			it->buf = NULL;
683255932Salfred			return(ENOMEM);
684255932Salfred		}
685255932Salfred
686255932Salfred		ir->bnchunk = ibufreq->rx.nchunk;
687255932Salfred		ir->bnpacket = ibufreq->rx.npacket;
688255932Salfred		ir->psize = (ibufreq->rx.psize + 3) & ~3;
689255932Salfred		ir->queued = 0;
690255932Salfred
691255932Salfred		it->bnchunk = ibufreq->tx.nchunk;
692255932Salfred		it->bnpacket = ibufreq->tx.npacket;
693255932Salfred		it->psize = (ibufreq->tx.psize + 3) & ~3;
694255932Salfred		it->queued = 0;
695255932Salfred
696255932Salfred#ifdef FWXFERQ_DV
697255932Salfred		it->dvdbc = 0;
698255932Salfred		it->dvdiff = 0;
699255932Salfred		it->dvsync = 0;
700255932Salfred		it->dvoffset = 0;
701219820Sjeff#endif
702255932Salfred
703255932Salfred		STAILQ_INIT(&ir->stvalid);
704219820Sjeff		STAILQ_INIT(&ir->stfree);
705219820Sjeff		STAILQ_INIT(&ir->stdma);
706219820Sjeff		ir->stproc = NULL;
707219820Sjeff
708219820Sjeff		STAILQ_INIT(&it->stvalid);
709255932Salfred		STAILQ_INIT(&it->stfree);
710255932Salfred		STAILQ_INIT(&it->stdma);
711255932Salfred		it->stproc = NULL;
712255932Salfred
713255932Salfred		for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){
714255932Salfred			ir->bulkxfer[i].buf =
715255932Salfred				ir->buf + i * ir->bnpacket * ir->psize;
716255932Salfred			STAILQ_INSERT_TAIL(&ir->stfree,
717255932Salfred					&ir->bulkxfer[i], link);
718255932Salfred			ir->bulkxfer[i].npacket = ir->bnpacket;
719255932Salfred		}
720278886Shselasky		for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){
721278886Shselasky			it->bulkxfer[i].buf =
722255932Salfred				it->buf + i * it->bnpacket * it->psize;
723278886Shselasky			STAILQ_INSERT_TAIL(&it->stfree,
724278886Shselasky					&it->bulkxfer[i], link);
725255932Salfred			it->bulkxfer[i].npacket = it->bnpacket;
726255932Salfred		}
727255932Salfred		ir->flag &= ~FWXFERQ_MODEMASK;
728219820Sjeff		ir->flag |= FWXFERQ_STREAM;
729219820Sjeff		ir->flag |= FWXFERQ_EXTBUF;
730219820Sjeff
731219820Sjeff		it->flag &= ~FWXFERQ_MODEMASK;
732219820Sjeff		it->flag |= FWXFERQ_STREAM;
733219820Sjeff		it->flag |= FWXFERQ_EXTBUF;
734219820Sjeff		err = 0;
735219820Sjeff		break;
736219820Sjeff	case FW_GSTBUF:
737219820Sjeff		ibufreq->rx.nchunk = sc->fc->ir[sub]->bnchunk;
738219820Sjeff		ibufreq->rx.npacket = sc->fc->ir[sub]->bnpacket;
739219820Sjeff		ibufreq->rx.psize = sc->fc->ir[sub]->psize;
740219820Sjeff
741219820Sjeff		ibufreq->tx.nchunk = sc->fc->it[sub]->bnchunk;
742219820Sjeff		ibufreq->tx.npacket = sc->fc->it[sub]->bnpacket;
743255932Salfred		ibufreq->tx.psize = sc->fc->it[sub]->psize;
744219820Sjeff		break;
745255932Salfred	case FW_ASYREQ:
746219820Sjeff		xfer = fw_xfer_alloc(M_FWXFER);
747219820Sjeff		if(xfer == NULL){
748219820Sjeff			err = ENOMEM;
749219820Sjeff			return err;
750219820Sjeff		}
751219820Sjeff		fp = &asyreq->pkt;
752219820Sjeff		switch (asyreq->req.type) {
753219820Sjeff		case FWASREQNODE:
754219820Sjeff			xfer->dst = ntohs(fp->mode.hdr.dst);
755219820Sjeff			break;
756219820Sjeff		case FWASREQEUI:
757219820Sjeff			fwdev = fw_noderesolve_eui64(sc->fc,
758219820Sjeff						&asyreq->req.dst.eui);
759219820Sjeff			if (fwdev == NULL) {
760219820Sjeff				device_printf(sc->fc->bdev,
761219820Sjeff					"cannot find node\n");
762219820Sjeff				err = EINVAL;
763219820Sjeff				goto error;
764219820Sjeff			}
765255932Salfred			xfer->dst = fwdev->dst;
766255932Salfred			fp->mode.hdr.dst = htons(FWLOCALBUS | xfer->dst);
767255932Salfred			break;
768219820Sjeff		case FWASRESTL:
769219820Sjeff			/* XXX what's this? */
770219820Sjeff			break;
771219820Sjeff		case FWASREQSTREAM:
772219820Sjeff			/* nothing to do */
773255932Salfred			break;
774255932Salfred		}
775255932Salfred		xfer->spd = asyreq->req.sped;
776255932Salfred		xfer->send.len = asyreq->req.len;
777255932Salfred		xfer->send.buf = malloc(xfer->send.len, M_FW, M_NOWAIT);
778219820Sjeff		if(xfer->send.buf == NULL){
779219820Sjeff			return ENOMEM;
780219820Sjeff		}
781219820Sjeff		xfer->send.off = 0;
782219820Sjeff		bcopy(fp, xfer->send.buf, xfer->send.len);
783219820Sjeff		xfer->act.hand = fw_asy_callback;
784219820Sjeff		err = fw_asyreq(sc->fc, sub, xfer);
785219820Sjeff		if(err){
786219820Sjeff			fw_xfer_free( xfer);
787219820Sjeff			return err;
788219820Sjeff		}
789219820Sjeff		err = tsleep(xfer, FWPRI, "asyreq", hz);
790219820Sjeff		if(err == 0){
791255932Salfred			if(asyreq->req.len >= xfer->recv.len){
792255932Salfred				asyreq->req.len = xfer->recv.len;
793219820Sjeff			}else{
794255932Salfred				err = EINVAL;
795255932Salfred			}
796255932Salfred			bcopy(xfer->recv.buf + xfer->recv.off, fp, asyreq->req.len);
797255932Salfred		}
798255932Salfrederror:
799255932Salfred		fw_xfer_free( xfer);
800255932Salfred		break;
801255932Salfred	case FW_IBUSRST:
802255932Salfred		sc->fc->ibr(sc->fc);
803255932Salfred		break;
804255932Salfred	case FW_CBINDADDR:
805255932Salfred		fwb = fw_bindlookup(sc->fc,
806255932Salfred				bindreq->start.hi, bindreq->start.lo);
807255932Salfred		if(fwb == NULL){
808255932Salfred			err = EINVAL;
809255932Salfred			break;
810255932Salfred		}
811255932Salfred		STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
812255932Salfred		STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist);
813255932Salfred		free(fwb, M_FW);
814255932Salfred		break;
815255932Salfred	case FW_SBINDADDR:
816255932Salfred		if(bindreq->len <= 0 ){
817255932Salfred			err = EINVAL;
818255932Salfred			break;
819255932Salfred		}
820255932Salfred		if(bindreq->start.hi > 0xffff ){
821255932Salfred			err = EINVAL;
822255932Salfred			break;
823255932Salfred		}
824255932Salfred		fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT);
825255932Salfred		if(fwb == NULL){
826255932Salfred			err = ENOMEM;
827255932Salfred			break;
828255932Salfred		}
829255932Salfred		fwb->start_hi = bindreq->start.hi;
830255932Salfred		fwb->start_lo = bindreq->start.lo;
831255932Salfred		fwb->addrlen = bindreq->len;
832255932Salfred
833255932Salfred		xfer = fw_xfer_alloc(M_FWXFER);
834255932Salfred		if(xfer == NULL){
835255932Salfred			err = ENOMEM;
836255932Salfred			return err;
837255932Salfred		}
838255932Salfred		xfer->act_type = FWACT_CH;
839255932Salfred		xfer->sub = sub;
840255932Salfred		xfer->fc = sc->fc;
841255932Salfred
842255932Salfred		fwb->xfer = xfer;
843255932Salfred		err = fw_bindadd(sc->fc, fwb);
844255932Salfred		break;
845255932Salfred	case FW_GDEVLST:
846255932Salfred		i = len = 1;
847255932Salfred		/* myself */
848255932Salfred		devinfo = &fwdevlst->dev[0];
849255932Salfred		devinfo->dst = sc->fc->nodeid;
850255932Salfred		devinfo->status = 0;	/* XXX */
851255932Salfred		devinfo->eui.hi = sc->fc->eui.hi;
852255932Salfred		devinfo->eui.lo = sc->fc->eui.lo;
853255932Salfred		STAILQ_FOREACH(fwdev, &sc->fc->devices, link) {
854255932Salfred			if(len < FW_MAX_DEVLST){
855255932Salfred				devinfo = &fwdevlst->dev[len++];
856255932Salfred				devinfo->dst = fwdev->dst;
857255932Salfred				devinfo->status =
858255932Salfred					(fwdev->status == FWDEVINVAL)?0:1;
859255932Salfred				devinfo->eui.hi = fwdev->eui.hi;
860255932Salfred				devinfo->eui.lo = fwdev->eui.lo;
861255932Salfred			}
862255932Salfred			i++;
863255932Salfred		}
864255932Salfred		fwdevlst->n = i;
865255932Salfred		fwdevlst->info_len = len;
866255932Salfred		break;
867255932Salfred	case FW_GTPMAP:
868255932Salfred		bcopy(sc->fc->topology_map, data,
869255932Salfred				(sc->fc->topology_map->crc_len + 1) * 4);
870255932Salfred		break;
871255932Salfred	case FW_GCROM:
872255932Salfred		STAILQ_FOREACH(fwdev, &sc->fc->devices, link)
873255932Salfred			if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui))
874255932Salfred				break;
875255932Salfred		if (fwdev == NULL) {
876255932Salfred			err = FWNODE_INVAL;
877255932Salfred			break;
878255932Salfred		}
879255932Salfred#if 0
880255932Salfred		if (fwdev->csrrom[0] >> 24 == 1)
881255932Salfred			len = 4;
882255932Salfred		else
883255932Salfred			len = (1 + ((fwdev->csrrom[0] >> 16) & 0xff)) * 4;
884255932Salfred#else
885255932Salfred		if (fwdev->rommax < CSRROMOFF)
886255932Salfred			len = 0;
887255932Salfred		else
888255932Salfred			len = fwdev->rommax - CSRROMOFF + 4;
889255932Salfred#endif
890255932Salfred		if (crom_buf->len < len)
891255932Salfred			len = crom_buf->len;
892255932Salfred		else
893255932Salfred			crom_buf->len = len;
894255932Salfred		err = copyout(&fwdev->csrrom[0], crom_buf->ptr, len);
895255932Salfred		break;
896255932Salfred	default:
897255932Salfred		sc->fc->ioctl (dev, cmd, data, flag, td);
898255932Salfred		break;
899255932Salfred	}
900255932Salfred	return err;
901255932Salfred}
902255932Salfredint
903255932Salfredfw_poll(dev_t dev, int events, fw_proc *td)
904255932Salfred{
905255932Salfred	int revents;
906255932Salfred	int tmp;
907255932Salfred	int unit = DEV2UNIT(dev);
908255932Salfred	int sub = DEV2DMACH(dev);
909255932Salfred	struct firewire_softc *sc;
910255932Salfred
911255932Salfred	if (DEV_FWMEM(dev))
912255932Salfred		return fwmem_poll(dev, events, td);
913219820Sjeff
914219820Sjeff	sc = devclass_get_softc(firewire_devclass, unit);
915255932Salfred	revents = 0;
916255932Salfred	tmp = POLLIN | POLLRDNORM;
917219820Sjeff	if (events & tmp) {
918255932Salfred		if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL)
919255932Salfred			revents |= tmp;
920255932Salfred		else
921255932Salfred			selrecord(td, &sc->fc->ir[sub]->rsel);
922255932Salfred	}
923255932Salfred	tmp = POLLOUT | POLLWRNORM;
924255932Salfred	if (events & tmp) {
925255932Salfred		/* XXX should be fixed */
926255932Salfred		revents |= tmp;
927255932Salfred	}
928255932Salfred
929255932Salfred	return revents;
930255932Salfred}
931255932Salfred
932255932Salfredstatic int
933255932Salfred#if __FreeBSD_version < 500000
934255932Salfredfw_mmap (dev_t dev, vm_offset_t offset, int nproto)
935255932Salfred#else
936255932Salfredfw_mmap (dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nproto)
937255932Salfred#endif
938255932Salfred{
939219820Sjeff	struct firewire_softc *fc;
940255932Salfred	int unit = DEV2UNIT(dev);
941255932Salfred
942255932Salfred	if (DEV_FWMEM(dev))
943255932Salfred#if __FreeBSD_version < 500000
944255932Salfred		return fwmem_mmap(dev, offset, nproto);
945255932Salfred#else
946255932Salfred		return fwmem_mmap(dev, offset, paddr, nproto);
947255932Salfred#endif
948255932Salfred
949255932Salfred	fc = devclass_get_softc(firewire_devclass, unit);
950255932Salfred
951255932Salfred	return EINVAL;
952255932Salfred}
953255932Salfred