fwdev.c revision 118293
1/*
2 * Copyright (c) 2003 Hidetoshi Shimokawa
3 * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 *    must display the acknowledgement as bellow:
16 *
17 *    This product includes software developed by K. Kobayashi and H. Shimokawa
18 *
19 * 4. The name of the author may not be used to endorse or promote products
20 *    derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *
34 * $FreeBSD: head/sys/dev/firewire/fwdev.c 118293 2003-08-01 04:51:21Z simokawa $
35 *
36 */
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/types.h>
41#include <sys/mbuf.h>
42
43#include <sys/kernel.h>
44#include <sys/malloc.h>
45#include <sys/conf.h>
46#include <sys/poll.h>
47
48#include <sys/bus.h>
49#include <machine/bus.h>
50
51#include <sys/ioccom.h>
52
53#include <dev/firewire/firewire.h>
54#include <dev/firewire/firewirereg.h>
55#include <dev/firewire/fwdma.h>
56#include <dev/firewire/fwmem.h>
57#include <dev/firewire/iec68113.h>
58
59#define CDEV_MAJOR 127
60#define	FWNODE_INVAL 0xffff
61
62static	d_open_t	fw_open;
63static	d_close_t	fw_close;
64static	d_ioctl_t	fw_ioctl;
65static	d_poll_t	fw_poll;
66static	d_read_t	fw_read;	/* for Isochronous packet */
67static	d_write_t	fw_write;
68static	d_mmap_t	fw_mmap;
69
70struct cdevsw firewire_cdevsw =
71{
72#if __FreeBSD_version >= 500104
73	.d_open =	fw_open,
74	.d_close =	fw_close,
75	.d_read =	fw_read,
76	.d_write =	fw_write,
77	.d_ioctl =	fw_ioctl,
78	.d_poll =	fw_poll,
79	.d_mmap =	fw_mmap,
80	.d_name =	"fw",
81	.d_maj =	CDEV_MAJOR,
82	.d_flags =	D_MEM
83#else
84	fw_open, fw_close, fw_read, fw_write, fw_ioctl,
85	fw_poll, fw_mmap, nostrategy, "fw", CDEV_MAJOR, nodump, nopsize, D_MEM
86#endif
87};
88
89struct fw_drv1 {
90	struct fw_xferq *ir;
91	struct fw_xferq *it;
92	struct fw_isobufreq bufreq;
93};
94
95static int
96fwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q,
97	struct fw_bufspec *b)
98{
99	int i;
100
101	if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF))
102		return(EBUSY);
103
104	q->bulkxfer = (struct fw_bulkxfer *) malloc(
105		sizeof(struct fw_bulkxfer) * b->nchunk,
106		M_FW, M_WAITOK);
107	if (q->bulkxfer == NULL)
108		return(ENOMEM);
109
110	b->psize = roundup2(b->psize, sizeof(u_int32_t));
111	q->buf = fwdma_malloc_multiseg(fc, sizeof(u_int32_t),
112			b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK);
113
114	if (q->buf == NULL) {
115		free(q->bulkxfer, M_FW);
116		q->bulkxfer = NULL;
117		return(ENOMEM);
118	}
119	q->bnchunk = b->nchunk;
120	q->bnpacket = b->npacket;
121	q->psize = (b->psize + 3) & ~3;
122	q->queued = 0;
123
124	STAILQ_INIT(&q->stvalid);
125	STAILQ_INIT(&q->stfree);
126	STAILQ_INIT(&q->stdma);
127	q->stproc = NULL;
128
129	for(i = 0 ; i < q->bnchunk; i++){
130		q->bulkxfer[i].poffset = i * q->bnpacket;
131		q->bulkxfer[i].mbuf = NULL;
132		STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link);
133	}
134
135	q->flag &= ~FWXFERQ_MODEMASK;
136	q->flag |= FWXFERQ_STREAM;
137	q->flag |= FWXFERQ_EXTBUF;
138
139	return (0);
140}
141
142static int
143fwdev_freebuf(struct fw_xferq *q)
144{
145	if (q->flag & FWXFERQ_EXTBUF) {
146		if (q->buf != NULL)
147			fwdma_free_multiseg(q->buf);
148		q->buf = NULL;
149		free(q->bulkxfer, M_FW);
150		q->bulkxfer = NULL;
151		q->flag &= ~FWXFERQ_EXTBUF;
152		q->psize = 0;
153		q->maxq = FWMAXQUEUE;
154	}
155	return (0);
156}
157
158
159static int
160fw_open (dev_t dev, int flags, int fmt, fw_proc *td)
161{
162	int unit = DEV2UNIT(dev);
163	int sub = DEV2SUB(dev);
164
165	int err = 0;
166
167	if (dev->si_drv1 != NULL)
168		return (EBUSY);
169
170	if (DEV_FWMEM(dev))
171		return fwmem_open(dev, flags, fmt, td);
172
173#if __FreeBSD_version >= 500000
174	if ((dev->si_flags & SI_NAMED) == 0)
175#endif
176		make_dev(&firewire_cdevsw, minor(dev),
177			UID_ROOT, GID_OPERATOR, 0660,
178			"fw%d.%d", unit, sub);
179
180	dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO);
181
182	return err;
183}
184
185static int
186fw_close (dev_t dev, int flags, int fmt, fw_proc *td)
187{
188	struct firewire_softc *sc;
189	struct firewire_comm *fc;
190	struct fw_drv1 *d;
191	int unit = DEV2UNIT(dev);
192	struct fw_xfer *xfer;
193	struct fw_bind *fwb;
194	int err = 0;
195
196	if (DEV_FWMEM(dev))
197		return fwmem_close(dev, flags, fmt, td);
198
199	sc = devclass_get_softc(firewire_devclass, unit);
200	fc = sc->fc;
201	d = (struct fw_drv1 *)dev->si_drv1;
202
203	if (d->ir != NULL) {
204		struct fw_xferq *ir = d->ir;
205
206		if ((ir->flag & FWXFERQ_OPEN) == 0)
207			return (EINVAL);
208		if (ir->flag & FWXFERQ_RUNNING) {
209			ir->flag &= ~FWXFERQ_RUNNING;
210			fc->irx_disable(fc, ir->dmach);
211		}
212		/* free extbuf */
213		fwdev_freebuf(ir);
214		/* drain receiving buffer */
215		for (xfer = STAILQ_FIRST(&ir->q);
216			xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) {
217			ir->queued --;
218			STAILQ_REMOVE_HEAD(&ir->q, link);
219
220			xfer->resp = 0;
221			fw_xfer_done(xfer);
222		}
223		/* remove binding */
224		for (fwb = STAILQ_FIRST(&ir->binds); fwb != NULL;
225				fwb = STAILQ_FIRST(&ir->binds)) {
226			STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist);
227			STAILQ_REMOVE_HEAD(&ir->binds, chlist);
228			free(fwb, M_FW);
229		}
230		ir->flag &= ~(FWXFERQ_OPEN |
231			FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
232		d->ir = NULL;
233
234	}
235	if (d->it != NULL) {
236		struct fw_xferq *it = d->it;
237
238		if ((it->flag & FWXFERQ_OPEN) == 0)
239			return (EINVAL);
240		if (it->flag & FWXFERQ_RUNNING) {
241			it->flag &= ~FWXFERQ_RUNNING;
242			fc->itx_disable(fc, it->dmach);
243		}
244		/* free extbuf */
245		fwdev_freebuf(it);
246		it->flag &= ~(FWXFERQ_OPEN |
247			FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
248		d->it = NULL;
249	}
250	free(dev->si_drv1, M_FW);
251	dev->si_drv1 = NULL;
252
253	return err;
254}
255
256/*
257 * read request.
258 */
259static int
260fw_read (dev_t dev, struct uio *uio, int ioflag)
261{
262	struct firewire_softc *sc;
263	struct fw_xferq *ir;
264	struct fw_xfer *xfer;
265	int err = 0, s, slept = 0;
266	int unit = DEV2UNIT(dev);
267	struct fw_pkt *fp;
268
269	if (DEV_FWMEM(dev))
270		return fwmem_read(dev, uio, ioflag);
271
272	sc = devclass_get_softc(firewire_devclass, unit);
273
274	ir = ((struct fw_drv1 *)dev->si_drv1)->ir;
275	if (ir == NULL || ir->buf == NULL)
276		return (EIO);
277
278readloop:
279	xfer = STAILQ_FIRST(&ir->q);
280	if (ir->stproc == NULL) {
281		/* iso bulkxfer */
282		ir->stproc = STAILQ_FIRST(&ir->stvalid);
283		if (ir->stproc != NULL) {
284			s = splfw();
285			STAILQ_REMOVE_HEAD(&ir->stvalid, link);
286			splx(s);
287			ir->queued = 0;
288		}
289	}
290	if (xfer == NULL && ir->stproc == NULL) {
291		/* no data avaliable */
292		if (slept == 0) {
293			slept = 1;
294			ir->flag |= FWXFERQ_WAKEUP;
295			err = tsleep(ir, FWPRI, "fw_read", hz);
296			ir->flag &= ~FWXFERQ_WAKEUP;
297			if (err == 0)
298				goto readloop;
299		} else if (slept == 1)
300			err = EIO;
301		return err;
302	} else if(xfer != NULL) {
303		/* per packet mode or FWACT_CH bind?*/
304		s = splfw();
305		ir->queued --;
306		STAILQ_REMOVE_HEAD(&ir->q, link);
307		splx(s);
308		fp = (struct fw_pkt *)xfer->recv.buf;
309		if(sc->fc->irx_post != NULL)
310			sc->fc->irx_post(sc->fc, fp->mode.ld);
311		err = uiomove(xfer->recv.buf, xfer->recv.len, uio);
312		/* XXX we should recycle this xfer */
313		fw_xfer_free( xfer);
314	} else if(ir->stproc != NULL) {
315		/* iso bulkxfer */
316		fp = (struct fw_pkt *)fwdma_v_addr(ir->buf,
317				ir->stproc->poffset + ir->queued);
318		if(sc->fc->irx_post != NULL)
319			sc->fc->irx_post(sc->fc, fp->mode.ld);
320		if(fp->mode.stream.len == 0){
321			err = EIO;
322			return err;
323		}
324		err = uiomove((caddr_t)fp,
325			fp->mode.stream.len + sizeof(u_int32_t), uio);
326		ir->queued ++;
327		if(ir->queued >= ir->bnpacket){
328			s = splfw();
329			STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link);
330			splx(s);
331			sc->fc->irx_enable(sc->fc, ir->dmach);
332			ir->stproc = NULL;
333		}
334		if (uio->uio_resid >= ir->psize) {
335			slept = -1;
336			goto readloop;
337		}
338	}
339	return err;
340}
341
342static int
343fw_write (dev_t dev, struct uio *uio, int ioflag)
344{
345	int err = 0;
346	struct firewire_softc *sc;
347	int unit = DEV2UNIT(dev);
348	int s, slept = 0;
349	struct fw_pkt *fp;
350	struct firewire_comm *fc;
351	struct fw_xferq *it;
352
353	if (DEV_FWMEM(dev))
354		return fwmem_write(dev, uio, ioflag);
355
356	sc = devclass_get_softc(firewire_devclass, unit);
357	fc = sc->fc;
358	it = ((struct fw_drv1 *)dev->si_drv1)->it;
359	if (it == NULL || it->buf == NULL)
360		return (EIO);
361isoloop:
362	if (it->stproc == NULL) {
363		it->stproc = STAILQ_FIRST(&it->stfree);
364		if (it->stproc != NULL) {
365			s = splfw();
366			STAILQ_REMOVE_HEAD(&it->stfree, link);
367			splx(s);
368			it->queued = 0;
369		} else if (slept == 0) {
370			slept = 1;
371			err = sc->fc->itx_enable(sc->fc, it->dmach);
372			if (err)
373				return err;
374			err = tsleep(it, FWPRI, "fw_write", hz);
375			if (err)
376				return err;
377			goto isoloop;
378		} else {
379			err = EIO;
380			return err;
381		}
382	}
383	fp = (struct fw_pkt *)fwdma_v_addr(it->buf,
384			it->stproc->poffset + it->queued);
385	err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio);
386	err = uiomove((caddr_t)fp->mode.stream.payload,
387				fp->mode.stream.len, uio);
388	it->queued ++;
389	if (it->queued >= it->bnpacket) {
390		s = splfw();
391		STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
392		splx(s);
393		it->stproc = NULL;
394		err = sc->fc->itx_enable(sc->fc, it->dmach);
395	}
396	if (uio->uio_resid >= sizeof(struct fw_isohdr)) {
397		slept = 0;
398		goto isoloop;
399	}
400	return err;
401}
402/*
403 * ioctl support.
404 */
405int
406fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
407{
408	struct firewire_softc *sc;
409	struct firewire_comm *fc;
410	struct fw_drv1 *d;
411	int unit = DEV2UNIT(dev);
412	int s, i, len, err = 0;
413	struct fw_device *fwdev;
414	struct fw_bind *fwb;
415	struct fw_xferq *ir, *it;
416	struct fw_xfer *xfer;
417	struct fw_pkt *fp;
418	struct fw_devinfo *devinfo;
419	void *ptr;
420
421	struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data;
422	struct fw_asyreq *asyreq = (struct fw_asyreq *)data;
423	struct fw_isochreq *ichreq = (struct fw_isochreq *)data;
424	struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data;
425	struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data;
426	struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data;
427
428	if (DEV_FWMEM(dev))
429		return fwmem_ioctl(dev, cmd, data, flag, td);
430
431	if (!data)
432		return(EINVAL);
433
434	sc = devclass_get_softc(firewire_devclass, unit);
435	fc = sc->fc;
436	d = (struct fw_drv1 *)dev->si_drv1;
437	ir = d->ir;
438	it = d->it;
439
440	switch (cmd) {
441	case FW_STSTREAM:
442		if (it == NULL) {
443			for (i = 0; i < fc->nisodma; i ++) {
444				it = fc->it[i];
445				if ((it->flag & FWXFERQ_OPEN) == 0)
446					 break;
447	                }
448			if (i >= fc->nisodma) {
449				err = EBUSY;
450				break;
451			}
452			err = fwdev_allocbuf(fc, it, &d->bufreq.tx);
453			if (err)
454				break;
455			it->flag |=  FWXFERQ_OPEN;
456		}
457		it->flag &= ~0xff;
458		it->flag |= (0x3f & ichreq->ch);
459		it->flag |= ((0x3 & ichreq->tag) << 6);
460		d->it = it;
461		err = 0;
462		break;
463	case FW_GTSTREAM:
464		if (it != NULL) {
465			ichreq->ch = it->flag & 0x3f;
466			ichreq->tag = it->flag >> 2 & 0x3;
467			err = 0;
468		} else
469			err = EINVAL;
470		break;
471	case FW_SRSTREAM:
472		if (ir == NULL) {
473			for (i = 0; i < fc->nisodma; i ++) {
474				ir = fc->ir[i];
475				if ((ir->flag & FWXFERQ_OPEN) == 0)
476					break;
477			}
478			if (i >= fc->nisodma) {
479				err = EBUSY;
480				break;
481			}
482			err = fwdev_allocbuf(fc, ir, &d->bufreq.rx);
483			if (err)
484				break;
485			ir->flag |=  FWXFERQ_OPEN;
486		}
487		ir->flag &= ~0xff;
488		ir->flag |= (0x3f & ichreq->ch);
489		ir->flag |= ((0x3 & ichreq->tag) << 6);
490		d->ir = ir;
491		err = fc->irx_enable(fc, ir->dmach);
492		break;
493	case FW_GRSTREAM:
494		if (d->ir != NULL) {
495			ichreq->ch = ir->flag & 0x3f;
496			ichreq->tag = ir->flag >> 2 & 0x3;
497			err = 0;
498		} else
499			err = EINVAL;
500		break;
501	case FW_SSTBUF:
502		bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq));
503		err = 0;
504		break;
505	case FW_GSTBUF:
506		bzero(&ibufreq->rx, sizeof(ibufreq->rx));
507		if (ir != NULL) {
508			ibufreq->rx.nchunk = ir->bnchunk;
509			ibufreq->rx.npacket = ir->bnpacket;
510			ibufreq->rx.psize = ir->psize;
511		}
512		bzero(&ibufreq->tx, sizeof(ibufreq->tx));
513		if (it != NULL) {
514			ibufreq->tx.nchunk = it->bnchunk;
515			ibufreq->tx.npacket = it->bnpacket;
516			ibufreq->tx.psize = it->psize;
517		}
518		break;
519	case FW_ASYREQ:
520		xfer = fw_xfer_alloc_buf(M_FWXFER, asyreq->req.len,
521							PAGE_SIZE /* XXX */);
522		if(xfer == NULL){
523			err = ENOMEM;
524			return err;
525		}
526		fp = &asyreq->pkt;
527		switch (asyreq->req.type) {
528		case FWASREQNODE:
529			xfer->dst = fp->mode.hdr.dst;
530			break;
531		case FWASREQEUI:
532			fwdev = fw_noderesolve_eui64(sc->fc,
533						&asyreq->req.dst.eui);
534			if (fwdev == NULL) {
535				device_printf(sc->fc->bdev,
536					"cannot find node\n");
537				err = EINVAL;
538				goto error;
539			}
540			xfer->dst = FWLOCALBUS | fwdev->dst;
541			fp->mode.hdr.dst = xfer->dst;
542			break;
543		case FWASRESTL:
544			/* XXX what's this? */
545			break;
546		case FWASREQSTREAM:
547			/* nothing to do */
548			break;
549		}
550		xfer->spd = asyreq->req.sped;
551		bcopy(fp, xfer->send.buf, xfer->send.len);
552		xfer->act.hand = fw_asy_callback;
553		err = fw_asyreq(sc->fc, -1, xfer);
554		if(err){
555			fw_xfer_free( xfer);
556			return err;
557		}
558		err = tsleep(xfer, FWPRI, "asyreq", hz);
559		if(err == 0){
560			if(asyreq->req.len >= xfer->recv.len){
561				asyreq->req.len = xfer->recv.len;
562			}else{
563				err = EINVAL;
564			}
565			bcopy(xfer->recv.buf, fp, asyreq->req.len);
566		}
567error:
568		fw_xfer_free( xfer);
569		break;
570	case FW_IBUSRST:
571		sc->fc->ibr(sc->fc);
572		break;
573	case FW_CBINDADDR:
574		fwb = fw_bindlookup(sc->fc,
575				bindreq->start.hi, bindreq->start.lo);
576		if(fwb == NULL){
577			err = EINVAL;
578			break;
579		}
580		STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
581		STAILQ_REMOVE(&ir->binds, fwb, fw_bind, chlist);
582		free(fwb, M_FW);
583		break;
584	case FW_SBINDADDR:
585		if(bindreq->len <= 0 ){
586			err = EINVAL;
587			break;
588		}
589		if(bindreq->start.hi > 0xffff ){
590			err = EINVAL;
591			break;
592		}
593		fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT);
594		if(fwb == NULL){
595			err = ENOMEM;
596			break;
597		}
598		fwb->start_hi = bindreq->start.hi;
599		fwb->start_lo = bindreq->start.lo;
600		fwb->addrlen = bindreq->len;
601		/* XXX */
602		fwb->sub = ir->dmach;
603		fwb->act_type = FWACT_CH;
604
605		xfer = fw_xfer_alloc(M_FWXFER);
606		if(xfer == NULL){
607			err = ENOMEM;
608			return err;
609		}
610		xfer->fc = sc->fc;
611
612		s = splfw();
613		/* XXX broken. need multiple xfer */
614		STAILQ_INIT(&fwb->xferlist);
615		STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link);
616		splx(s);
617		err = fw_bindadd(sc->fc, fwb);
618		break;
619	case FW_GDEVLST:
620		i = len = 1;
621		/* myself */
622		devinfo = &fwdevlst->dev[0];
623		devinfo->dst = sc->fc->nodeid;
624		devinfo->status = 0;	/* XXX */
625		devinfo->eui.hi = sc->fc->eui.hi;
626		devinfo->eui.lo = sc->fc->eui.lo;
627		STAILQ_FOREACH(fwdev, &sc->fc->devices, link) {
628			if(len < FW_MAX_DEVLST){
629				devinfo = &fwdevlst->dev[len++];
630				devinfo->dst = fwdev->dst;
631				devinfo->status =
632					(fwdev->status == FWDEVINVAL)?0:1;
633				devinfo->eui.hi = fwdev->eui.hi;
634				devinfo->eui.lo = fwdev->eui.lo;
635			}
636			i++;
637		}
638		fwdevlst->n = i;
639		fwdevlst->info_len = len;
640		break;
641	case FW_GTPMAP:
642		bcopy(sc->fc->topology_map, data,
643				(sc->fc->topology_map->crc_len + 1) * 4);
644		break;
645	case FW_GCROM:
646		STAILQ_FOREACH(fwdev, &sc->fc->devices, link)
647			if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui))
648				break;
649		if (fwdev == NULL) {
650			if (!FW_EUI64_EQUAL(sc->fc->eui, crom_buf->eui)) {
651				err = FWNODE_INVAL;
652				break;
653			}
654			/* myself */
655			ptr = malloc(CROMSIZE, M_FW, M_WAITOK);
656			len = CROMSIZE;
657			for (i = 0; i < CROMSIZE/4; i++)
658				((u_int32_t *)ptr)[i]
659					= ntohl(sc->fc->config_rom[i]);
660		} else {
661			/* found */
662			ptr = (void *)&fwdev->csrrom[0];
663			if (fwdev->rommax < CSRROMOFF)
664				len = 0;
665			else
666				len = fwdev->rommax - CSRROMOFF + 4;
667		}
668		if (crom_buf->len < len)
669			len = crom_buf->len;
670		else
671			crom_buf->len = len;
672		err = copyout(ptr, crom_buf->ptr, len);
673		if (fwdev == NULL)
674			/* myself */
675			free(ptr, M_FW);
676		break;
677	default:
678		sc->fc->ioctl (dev, cmd, data, flag, td);
679		break;
680	}
681	return err;
682}
683int
684fw_poll(dev_t dev, int events, fw_proc *td)
685{
686	struct firewire_softc *sc;
687	struct fw_xferq *ir;
688	int revents;
689	int tmp;
690	int unit = DEV2UNIT(dev);
691
692	if (DEV_FWMEM(dev))
693		return fwmem_poll(dev, events, td);
694
695	sc = devclass_get_softc(firewire_devclass, unit);
696	ir = ((struct fw_drv1 *)dev->si_drv1)->ir;
697	revents = 0;
698	tmp = POLLIN | POLLRDNORM;
699	if (events & tmp) {
700		if (STAILQ_FIRST(&ir->q) != NULL)
701			revents |= tmp;
702		else
703			selrecord(td, &ir->rsel);
704	}
705	tmp = POLLOUT | POLLWRNORM;
706	if (events & tmp) {
707		/* XXX should be fixed */
708		revents |= tmp;
709	}
710
711	return revents;
712}
713
714static int
715#if __FreeBSD_version < 500102
716fw_mmap (dev_t dev, vm_offset_t offset, int nproto)
717#else
718fw_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto)
719#endif
720{
721	struct firewire_softc *fc;
722	int unit = DEV2UNIT(dev);
723
724	if (DEV_FWMEM(dev))
725#if __FreeBSD_version < 500102
726		return fwmem_mmap(dev, offset, nproto);
727#else
728		return fwmem_mmap(dev, offset, paddr, nproto);
729#endif
730
731	fc = devclass_get_softc(firewire_devclass, unit);
732
733	return EINVAL;
734}
735