fwdev.c revision 255359
1139749Simp/*-
2113584Ssimokawa * Copyright (c) 2003 Hidetoshi Shimokawa
3106813Ssimokawa * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
4106813Ssimokawa * All rights reserved.
5106813Ssimokawa *
6106813Ssimokawa * Redistribution and use in source and binary forms, with or without
7106813Ssimokawa * modification, are permitted provided that the following conditions
8106813Ssimokawa * are met:
9106813Ssimokawa * 1. Redistributions of source code must retain the above copyright
10106813Ssimokawa *    notice, this list of conditions and the following disclaimer.
11106813Ssimokawa * 2. Redistributions in binary form must reproduce the above copyright
12106813Ssimokawa *    notice, this list of conditions and the following disclaimer in the
13106813Ssimokawa *    documentation and/or other materials provided with the distribution.
14106813Ssimokawa * 3. All advertising materials mentioning features or use of this software
15106813Ssimokawa *    must display the acknowledgement as bellow:
16106813Ssimokawa *
17106813Ssimokawa *    This product includes software developed by K. Kobayashi and H. Shimokawa
18106813Ssimokawa *
19106813Ssimokawa * 4. The name of the author may not be used to endorse or promote products
20106813Ssimokawa *    derived from this software without specific prior written permission.
21106813Ssimokawa *
22106813Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23106813Ssimokawa * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24106813Ssimokawa * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25106813Ssimokawa * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
26106813Ssimokawa * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27106813Ssimokawa * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28106813Ssimokawa * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29106813Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30106813Ssimokawa * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31106813Ssimokawa * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32106813Ssimokawa * POSSIBILITY OF SUCH DAMAGE.
33106813Ssimokawa *
34106813Ssimokawa * $FreeBSD: head/sys/dev/firewire/fwdev.c 255359 2013-09-07 13:45:44Z davide $
35106813Ssimokawa *
36106813Ssimokawa */
37106813Ssimokawa
38106813Ssimokawa#include <sys/param.h>
39106813Ssimokawa#include <sys/systm.h>
40106813Ssimokawa#include <sys/types.h>
41106813Ssimokawa#include <sys/mbuf.h>
42127468Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500000
43120660Ssimokawa#include <sys/buf.h>
44120660Ssimokawa#else
45120660Ssimokawa#include <sys/bio.h>
46120660Ssimokawa#endif
47106813Ssimokawa
48106813Ssimokawa#include <sys/kernel.h>
49106813Ssimokawa#include <sys/malloc.h>
50106813Ssimokawa#include <sys/conf.h>
51106813Ssimokawa#include <sys/poll.h>
52106813Ssimokawa
53106813Ssimokawa#include <sys/bus.h>
54118455Ssimokawa#include <sys/ctype.h>
55113584Ssimokawa#include <machine/bus.h>
56106813Ssimokawa
57106813Ssimokawa#include <sys/ioccom.h>
58106813Ssimokawa
59127468Ssimokawa#ifdef __DragonFly__
60127468Ssimokawa#include "firewire.h"
61127468Ssimokawa#include "firewirereg.h"
62127468Ssimokawa#include "fwdma.h"
63127468Ssimokawa#include "fwmem.h"
64127468Ssimokawa#include "iec68113.h"
65127468Ssimokawa#else
66106813Ssimokawa#include <dev/firewire/firewire.h>
67106813Ssimokawa#include <dev/firewire/firewirereg.h>
68113584Ssimokawa#include <dev/firewire/fwdma.h>
69106813Ssimokawa#include <dev/firewire/fwmem.h>
70109282Ssimokawa#include <dev/firewire/iec68113.h>
71127468Ssimokawa#endif
72106813Ssimokawa
73106813Ssimokawa#define	FWNODE_INVAL 0xffff
74106813Ssimokawa
75106813Ssimokawastatic	d_open_t	fw_open;
76106813Ssimokawastatic	d_close_t	fw_close;
77106813Ssimokawastatic	d_ioctl_t	fw_ioctl;
78106813Ssimokawastatic	d_poll_t	fw_poll;
79106813Ssimokawastatic	d_read_t	fw_read;	/* for Isochronous packet */
80106813Ssimokawastatic	d_write_t	fw_write;
81106813Ssimokawastatic	d_mmap_t	fw_mmap;
82120660Ssimokawastatic	d_strategy_t	fw_strategy;
83106813Ssimokawa
84126080Sphkstruct cdevsw firewire_cdevsw = {
85127468Ssimokawa#ifdef __DragonFly__
86127468Ssimokawa#define CDEV_MAJOR 127
87127468Ssimokawa	"fw", CDEV_MAJOR, D_MEM, NULL, 0,
88127468Ssimokawa	fw_open, fw_close, fw_read, fw_write, fw_ioctl,
89127468Ssimokawa	fw_poll, fw_mmap, fw_strategy, nodump, nopsize,
90127468Ssimokawa#elif __FreeBSD_version >= 500104
91126080Sphk	.d_version =	D_VERSION,
92111815Sphk	.d_open =	fw_open,
93111815Sphk	.d_close =	fw_close,
94111815Sphk	.d_read =	fw_read,
95111815Sphk	.d_write =	fw_write,
96111815Sphk	.d_ioctl =	fw_ioctl,
97111815Sphk	.d_poll =	fw_poll,
98111815Sphk	.d_mmap =	fw_mmap,
99120660Ssimokawa	.d_strategy =	fw_strategy,
100111815Sphk	.d_name =	"fw",
101170374Ssimokawa	.d_flags =	D_MEM
102111942Ssimokawa#else
103127468Ssimokawa#define CDEV_MAJOR 127
104111942Ssimokawa	fw_open, fw_close, fw_read, fw_write, fw_ioctl,
105120660Ssimokawa	fw_poll, fw_mmap, fw_strategy, "fw", CDEV_MAJOR,
106118455Ssimokawa	nodump, nopsize, D_MEM, -1
107111942Ssimokawa#endif
108106813Ssimokawa};
109106813Ssimokawa
110118293Ssimokawastruct fw_drv1 {
111169130Ssimokawa	struct firewire_comm *fc;
112118293Ssimokawa	struct fw_xferq *ir;
113118293Ssimokawa	struct fw_xferq *it;
114118293Ssimokawa	struct fw_isobufreq bufreq;
115169130Ssimokawa	STAILQ_HEAD(, fw_bind) binds;
116169130Ssimokawa	STAILQ_HEAD(, fw_xfer) rq;
117118293Ssimokawa};
118118293Ssimokawa
119106813Ssimokawastatic int
120118293Ssimokawafwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q,
121118293Ssimokawa	struct fw_bufspec *b)
122118293Ssimokawa{
123118293Ssimokawa	int i;
124118293Ssimokawa
125118293Ssimokawa	if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF))
126118293Ssimokawa		return(EBUSY);
127118293Ssimokawa
128118293Ssimokawa	q->bulkxfer = (struct fw_bulkxfer *) malloc(
129118293Ssimokawa		sizeof(struct fw_bulkxfer) * b->nchunk,
130118293Ssimokawa		M_FW, M_WAITOK);
131118293Ssimokawa	if (q->bulkxfer == NULL)
132118293Ssimokawa		return(ENOMEM);
133118293Ssimokawa
134129585Sdfr	b->psize = roundup2(b->psize, sizeof(uint32_t));
135129585Sdfr	q->buf = fwdma_malloc_multiseg(fc, sizeof(uint32_t),
136118293Ssimokawa			b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK);
137118293Ssimokawa
138118293Ssimokawa	if (q->buf == NULL) {
139118293Ssimokawa		free(q->bulkxfer, M_FW);
140118293Ssimokawa		q->bulkxfer = NULL;
141118293Ssimokawa		return(ENOMEM);
142118293Ssimokawa	}
143118293Ssimokawa	q->bnchunk = b->nchunk;
144118293Ssimokawa	q->bnpacket = b->npacket;
145118293Ssimokawa	q->psize = (b->psize + 3) & ~3;
146118293Ssimokawa	q->queued = 0;
147118293Ssimokawa
148118293Ssimokawa	STAILQ_INIT(&q->stvalid);
149118293Ssimokawa	STAILQ_INIT(&q->stfree);
150118293Ssimokawa	STAILQ_INIT(&q->stdma);
151118293Ssimokawa	q->stproc = NULL;
152118293Ssimokawa
153118293Ssimokawa	for(i = 0 ; i < q->bnchunk; i++){
154118293Ssimokawa		q->bulkxfer[i].poffset = i * q->bnpacket;
155118293Ssimokawa		q->bulkxfer[i].mbuf = NULL;
156118293Ssimokawa		STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link);
157118293Ssimokawa	}
158118293Ssimokawa
159118293Ssimokawa	q->flag &= ~FWXFERQ_MODEMASK;
160118293Ssimokawa	q->flag |= FWXFERQ_STREAM;
161118293Ssimokawa	q->flag |= FWXFERQ_EXTBUF;
162118293Ssimokawa
163118293Ssimokawa	return (0);
164118293Ssimokawa}
165118293Ssimokawa
166118293Ssimokawastatic int
167118293Ssimokawafwdev_freebuf(struct fw_xferq *q)
168118293Ssimokawa{
169118293Ssimokawa	if (q->flag & FWXFERQ_EXTBUF) {
170118293Ssimokawa		if (q->buf != NULL)
171118293Ssimokawa			fwdma_free_multiseg(q->buf);
172118293Ssimokawa		q->buf = NULL;
173118293Ssimokawa		free(q->bulkxfer, M_FW);
174118293Ssimokawa		q->bulkxfer = NULL;
175118293Ssimokawa		q->flag &= ~FWXFERQ_EXTBUF;
176118293Ssimokawa		q->psize = 0;
177118293Ssimokawa		q->maxq = FWMAXQUEUE;
178118293Ssimokawa	}
179118293Ssimokawa	return (0);
180118293Ssimokawa}
181118293Ssimokawa
182118293Ssimokawa
183118293Ssimokawastatic int
184130585Sphkfw_open (struct cdev *dev, int flags, int fmt, fw_proc *td)
185106813Ssimokawa{
186106813Ssimokawa	int err = 0;
187169130Ssimokawa	int unit = DEV2UNIT(dev);
188169130Ssimokawa	struct fw_drv1 *d;
189169130Ssimokawa	struct firewire_softc *sc;
190106813Ssimokawa
191122227Ssimokawa	if (DEV_FWMEM(dev))
192122227Ssimokawa		return fwmem_open(dev, flags, fmt, td);
193122227Ssimokawa
194170374Ssimokawa	sc = devclass_get_softc(firewire_devclass, unit);
195170374Ssimokawa	if (sc == NULL)
196170374Ssimokawa		return (ENXIO);
197170374Ssimokawa
198170374Ssimokawa	FW_GLOCK(sc->fc);
199170374Ssimokawa	if (dev->si_drv1 != NULL) {
200170374Ssimokawa		FW_GUNLOCK(sc->fc);
201118293Ssimokawa		return (EBUSY);
202170374Ssimokawa	}
203170374Ssimokawa	/* set dummy value for allocation */
204170374Ssimokawa	dev->si_drv1 = (void *)-1;
205170374Ssimokawa	FW_GUNLOCK(sc->fc);
206118293Ssimokawa
207170374Ssimokawa	dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO);
208170374Ssimokawa	if (dev->si_drv1 == NULL)
209170374Ssimokawa		return (ENOMEM);
210170374Ssimokawa
211127468Ssimokawa#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
212118455Ssimokawa	if ((dev->si_flags & SI_NAMED) == 0) {
213118455Ssimokawa		int unit = DEV2UNIT(dev);
214118455Ssimokawa		int sub = DEV2SUB(dev);
215118455Ssimokawa
216183397Sed		make_dev(&firewire_cdevsw, dev2unit(dev),
217118293Ssimokawa			UID_ROOT, GID_OPERATOR, 0660,
218118293Ssimokawa			"fw%d.%d", unit, sub);
219118455Ssimokawa	}
220118455Ssimokawa#endif
221169130Ssimokawa	d = (struct fw_drv1 *)dev->si_drv1;
222169130Ssimokawa	d->fc = sc->fc;
223169130Ssimokawa	STAILQ_INIT(&d->binds);
224169130Ssimokawa	STAILQ_INIT(&d->rq);
225169130Ssimokawa
226106813Ssimokawa	return err;
227106813Ssimokawa}
228106813Ssimokawa
229106813Ssimokawastatic int
230130585Sphkfw_close (struct cdev *dev, int flags, int fmt, fw_proc *td)
231106813Ssimokawa{
232118293Ssimokawa	struct firewire_comm *fc;
233118293Ssimokawa	struct fw_drv1 *d;
234106813Ssimokawa	struct fw_xfer *xfer;
235106813Ssimokawa	struct fw_bind *fwb;
236106813Ssimokawa	int err = 0;
237106813Ssimokawa
238106813Ssimokawa	if (DEV_FWMEM(dev))
239106813Ssimokawa		return fwmem_close(dev, flags, fmt, td);
240106813Ssimokawa
241118293Ssimokawa	d = (struct fw_drv1 *)dev->si_drv1;
242169130Ssimokawa	fc = d->fc;
243118293Ssimokawa
244169130Ssimokawa	/* remove binding */
245169130Ssimokawa	for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL;
246169130Ssimokawa			fwb = STAILQ_FIRST(&d->binds)) {
247169130Ssimokawa		fw_bindremove(fc, fwb);
248169130Ssimokawa		STAILQ_REMOVE_HEAD(&d->binds, chlist);
249169130Ssimokawa		fw_xferlist_remove(&fwb->xferlist);
250169130Ssimokawa		free(fwb, M_FW);
251169130Ssimokawa	}
252118293Ssimokawa	if (d->ir != NULL) {
253118293Ssimokawa		struct fw_xferq *ir = d->ir;
254118293Ssimokawa
255118293Ssimokawa		if ((ir->flag & FWXFERQ_OPEN) == 0)
256118293Ssimokawa			return (EINVAL);
257118293Ssimokawa		if (ir->flag & FWXFERQ_RUNNING) {
258118293Ssimokawa			ir->flag &= ~FWXFERQ_RUNNING;
259118293Ssimokawa			fc->irx_disable(fc, ir->dmach);
260118293Ssimokawa		}
261118293Ssimokawa		/* free extbuf */
262118293Ssimokawa		fwdev_freebuf(ir);
263118293Ssimokawa		/* drain receiving buffer */
264118293Ssimokawa		for (xfer = STAILQ_FIRST(&ir->q);
265118293Ssimokawa			xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) {
266118293Ssimokawa			ir->queued --;
267118293Ssimokawa			STAILQ_REMOVE_HEAD(&ir->q, link);
268118293Ssimokawa
269118293Ssimokawa			xfer->resp = 0;
270118293Ssimokawa			fw_xfer_done(xfer);
271118293Ssimokawa		}
272118293Ssimokawa		ir->flag &= ~(FWXFERQ_OPEN |
273118293Ssimokawa			FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
274118293Ssimokawa		d->ir = NULL;
275118293Ssimokawa
276106813Ssimokawa	}
277118293Ssimokawa	if (d->it != NULL) {
278118293Ssimokawa		struct fw_xferq *it = d->it;
279106813Ssimokawa
280118293Ssimokawa		if ((it->flag & FWXFERQ_OPEN) == 0)
281118293Ssimokawa			return (EINVAL);
282118293Ssimokawa		if (it->flag & FWXFERQ_RUNNING) {
283118293Ssimokawa			it->flag &= ~FWXFERQ_RUNNING;
284118293Ssimokawa			fc->itx_disable(fc, it->dmach);
285118293Ssimokawa		}
286118293Ssimokawa		/* free extbuf */
287118293Ssimokawa		fwdev_freebuf(it);
288118293Ssimokawa		it->flag &= ~(FWXFERQ_OPEN |
289118293Ssimokawa			FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
290118293Ssimokawa		d->it = NULL;
291106813Ssimokawa	}
292118293Ssimokawa	free(dev->si_drv1, M_FW);
293118293Ssimokawa	dev->si_drv1 = NULL;
294106813Ssimokawa
295106813Ssimokawa	return err;
296106813Ssimokawa}
297106813Ssimokawa
298169130Ssimokawastatic int
299169130Ssimokawafw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag)
300169130Ssimokawa{
301169130Ssimokawa	int err = 0, s;
302169130Ssimokawa	struct fw_xfer *xfer;
303169130Ssimokawa	struct fw_bind *fwb;
304169130Ssimokawa	struct fw_pkt *fp;
305169130Ssimokawa	struct tcode_info *tinfo;
306169130Ssimokawa
307170374Ssimokawa	FW_GLOCK(d->fc);
308169130Ssimokawa	while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == 0)
309170374Ssimokawa		err = msleep(&d->rq, FW_GMTX(d->fc), FWPRI, "fwra", 0);
310169130Ssimokawa
311170374Ssimokawa	if (err != 0) {
312170374Ssimokawa		FW_GUNLOCK(d->fc);
313169130Ssimokawa		return (err);
314170374Ssimokawa	}
315169130Ssimokawa
316169130Ssimokawa	s = splfw();
317169130Ssimokawa	STAILQ_REMOVE_HEAD(&d->rq, link);
318170374Ssimokawa	FW_GUNLOCK(xfer->fc);
319169130Ssimokawa	splx(s);
320169130Ssimokawa	fp = &xfer->recv.hdr;
321169130Ssimokawa#if 0 /* for GASP ?? */
322169130Ssimokawa	if (fc->irx_post != NULL)
323169130Ssimokawa		fc->irx_post(fc, fp->mode.ld);
324169130Ssimokawa#endif
325169130Ssimokawa	tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode];
326169130Ssimokawa	err = uiomove((void *)fp, tinfo->hdr_len, uio);
327169130Ssimokawa	if (err)
328169130Ssimokawa		goto out;
329169130Ssimokawa	err = uiomove((void *)xfer->recv.payload, xfer->recv.pay_len, uio);
330169130Ssimokawa
331169130Ssimokawaout:
332169130Ssimokawa	/* recycle this xfer */
333169130Ssimokawa	fwb = (struct fw_bind *)xfer->sc;
334169130Ssimokawa	fw_xfer_unload(xfer);
335169130Ssimokawa	xfer->recv.pay_len = PAGE_SIZE;
336170374Ssimokawa	FW_GLOCK(xfer->fc);
337169130Ssimokawa	STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link);
338170374Ssimokawa	FW_GUNLOCK(xfer->fc);
339169130Ssimokawa	return (err);
340169130Ssimokawa}
341169130Ssimokawa
342106813Ssimokawa/*
343106813Ssimokawa * read request.
344106813Ssimokawa */
345106813Ssimokawastatic int
346130585Sphkfw_read (struct cdev *dev, struct uio *uio, int ioflag)
347106813Ssimokawa{
348169130Ssimokawa	struct fw_drv1 *d;
349106813Ssimokawa	struct fw_xferq *ir;
350169130Ssimokawa	struct firewire_comm *fc;
351106813Ssimokawa	int err = 0, s, slept = 0;
352106813Ssimokawa	struct fw_pkt *fp;
353106813Ssimokawa
354106813Ssimokawa	if (DEV_FWMEM(dev))
355170374Ssimokawa		return (physio(dev, uio, ioflag));
356106813Ssimokawa
357169130Ssimokawa	d = (struct fw_drv1 *)dev->si_drv1;
358169130Ssimokawa	fc = d->fc;
359169130Ssimokawa	ir = d->ir;
360169130Ssimokawa
361169130Ssimokawa	if (ir == NULL)
362169130Ssimokawa		return (fw_read_async(d, uio, ioflag));
363169130Ssimokawa
364169130Ssimokawa	if (ir->buf == NULL)
365118293Ssimokawa		return (EIO);
366106813Ssimokawa
367170374Ssimokawa	FW_GLOCK(fc);
368106813Ssimokawareadloop:
369113584Ssimokawa	if (ir->stproc == NULL) {
370109988Ssimokawa		/* iso bulkxfer */
371106813Ssimokawa		ir->stproc = STAILQ_FIRST(&ir->stvalid);
372109988Ssimokawa		if (ir->stproc != NULL) {
373106813Ssimokawa			s = splfw();
374106813Ssimokawa			STAILQ_REMOVE_HEAD(&ir->stvalid, link);
375106813Ssimokawa			splx(s);
376106813Ssimokawa			ir->queued = 0;
377106813Ssimokawa		}
378106813Ssimokawa	}
379169130Ssimokawa	if (ir->stproc == NULL) {
380109988Ssimokawa		/* no data avaliable */
381109988Ssimokawa		if (slept == 0) {
382106813Ssimokawa			slept = 1;
383106813Ssimokawa			ir->flag |= FWXFERQ_WAKEUP;
384170374Ssimokawa			err = msleep(ir, FW_GMTX(fc), FWPRI, "fw_read", hz);
385109988Ssimokawa			ir->flag &= ~FWXFERQ_WAKEUP;
386109988Ssimokawa			if (err == 0)
387109988Ssimokawa				goto readloop;
388109988Ssimokawa		} else if (slept == 1)
389106813Ssimokawa			err = EIO;
390170374Ssimokawa		FW_GUNLOCK(fc);
391109988Ssimokawa		return err;
392109988Ssimokawa	} else if(ir->stproc != NULL) {
393109988Ssimokawa		/* iso bulkxfer */
394170374Ssimokawa		FW_GUNLOCK(fc);
395113584Ssimokawa		fp = (struct fw_pkt *)fwdma_v_addr(ir->buf,
396113584Ssimokawa				ir->stproc->poffset + ir->queued);
397169130Ssimokawa		if(fc->irx_post != NULL)
398169130Ssimokawa			fc->irx_post(fc, fp->mode.ld);
399113584Ssimokawa		if(fp->mode.stream.len == 0){
400106813Ssimokawa			err = EIO;
401106813Ssimokawa			return err;
402106813Ssimokawa		}
403109988Ssimokawa		err = uiomove((caddr_t)fp,
404129585Sdfr			fp->mode.stream.len + sizeof(uint32_t), uio);
405106813Ssimokawa		ir->queued ++;
406106813Ssimokawa		if(ir->queued >= ir->bnpacket){
407106813Ssimokawa			s = splfw();
408106813Ssimokawa			STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link);
409106813Ssimokawa			splx(s);
410169130Ssimokawa			fc->irx_enable(fc, ir->dmach);
411106813Ssimokawa			ir->stproc = NULL;
412106813Ssimokawa		}
413109988Ssimokawa		if (uio->uio_resid >= ir->psize) {
414109988Ssimokawa			slept = -1;
415170374Ssimokawa			FW_GLOCK(fc);
416109988Ssimokawa			goto readloop;
417109988Ssimokawa		}
418106813Ssimokawa	}
419106813Ssimokawa	return err;
420106813Ssimokawa}
421106813Ssimokawa
422106813Ssimokawastatic int
423169130Ssimokawafw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag)
424169130Ssimokawa{
425169130Ssimokawa	struct fw_xfer *xfer;
426169130Ssimokawa	struct fw_pkt pkt;
427169130Ssimokawa	struct tcode_info *tinfo;
428169130Ssimokawa	int err;
429169130Ssimokawa
430169130Ssimokawa	bzero(&pkt, sizeof(struct fw_pkt));
431169130Ssimokawa	if ((err = uiomove((caddr_t)&pkt, sizeof(uint32_t), uio)))
432169130Ssimokawa		return (err);
433169130Ssimokawa	tinfo = &d->fc->tcode[pkt.mode.hdr.tcode];
434169130Ssimokawa	if ((err = uiomove((caddr_t)&pkt + sizeof(uint32_t),
435169130Ssimokawa	    tinfo->hdr_len - sizeof(uint32_t), uio)))
436169130Ssimokawa		return (err);
437169130Ssimokawa
438169130Ssimokawa	if ((xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid,
439169130Ssimokawa	    PAGE_SIZE/*XXX*/)) == NULL)
440169130Ssimokawa		return (ENOMEM);
441169130Ssimokawa
442169130Ssimokawa	bcopy(&pkt, &xfer->send.hdr, sizeof(struct fw_pkt));
443169130Ssimokawa	xfer->send.pay_len = uio->uio_resid;
444169130Ssimokawa	if (uio->uio_resid > 0) {
445169130Ssimokawa		if ((err = uiomove((caddr_t)&xfer->send.payload[0],
446194687Srdivacky		    uio->uio_resid, uio)))
447169130Ssimokawa			goto out;
448169130Ssimokawa	}
449169130Ssimokawa
450169130Ssimokawa	xfer->fc = d->fc;
451169130Ssimokawa	xfer->sc = NULL;
452170374Ssimokawa	xfer->hand = fw_xferwake;
453169130Ssimokawa	xfer->send.spd = 2 /* XXX */;
454169130Ssimokawa
455169130Ssimokawa	if ((err = fw_asyreq(xfer->fc, -1, xfer)))
456169130Ssimokawa		goto out;
457169130Ssimokawa
458170374Ssimokawa	if ((err = fw_xferwait(xfer)))
459169130Ssimokawa		goto out;
460169130Ssimokawa
461169130Ssimokawa	if (xfer->resp != 0) {
462169130Ssimokawa		err = xfer->resp;
463169130Ssimokawa		goto out;
464169130Ssimokawa	}
465169130Ssimokawa
466170374Ssimokawa	if (xfer->flag & FWXF_RCVD) {
467170374Ssimokawa		FW_GLOCK(xfer->fc);
468169130Ssimokawa		STAILQ_INSERT_TAIL(&d->rq, xfer, link);
469170374Ssimokawa		FW_GUNLOCK(xfer->fc);
470169130Ssimokawa		return (0);
471169130Ssimokawa	}
472169130Ssimokawa
473169130Ssimokawaout:
474169130Ssimokawa	fw_xfer_free(xfer);
475169130Ssimokawa	return (err);
476169130Ssimokawa}
477169130Ssimokawa
478169130Ssimokawastatic int
479130585Sphkfw_write (struct cdev *dev, struct uio *uio, int ioflag)
480106813Ssimokawa{
481106813Ssimokawa	int err = 0;
482106813Ssimokawa	int s, slept = 0;
483169130Ssimokawa	struct fw_drv1 *d;
484106813Ssimokawa	struct fw_pkt *fp;
485106813Ssimokawa	struct firewire_comm *fc;
486106813Ssimokawa	struct fw_xferq *it;
487106813Ssimokawa
488106813Ssimokawa	if (DEV_FWMEM(dev))
489170374Ssimokawa		return (physio(dev, uio, ioflag));
490106813Ssimokawa
491169130Ssimokawa	d = (struct fw_drv1 *)dev->si_drv1;
492169130Ssimokawa	fc = d->fc;
493169130Ssimokawa	it = d->it;
494169130Ssimokawa
495169130Ssimokawa	if (it == NULL)
496169130Ssimokawa		return (fw_write_async(d, uio, ioflag));
497169130Ssimokawa
498169130Ssimokawa	if (it->buf == NULL)
499118293Ssimokawa		return (EIO);
500170374Ssimokawa
501170374Ssimokawa	FW_GLOCK(fc);
502106813Ssimokawaisoloop:
503113802Ssimokawa	if (it->stproc == NULL) {
504113802Ssimokawa		it->stproc = STAILQ_FIRST(&it->stfree);
505113802Ssimokawa		if (it->stproc != NULL) {
506106813Ssimokawa			s = splfw();
507113802Ssimokawa			STAILQ_REMOVE_HEAD(&it->stfree, link);
508106813Ssimokawa			splx(s);
509113802Ssimokawa			it->queued = 0;
510113802Ssimokawa		} else if (slept == 0) {
511113802Ssimokawa			slept = 1;
512170374Ssimokawa#if 0	/* XXX to avoid lock recursion */
513169130Ssimokawa			err = fc->itx_enable(fc, it->dmach);
514113802Ssimokawa			if (err)
515170374Ssimokawa				goto out;
516170374Ssimokawa#endif
517170374Ssimokawa			err = msleep(it, FW_GMTX(fc), FWPRI, "fw_write", hz);
518113802Ssimokawa			if (err)
519170374Ssimokawa				goto out;
520109988Ssimokawa			goto isoloop;
521113802Ssimokawa		} else {
522113802Ssimokawa			err = EIO;
523170374Ssimokawa			goto out;
524106813Ssimokawa		}
525106813Ssimokawa	}
526170374Ssimokawa	FW_GUNLOCK(fc);
527113802Ssimokawa	fp = (struct fw_pkt *)fwdma_v_addr(it->buf,
528113802Ssimokawa			it->stproc->poffset + it->queued);
529113802Ssimokawa	err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio);
530113802Ssimokawa	err = uiomove((caddr_t)fp->mode.stream.payload,
531113802Ssimokawa				fp->mode.stream.len, uio);
532113802Ssimokawa	it->queued ++;
533113802Ssimokawa	if (it->queued >= it->bnpacket) {
534113802Ssimokawa		s = splfw();
535113802Ssimokawa		STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
536113802Ssimokawa		splx(s);
537113802Ssimokawa		it->stproc = NULL;
538169130Ssimokawa		err = fc->itx_enable(fc, it->dmach);
539113802Ssimokawa	}
540113802Ssimokawa	if (uio->uio_resid >= sizeof(struct fw_isohdr)) {
541113802Ssimokawa		slept = 0;
542170374Ssimokawa		FW_GLOCK(fc);
543113802Ssimokawa		goto isoloop;
544113802Ssimokawa	}
545113802Ssimokawa	return err;
546170374Ssimokawa
547170374Ssimokawaout:
548170374Ssimokawa	FW_GUNLOCK(fc);
549170374Ssimokawa	return err;
550106813Ssimokawa}
551169130Ssimokawa
552169130Ssimokawastatic void
553169130Ssimokawafw_hand(struct fw_xfer *xfer)
554169130Ssimokawa{
555169130Ssimokawa	struct fw_bind *fwb;
556169130Ssimokawa	struct fw_drv1 *d;
557169130Ssimokawa
558169130Ssimokawa	fwb = (struct fw_bind *)xfer->sc;
559169130Ssimokawa	d = (struct fw_drv1 *)fwb->sc;
560170374Ssimokawa	FW_GLOCK(xfer->fc);
561169130Ssimokawa	STAILQ_INSERT_TAIL(&d->rq, xfer, link);
562170374Ssimokawa	FW_GUNLOCK(xfer->fc);
563169130Ssimokawa	wakeup(&d->rq);
564169130Ssimokawa}
565169130Ssimokawa
566106813Ssimokawa/*
567106813Ssimokawa * ioctl support.
568106813Ssimokawa */
569106813Ssimokawaint
570130585Sphkfw_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
571106813Ssimokawa{
572118293Ssimokawa	struct firewire_comm *fc;
573118293Ssimokawa	struct fw_drv1 *d;
574169130Ssimokawa	int i, len, err = 0;
575106813Ssimokawa	struct fw_device *fwdev;
576106813Ssimokawa	struct fw_bind *fwb;
577106813Ssimokawa	struct fw_xferq *ir, *it;
578106813Ssimokawa	struct fw_xfer *xfer;
579106813Ssimokawa	struct fw_pkt *fp;
580109814Ssimokawa	struct fw_devinfo *devinfo;
581117473Ssimokawa	void *ptr;
582106813Ssimokawa
583106813Ssimokawa	struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data;
584106813Ssimokawa	struct fw_asyreq *asyreq = (struct fw_asyreq *)data;
585106813Ssimokawa	struct fw_isochreq *ichreq = (struct fw_isochreq *)data;
586106813Ssimokawa	struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data;
587106813Ssimokawa	struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data;
588106813Ssimokawa	struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data;
589106813Ssimokawa
590106813Ssimokawa	if (DEV_FWMEM(dev))
591106813Ssimokawa		return fwmem_ioctl(dev, cmd, data, flag, td);
592106813Ssimokawa
593106813Ssimokawa	if (!data)
594106813Ssimokawa		return(EINVAL);
595106813Ssimokawa
596118293Ssimokawa	d = (struct fw_drv1 *)dev->si_drv1;
597169130Ssimokawa	fc = d->fc;
598118293Ssimokawa	ir = d->ir;
599118293Ssimokawa	it = d->it;
600118293Ssimokawa
601106813Ssimokawa	switch (cmd) {
602106813Ssimokawa	case FW_STSTREAM:
603118293Ssimokawa		if (it == NULL) {
604170374Ssimokawa			i = fw_open_isodma(fc, /* tx */1);
605170374Ssimokawa			if (i < 0) {
606118293Ssimokawa				err = EBUSY;
607118293Ssimokawa				break;
608118293Ssimokawa			}
609170374Ssimokawa			it = fc->it[i];
610118293Ssimokawa			err = fwdev_allocbuf(fc, it, &d->bufreq.tx);
611170374Ssimokawa			if (err) {
612170374Ssimokawa				it->flag &= ~FWXFERQ_OPEN;
613118293Ssimokawa				break;
614170374Ssimokawa			}
615118293Ssimokawa		}
616118293Ssimokawa		it->flag &= ~0xff;
617118293Ssimokawa		it->flag |= (0x3f & ichreq->ch);
618118293Ssimokawa		it->flag |= ((0x3 & ichreq->tag) << 6);
619118293Ssimokawa		d->it = it;
620106813Ssimokawa		break;
621106813Ssimokawa	case FW_GTSTREAM:
622118293Ssimokawa		if (it != NULL) {
623118293Ssimokawa			ichreq->ch = it->flag & 0x3f;
624118293Ssimokawa			ichreq->tag = it->flag >> 2 & 0x3;
625118293Ssimokawa		} else
626118293Ssimokawa			err = EINVAL;
627106813Ssimokawa		break;
628106813Ssimokawa	case FW_SRSTREAM:
629118293Ssimokawa		if (ir == NULL) {
630170374Ssimokawa			i = fw_open_isodma(fc, /* tx */0);
631170374Ssimokawa			if (i < 0) {
632118293Ssimokawa				err = EBUSY;
633118293Ssimokawa				break;
634118293Ssimokawa			}
635170374Ssimokawa			ir = fc->ir[i];
636118293Ssimokawa			err = fwdev_allocbuf(fc, ir, &d->bufreq.rx);
637170374Ssimokawa			if (err) {
638170374Ssimokawa				ir->flag &= ~FWXFERQ_OPEN;
639118293Ssimokawa				break;
640170374Ssimokawa			}
641118293Ssimokawa		}
642118293Ssimokawa		ir->flag &= ~0xff;
643118293Ssimokawa		ir->flag |= (0x3f & ichreq->ch);
644118293Ssimokawa		ir->flag |= ((0x3 & ichreq->tag) << 6);
645118293Ssimokawa		d->ir = ir;
646118293Ssimokawa		err = fc->irx_enable(fc, ir->dmach);
647106813Ssimokawa		break;
648106813Ssimokawa	case FW_GRSTREAM:
649118293Ssimokawa		if (d->ir != NULL) {
650118293Ssimokawa			ichreq->ch = ir->flag & 0x3f;
651118293Ssimokawa			ichreq->tag = ir->flag >> 2 & 0x3;
652118293Ssimokawa		} else
653118293Ssimokawa			err = EINVAL;
654106813Ssimokawa		break;
655106813Ssimokawa	case FW_SSTBUF:
656118293Ssimokawa		bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq));
657106813Ssimokawa		break;
658106813Ssimokawa	case FW_GSTBUF:
659118293Ssimokawa		bzero(&ibufreq->rx, sizeof(ibufreq->rx));
660118293Ssimokawa		if (ir != NULL) {
661118293Ssimokawa			ibufreq->rx.nchunk = ir->bnchunk;
662118293Ssimokawa			ibufreq->rx.npacket = ir->bnpacket;
663118293Ssimokawa			ibufreq->rx.psize = ir->psize;
664118293Ssimokawa		}
665118293Ssimokawa		bzero(&ibufreq->tx, sizeof(ibufreq->tx));
666118293Ssimokawa		if (it != NULL) {
667118293Ssimokawa			ibufreq->tx.nchunk = it->bnchunk;
668118293Ssimokawa			ibufreq->tx.npacket = it->bnpacket;
669118293Ssimokawa			ibufreq->tx.psize = it->psize;
670118293Ssimokawa		}
671106813Ssimokawa		break;
672106813Ssimokawa	case FW_ASYREQ:
673120660Ssimokawa	{
674120660Ssimokawa		struct tcode_info *tinfo;
675121466Ssimokawa		int pay_len = 0;
676120660Ssimokawa
677106813Ssimokawa		fp = &asyreq->pkt;
678169130Ssimokawa		tinfo = &fc->tcode[fp->mode.hdr.tcode];
679121466Ssimokawa
680121466Ssimokawa		if ((tinfo->flag & FWTI_BLOCK_ASY) != 0)
681121466Ssimokawa			pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len);
682121466Ssimokawa
683121466Ssimokawa		xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/);
684121466Ssimokawa		if (xfer == NULL)
685121466Ssimokawa			return (ENOMEM);
686121466Ssimokawa
687106813Ssimokawa		switch (asyreq->req.type) {
688106813Ssimokawa		case FWASREQNODE:
689106813Ssimokawa			break;
690106813Ssimokawa		case FWASREQEUI:
691169130Ssimokawa			fwdev = fw_noderesolve_eui64(fc,
692110582Ssimokawa						&asyreq->req.dst.eui);
693106813Ssimokawa			if (fwdev == NULL) {
694169130Ssimokawa				device_printf(fc->bdev,
695108782Ssimokawa					"cannot find node\n");
696106813Ssimokawa				err = EINVAL;
697121466Ssimokawa				goto out;
698106813Ssimokawa			}
699120660Ssimokawa			fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst;
700106813Ssimokawa			break;
701106813Ssimokawa		case FWASRESTL:
702106813Ssimokawa			/* XXX what's this? */
703106813Ssimokawa			break;
704106813Ssimokawa		case FWASREQSTREAM:
705106813Ssimokawa			/* nothing to do */
706106813Ssimokawa			break;
707106813Ssimokawa		}
708121466Ssimokawa
709120660Ssimokawa		bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len);
710121466Ssimokawa		if (pay_len > 0)
711120660Ssimokawa			bcopy((char *)fp + tinfo->hdr_len,
712127347Ssimokawa			    (void *)xfer->send.payload, pay_len);
713121466Ssimokawa		xfer->send.spd = asyreq->req.sped;
714170374Ssimokawa		xfer->hand = fw_xferwake;
715121466Ssimokawa
716169130Ssimokawa		if ((err = fw_asyreq(fc, -1, xfer)) != 0)
717121466Ssimokawa			goto out;
718170374Ssimokawa		if ((err = fw_xferwait(xfer)) != 0)
719121466Ssimokawa			goto out;
720121466Ssimokawa		if (xfer->resp != 0) {
721121466Ssimokawa			err = EIO;
722121466Ssimokawa			goto out;
723106813Ssimokawa		}
724121466Ssimokawa		if ((tinfo->flag & FWTI_TLABEL) == 0)
725121466Ssimokawa			goto out;
726121466Ssimokawa
727121466Ssimokawa		/* copy response */
728169130Ssimokawa		tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode];
729129628Sdfr		if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB ||
730129628Sdfr		    xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) {
731129628Sdfr			pay_len = xfer->recv.pay_len;
732129628Sdfr			if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) {
733129628Sdfr				asyreq->req.len = xfer->recv.pay_len +
734129628Sdfr					tinfo->hdr_len;
735129628Sdfr			} else {
736129628Sdfr				err = EINVAL;
737129628Sdfr				pay_len = 0;
738129628Sdfr			}
739129628Sdfr		} else {
740129628Sdfr			pay_len = 0;
741129628Sdfr		}
742121466Ssimokawa		bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len);
743129628Sdfr		bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, pay_len);
744121466Ssimokawaout:
745120660Ssimokawa		fw_xfer_free_buf(xfer);
746106813Ssimokawa		break;
747120660Ssimokawa	}
748106813Ssimokawa	case FW_IBUSRST:
749169130Ssimokawa		fc->ibr(fc);
750106813Ssimokawa		break;
751106813Ssimokawa	case FW_CBINDADDR:
752169130Ssimokawa		fwb = fw_bindlookup(fc,
753106813Ssimokawa				bindreq->start.hi, bindreq->start.lo);
754106813Ssimokawa		if(fwb == NULL){
755106813Ssimokawa			err = EINVAL;
756106813Ssimokawa			break;
757106813Ssimokawa		}
758169130Ssimokawa		fw_bindremove(fc, fwb);
759169130Ssimokawa		STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist);
760169130Ssimokawa		fw_xferlist_remove(&fwb->xferlist);
761110195Ssimokawa		free(fwb, M_FW);
762106813Ssimokawa		break;
763106813Ssimokawa	case FW_SBINDADDR:
764106813Ssimokawa		if(bindreq->len <= 0 ){
765106813Ssimokawa			err = EINVAL;
766106813Ssimokawa			break;
767106813Ssimokawa		}
768106813Ssimokawa		if(bindreq->start.hi > 0xffff ){
769106813Ssimokawa			err = EINVAL;
770106813Ssimokawa			break;
771106813Ssimokawa		}
772170374Ssimokawa		fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_WAITOK);
773106813Ssimokawa		if(fwb == NULL){
774106813Ssimokawa			err = ENOMEM;
775106813Ssimokawa			break;
776106813Ssimokawa		}
777120660Ssimokawa		fwb->start = ((u_int64_t)bindreq->start.hi << 32) |
778120660Ssimokawa		    bindreq->start.lo;
779120660Ssimokawa		fwb->end = fwb->start +  bindreq->len;
780169130Ssimokawa		fwb->sc = (void *)d;
781169130Ssimokawa		STAILQ_INIT(&fwb->xferlist);
782169130Ssimokawa		err = fw_bindadd(fc, fwb);
783169130Ssimokawa		if (err == 0) {
784169130Ssimokawa			fw_xferlist_add(&fwb->xferlist, M_FWXFER,
785169130Ssimokawa			    /* XXX */
786169130Ssimokawa			    PAGE_SIZE, PAGE_SIZE, 5,
787169130Ssimokawa			    fc, (void *)fwb, fw_hand);
788169130Ssimokawa			STAILQ_INSERT_TAIL(&d->binds, fwb, chlist);
789106813Ssimokawa		}
790106813Ssimokawa		break;
791106813Ssimokawa	case FW_GDEVLST:
792109814Ssimokawa		i = len = 1;
793109814Ssimokawa		/* myself */
794109814Ssimokawa		devinfo = &fwdevlst->dev[0];
795169130Ssimokawa		devinfo->dst = fc->nodeid;
796109814Ssimokawa		devinfo->status = 0;	/* XXX */
797169130Ssimokawa		devinfo->eui.hi = fc->eui.hi;
798169130Ssimokawa		devinfo->eui.lo = fc->eui.lo;
799169130Ssimokawa		STAILQ_FOREACH(fwdev, &fc->devices, link) {
800109814Ssimokawa			if(len < FW_MAX_DEVLST){
801109814Ssimokawa				devinfo = &fwdevlst->dev[len++];
802109814Ssimokawa				devinfo->dst = fwdev->dst;
803109814Ssimokawa				devinfo->status =
804109814Ssimokawa					(fwdev->status == FWDEVINVAL)?0:1;
805109814Ssimokawa				devinfo->eui.hi = fwdev->eui.hi;
806109814Ssimokawa				devinfo->eui.lo = fwdev->eui.lo;
807106813Ssimokawa			}
808106813Ssimokawa			i++;
809106813Ssimokawa		}
810106813Ssimokawa		fwdevlst->n = i;
811109814Ssimokawa		fwdevlst->info_len = len;
812106813Ssimokawa		break;
813106813Ssimokawa	case FW_GTPMAP:
814169130Ssimokawa		bcopy(fc->topology_map, data,
815169130Ssimokawa				(fc->topology_map->crc_len + 1) * 4);
816106813Ssimokawa		break;
817106813Ssimokawa	case FW_GCROM:
818169130Ssimokawa		STAILQ_FOREACH(fwdev, &fc->devices, link)
819110193Ssimokawa			if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui))
820106813Ssimokawa				break;
821106813Ssimokawa		if (fwdev == NULL) {
822169130Ssimokawa			if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) {
823117473Ssimokawa				err = FWNODE_INVAL;
824117473Ssimokawa				break;
825117473Ssimokawa			}
826117473Ssimokawa			/* myself */
827117473Ssimokawa			ptr = malloc(CROMSIZE, M_FW, M_WAITOK);
828117473Ssimokawa			len = CROMSIZE;
829117473Ssimokawa			for (i = 0; i < CROMSIZE/4; i++)
830129585Sdfr				((uint32_t *)ptr)[i]
831169130Ssimokawa					= ntohl(fc->config_rom[i]);
832117473Ssimokawa		} else {
833117473Ssimokawa			/* found */
834117473Ssimokawa			ptr = (void *)&fwdev->csrrom[0];
835117473Ssimokawa			if (fwdev->rommax < CSRROMOFF)
836117473Ssimokawa				len = 0;
837117473Ssimokawa			else
838117473Ssimokawa				len = fwdev->rommax - CSRROMOFF + 4;
839106813Ssimokawa		}
840169019Ssimokawa		if (crom_buf->len < len)
841106813Ssimokawa			len = crom_buf->len;
842106813Ssimokawa		else
843106813Ssimokawa			crom_buf->len = len;
844117473Ssimokawa		err = copyout(ptr, crom_buf->ptr, len);
845117473Ssimokawa		if (fwdev == NULL)
846117473Ssimokawa			/* myself */
847117473Ssimokawa			free(ptr, M_FW);
848106813Ssimokawa		break;
849106813Ssimokawa	default:
850169130Ssimokawa		fc->ioctl (dev, cmd, data, flag, td);
851106813Ssimokawa		break;
852106813Ssimokawa	}
853106813Ssimokawa	return err;
854106813Ssimokawa}
855106813Ssimokawaint
856130585Sphkfw_poll(struct cdev *dev, int events, fw_proc *td)
857106813Ssimokawa{
858118293Ssimokawa	struct fw_xferq *ir;
859106813Ssimokawa	int revents;
860106813Ssimokawa	int tmp;
861106813Ssimokawa
862106813Ssimokawa	if (DEV_FWMEM(dev))
863106813Ssimokawa		return fwmem_poll(dev, events, td);
864106813Ssimokawa
865118293Ssimokawa	ir = ((struct fw_drv1 *)dev->si_drv1)->ir;
866106813Ssimokawa	revents = 0;
867106813Ssimokawa	tmp = POLLIN | POLLRDNORM;
868106813Ssimokawa	if (events & tmp) {
869118293Ssimokawa		if (STAILQ_FIRST(&ir->q) != NULL)
870106813Ssimokawa			revents |= tmp;
871106813Ssimokawa		else
872118293Ssimokawa			selrecord(td, &ir->rsel);
873106813Ssimokawa	}
874106813Ssimokawa	tmp = POLLOUT | POLLWRNORM;
875106813Ssimokawa	if (events & tmp) {
876106813Ssimokawa		/* XXX should be fixed */
877106813Ssimokawa		revents |= tmp;
878106813Ssimokawa	}
879106813Ssimokawa
880106813Ssimokawa	return revents;
881106813Ssimokawa}
882106813Ssimokawa
883106813Ssimokawastatic int
884127468Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500102
885130585Sphkfw_mmap (struct cdev *dev, vm_offset_t offset, int nproto)
886111615Ssimokawa#else
887201223Srnolandfw_mmap (struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
888201223Srnoland    int nproto, vm_memattr_t *memattr)
889111615Ssimokawa#endif
890106813Ssimokawa{
891106813Ssimokawa
892106813Ssimokawa	if (DEV_FWMEM(dev))
893127468Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500102
894111615Ssimokawa		return fwmem_mmap(dev, offset, nproto);
895111615Ssimokawa#else
896201223Srnoland		return fwmem_mmap(dev, offset, paddr, nproto, memattr);
897111615Ssimokawa#endif
898106813Ssimokawa
899106813Ssimokawa	return EINVAL;
900106813Ssimokawa}
901118455Ssimokawa
902120660Ssimokawastatic void
903120660Ssimokawafw_strategy(struct bio *bp)
904120660Ssimokawa{
905130585Sphk	struct cdev *dev;
906120660Ssimokawa
907120660Ssimokawa	dev = bp->bio_dev;
908120660Ssimokawa	if (DEV_FWMEM(dev)) {
909120660Ssimokawa		fwmem_strategy(bp);
910120660Ssimokawa		return;
911120660Ssimokawa	}
912120660Ssimokawa
913120660Ssimokawa	bp->bio_error = EOPNOTSUPP;
914120660Ssimokawa	bp->bio_flags |= BIO_ERROR;
915120660Ssimokawa	bp->bio_resid = bp->bio_bcount;
916120660Ssimokawa	biodone(bp);
917120660Ssimokawa}
918120660Ssimokawa
919118455Ssimokawaint
920118455Ssimokawafwdev_makedev(struct firewire_softc *sc)
921118455Ssimokawa{
922118455Ssimokawa	int err = 0;
923118455Ssimokawa
924127468Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500000
925127468Ssimokawa	cdevsw_add(&firewire_cdevsw);
926127468Ssimokawa#else
927130585Sphk	struct cdev *d;
928118455Ssimokawa	int unit;
929118455Ssimokawa
930118455Ssimokawa	unit = device_get_unit(sc->fc->bdev);
931118455Ssimokawa	sc->dev = make_dev(&firewire_cdevsw, MAKEMINOR(0, unit, 0),
932118455Ssimokawa			UID_ROOT, GID_OPERATOR, 0660,
933118455Ssimokawa			"fw%d.%d", unit, 0);
934118455Ssimokawa	d = make_dev(&firewire_cdevsw,
935118455Ssimokawa			MAKEMINOR(FWMEM_FLAG, unit, 0),
936118455Ssimokawa			UID_ROOT, GID_OPERATOR, 0660,
937118455Ssimokawa			"fwmem%d.%d", unit, 0);
938118455Ssimokawa	dev_depends(sc->dev, d);
939118455Ssimokawa	make_dev_alias(sc->dev, "fw%d", unit);
940118455Ssimokawa	make_dev_alias(d, "fwmem%d", unit);
941118455Ssimokawa#endif
942118455Ssimokawa
943118455Ssimokawa	return (err);
944118455Ssimokawa}
945118455Ssimokawa
946118455Ssimokawaint
947118455Ssimokawafwdev_destroydev(struct firewire_softc *sc)
948118455Ssimokawa{
949118455Ssimokawa	int err = 0;
950118455Ssimokawa
951127468Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500000
952127468Ssimokawa	cdevsw_remove(&firewire_cdevsw);
953127468Ssimokawa#else
954118455Ssimokawa	destroy_dev(sc->dev);
955118455Ssimokawa#endif
956118455Ssimokawa	return (err);
957118455Ssimokawa}
958118455Ssimokawa
959127468Ssimokawa#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
960118455Ssimokawa#define NDEVTYPE 2
961118455Ssimokawavoid
962148868Srwatsonfwdev_clone(void *arg, struct ucred *cred, char *name, int namelen,
963148868Srwatson    struct cdev **dev)
964118455Ssimokawa{
965118455Ssimokawa	struct firewire_softc *sc;
966118455Ssimokawa	char *devnames[NDEVTYPE] = {"fw", "fwmem"};
967118455Ssimokawa	char *subp = NULL;
968118455Ssimokawa	int devflag[NDEVTYPE] = {0, FWMEM_FLAG};
969118455Ssimokawa	int i, unit = 0, sub = 0;
970118455Ssimokawa
971130640Sphk	if (*dev != NULL)
972118455Ssimokawa		return;
973118455Ssimokawa
974118455Ssimokawa	for (i = 0; i < NDEVTYPE; i++)
975120624Ssimokawa		if (dev_stdclone(name, &subp, devnames[i], &unit) == 2)
976118455Ssimokawa			goto found;
977118455Ssimokawa	/* not match */
978118455Ssimokawa	return;
979118455Ssimokawafound:
980118455Ssimokawa
981118455Ssimokawa	if (subp == NULL || *subp++ != '.')
982118455Ssimokawa		return;
983118455Ssimokawa
984118455Ssimokawa	/* /dev/fwU.S */
985118455Ssimokawa	while (isdigit(*subp)) {
986118455Ssimokawa		sub *= 10;
987118455Ssimokawa		sub += *subp++ - '0';
988118455Ssimokawa	}
989118455Ssimokawa	if (*subp != '\0')
990118455Ssimokawa		return;
991118455Ssimokawa
992118455Ssimokawa	sc = devclass_get_softc(firewire_devclass, unit);
993118455Ssimokawa	if (sc == NULL)
994118455Ssimokawa		return;
995255359Sdavide	*dev = make_dev_credf(MAKEDEV_REF, &firewire_cdevsw,
996255359Sdavide	    MAKEMINOR(devflag[i], unit, sub), cred, UID_ROOT, GID_OPERATOR,
997255359Sdavide	    0660, "%s%d.%d", devnames[i], unit, sub);
998118455Ssimokawa	dev_depends(sc->dev, *dev);
999118455Ssimokawa	return;
1000118455Ssimokawa}
1001118455Ssimokawa#endif
1002