xref: /netbsd-src/sys/dev/ieee1394/fwdev.c (revision 94f62ba6c0409bb5d1f80ed108ce646509c492f0)
1*94f62ba6Smsaitoh /*	$NetBSD: fwdev.c,v 1.33 2021/11/10 16:08:17 msaitoh Exp $	*/
2c1a84a4dSkiyohara /*-
3c1a84a4dSkiyohara  * Copyright (c) 2003 Hidetoshi Shimokawa
4c1a84a4dSkiyohara  * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
5c1a84a4dSkiyohara  * All rights reserved.
6c1a84a4dSkiyohara  *
7c1a84a4dSkiyohara  * Redistribution and use in source and binary forms, with or without
8c1a84a4dSkiyohara  * modification, are permitted provided that the following conditions
9c1a84a4dSkiyohara  * are met:
10c1a84a4dSkiyohara  * 1. Redistributions of source code must retain the above copyright
11c1a84a4dSkiyohara  *    notice, this list of conditions and the following disclaimer.
12c1a84a4dSkiyohara  * 2. Redistributions in binary form must reproduce the above copyright
13c1a84a4dSkiyohara  *    notice, this list of conditions and the following disclaimer in the
14c1a84a4dSkiyohara  *    documentation and/or other materials provided with the distribution.
15c1a84a4dSkiyohara  * 3. All advertising materials mentioning features or use of this software
16c1a84a4dSkiyohara  *    must display the acknowledgement as bellow:
17c1a84a4dSkiyohara  *
18c1a84a4dSkiyohara  *    This product includes software developed by K. Kobayashi and H. Shimokawa
19c1a84a4dSkiyohara  *
20c1a84a4dSkiyohara  * 4. The name of the author may not be used to endorse or promote products
21c1a84a4dSkiyohara  *    derived from this software without specific prior written permission.
22c1a84a4dSkiyohara  *
23c1a84a4dSkiyohara  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24c1a84a4dSkiyohara  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25c1a84a4dSkiyohara  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26c1a84a4dSkiyohara  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27c1a84a4dSkiyohara  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28c1a84a4dSkiyohara  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29c1a84a4dSkiyohara  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30c1a84a4dSkiyohara  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31c1a84a4dSkiyohara  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32c1a84a4dSkiyohara  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33c1a84a4dSkiyohara  * POSSIBILITY OF SUCH DAMAGE.
34c1a84a4dSkiyohara  *
35c33e2714Skiyohara  * $FreeBSD: src/sys/dev/firewire/fwdev.c,v 1.52 2007/06/06 14:31:36 simokawa Exp $
36c1a84a4dSkiyohara  *
37c1a84a4dSkiyohara  */
38c1a84a4dSkiyohara 
39388339aaSlukem #include <sys/cdefs.h>
40*94f62ba6Smsaitoh __KERNEL_RCSID(0, "$NetBSD: fwdev.c,v 1.33 2021/11/10 16:08:17 msaitoh Exp $");
41388339aaSlukem 
42c1a84a4dSkiyohara #include <sys/param.h>
43c1a84a4dSkiyohara #include <sys/device.h>
44c1a84a4dSkiyohara #include <sys/errno.h>
45c1a84a4dSkiyohara #include <sys/buf.h>
46af09db11Skiyohara #include <sys/bus.h>
47c1a84a4dSkiyohara #include <sys/conf.h>
48c1a84a4dSkiyohara #include <sys/kernel.h>
4932e80c5dSchristos #include <sys/malloc.h>
50c1a84a4dSkiyohara #include <sys/mbuf.h>
51c1a84a4dSkiyohara #include <sys/poll.h>
52c1a84a4dSkiyohara #include <sys/proc.h>
53af09db11Skiyohara #include <sys/select.h>
54c1a84a4dSkiyohara 
55c1a84a4dSkiyohara #include <dev/ieee1394/firewire.h>
56c1a84a4dSkiyohara #include <dev/ieee1394/firewirereg.h>
57c1a84a4dSkiyohara #include <dev/ieee1394/fwdma.h>
58c1a84a4dSkiyohara #include <dev/ieee1394/fwmem.h>
59c1a84a4dSkiyohara #include <dev/ieee1394/iec68113.h>
60af09db11Skiyohara 
61c8c01f23Suebayasi #include "ioconf.h"
62c8c01f23Suebayasi 
63c1a84a4dSkiyohara #define	FWNODE_INVAL 0xffff
64c1a84a4dSkiyohara 
65c1a84a4dSkiyohara dev_type_open(fw_open);
66c1a84a4dSkiyohara dev_type_close(fw_close);
67c1a84a4dSkiyohara dev_type_read(fw_read);
68c1a84a4dSkiyohara dev_type_write(fw_write);
69c1a84a4dSkiyohara dev_type_ioctl(fw_ioctl);
70c1a84a4dSkiyohara dev_type_poll(fw_poll);
71c1a84a4dSkiyohara dev_type_mmap(fw_mmap);
72c1a84a4dSkiyohara dev_type_strategy(fw_strategy);
73c1a84a4dSkiyohara 
74c1a84a4dSkiyohara const struct bdevsw fw_bdevsw = {
75a68f9396Sdholland 	.d_open = fw_open,
76a68f9396Sdholland 	.d_close = fw_close,
77a68f9396Sdholland 	.d_strategy = fw_strategy,
78a68f9396Sdholland 	.d_ioctl = fw_ioctl,
79a68f9396Sdholland 	.d_dump = nodump,
80a68f9396Sdholland 	.d_psize = nosize,
818c70ef39Sdholland 	.d_discard = nodiscard,
82a68f9396Sdholland 	.d_flag = D_OTHER
83c1a84a4dSkiyohara };
84c1a84a4dSkiyohara 
85c1a84a4dSkiyohara const struct cdevsw fw_cdevsw = {
86a68f9396Sdholland 	.d_open = fw_open,
87a68f9396Sdholland 	.d_close = fw_close,
88a68f9396Sdholland 	.d_read = fw_read,
89a68f9396Sdholland 	.d_write = fw_write,
90a68f9396Sdholland 	.d_ioctl = fw_ioctl,
91a68f9396Sdholland 	.d_stop = nostop,
92a68f9396Sdholland 	.d_tty = notty,
93a68f9396Sdholland 	.d_poll = fw_poll,
94a68f9396Sdholland 	.d_mmap = fw_mmap,
95a68f9396Sdholland 	.d_kqfilter = nokqfilter,
96f9228f42Sdholland 	.d_discard = nodiscard,
97a68f9396Sdholland 	.d_flag = D_OTHER
98c1a84a4dSkiyohara };
99c1a84a4dSkiyohara 
100c1a84a4dSkiyohara struct fw_drv1 {
101c1a84a4dSkiyohara 	struct firewire_comm *fc;
102c1a84a4dSkiyohara 	struct fw_xferq *ir;
103c1a84a4dSkiyohara 	struct fw_xferq *it;
104c1a84a4dSkiyohara 	struct fw_isobufreq bufreq;
105c1a84a4dSkiyohara 	STAILQ_HEAD(, fw_bind) binds;
106c1a84a4dSkiyohara 	STAILQ_HEAD(, fw_xfer) rq;
1071ebf7dd1Sriastradh 	kcondvar_t cv;
108c1a84a4dSkiyohara };
109c1a84a4dSkiyohara 
110af09db11Skiyohara static int fwdev_allocbuf(struct firewire_comm *, struct fw_xferq *,
111af09db11Skiyohara 			  struct fw_bufspec *);
11232e80c5dSchristos static int fwdev_freebuf(struct fw_xferq *);
113af09db11Skiyohara static int fw_read_async(struct fw_drv1 *, struct uio *, int);
114af09db11Skiyohara static int fw_write_async(struct fw_drv1 *, struct uio *, int);
115af09db11Skiyohara static void fw_hand(struct fw_xfer *);
116af09db11Skiyohara 
117af09db11Skiyohara 
118af09db11Skiyohara int
fw_open(dev_t dev,int flags,int fmt,struct lwp * td)119af09db11Skiyohara fw_open(dev_t dev, int flags, int fmt, struct lwp *td)
120c1a84a4dSkiyohara {
121af09db11Skiyohara 	struct firewire_softc *sc;
122c1a84a4dSkiyohara 	struct fw_drv1 *d;
123af09db11Skiyohara 	int err = 0;
124c1a84a4dSkiyohara 
125af09db11Skiyohara 	sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev));
126af09db11Skiyohara 	if (sc == NULL)
127af09db11Skiyohara 		return ENXIO;
128c1a84a4dSkiyohara 
129af09db11Skiyohara 	if (DEV_FWMEM(dev))
130af09db11Skiyohara 		return fwmem_open(dev, flags, fmt, td);
131af09db11Skiyohara 
132af09db11Skiyohara 	mutex_enter(&sc->fc->fc_mtx);
133af09db11Skiyohara 	if (sc->si_drv1 != NULL) {
134af09db11Skiyohara 		mutex_exit(&sc->fc->fc_mtx);
135af09db11Skiyohara 		return EBUSY;
136c33e2714Skiyohara 	}
137c33e2714Skiyohara 	/* set dummy value for allocation */
138af09db11Skiyohara 	sc->si_drv1 = (void *)-1;
139af09db11Skiyohara 	mutex_exit(&sc->fc->fc_mtx);
140c33e2714Skiyohara 
14132e80c5dSchristos 	sc->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO);
142af09db11Skiyohara 	if (sc->si_drv1 == NULL)
143af09db11Skiyohara 		return ENOMEM;
144c1a84a4dSkiyohara 
145af09db11Skiyohara 	d = (struct fw_drv1 *)sc->si_drv1;
146c1a84a4dSkiyohara 	d->fc = sc->fc;
147c1a84a4dSkiyohara 	STAILQ_INIT(&d->binds);
148c1a84a4dSkiyohara 	STAILQ_INIT(&d->rq);
1491ebf7dd1Sriastradh 	cv_init(&d->cv, "fwra");
150c1a84a4dSkiyohara 
151c1a84a4dSkiyohara 	return err;
152c1a84a4dSkiyohara }
153c1a84a4dSkiyohara 
154af09db11Skiyohara int
fw_close(dev_t dev,int flags,int fmt,struct lwp * td)155af09db11Skiyohara fw_close(dev_t dev, int flags, int fmt, struct lwp *td)
156c1a84a4dSkiyohara {
157af09db11Skiyohara 	struct firewire_softc *sc;
158c1a84a4dSkiyohara 	struct firewire_comm *fc;
159c1a84a4dSkiyohara 	struct fw_drv1 *d;
160c1a84a4dSkiyohara 	struct fw_xfer *xfer;
161c1a84a4dSkiyohara 	struct fw_bind *fwb;
162c1a84a4dSkiyohara         int err = 0;
163c1a84a4dSkiyohara 
164af09db11Skiyohara 	sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev));
165af09db11Skiyohara 	if (sc == NULL)
166af09db11Skiyohara 		return ENXIO;
167c1a84a4dSkiyohara 
168af09db11Skiyohara 	if (DEV_FWMEM(dev))
169af09db11Skiyohara 		return fwmem_close(dev, flags, fmt, td);
170af09db11Skiyohara 
171af09db11Skiyohara 	d = (struct fw_drv1 *)sc->si_drv1;
172c1a84a4dSkiyohara 	fc = d->fc;
173c1a84a4dSkiyohara 
174c1a84a4dSkiyohara 	/* remove binding */
175c1a84a4dSkiyohara 	for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL;
176c1a84a4dSkiyohara 	    fwb = STAILQ_FIRST(&d->binds)) {
177c1a84a4dSkiyohara 		fw_bindremove(fc, fwb);
178c1a84a4dSkiyohara 		STAILQ_REMOVE_HEAD(&d->binds, chlist);
179c1a84a4dSkiyohara 		fw_xferlist_remove(&fwb->xferlist);
180c1a84a4dSkiyohara 		free(fwb, M_FW);
181c1a84a4dSkiyohara 	}
182c1a84a4dSkiyohara 	if (d->ir != NULL) {
183c1a84a4dSkiyohara 		struct fw_xferq *ir = d->ir;
184c1a84a4dSkiyohara 
185c1a84a4dSkiyohara 		if ((ir->flag & FWXFERQ_OPEN) == 0)
186af09db11Skiyohara 			return EINVAL;
187c1a84a4dSkiyohara 		if (ir->flag & FWXFERQ_RUNNING) {
188c1a84a4dSkiyohara 			ir->flag &= ~FWXFERQ_RUNNING;
189c1a84a4dSkiyohara 			fc->irx_disable(fc, ir->dmach);
190c1a84a4dSkiyohara 		}
191c1a84a4dSkiyohara 		/* free extbuf */
19232e80c5dSchristos 		fwdev_freebuf(ir);
193c1a84a4dSkiyohara 		/* drain receiving buffer */
194af09db11Skiyohara 		for (xfer = STAILQ_FIRST(&ir->q); xfer != NULL;
195af09db11Skiyohara 		    xfer = STAILQ_FIRST(&ir->q)) {
196c1a84a4dSkiyohara 			ir->queued--;
197c1a84a4dSkiyohara 			STAILQ_REMOVE_HEAD(&ir->q, link);
198c1a84a4dSkiyohara 
199c1a84a4dSkiyohara 			xfer->resp = 0;
200c1a84a4dSkiyohara 			fw_xfer_done(xfer);
201c1a84a4dSkiyohara 		}
202af09db11Skiyohara 		ir->flag &=
203af09db11Skiyohara 		    ~(FWXFERQ_OPEN | FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
204c1a84a4dSkiyohara 		d->ir = NULL;
205c1a84a4dSkiyohara 
206c1a84a4dSkiyohara 	}
207c1a84a4dSkiyohara 	if (d->it != NULL) {
208c1a84a4dSkiyohara 		struct fw_xferq *it = d->it;
209c1a84a4dSkiyohara 
210c1a84a4dSkiyohara 		if ((it->flag & FWXFERQ_OPEN) == 0)
211af09db11Skiyohara 			return EINVAL;
212c1a84a4dSkiyohara 		if (it->flag & FWXFERQ_RUNNING) {
213c1a84a4dSkiyohara 			it->flag &= ~FWXFERQ_RUNNING;
214c1a84a4dSkiyohara 			fc->itx_disable(fc, it->dmach);
215c1a84a4dSkiyohara 		}
216c1a84a4dSkiyohara 		/* free extbuf */
21732e80c5dSchristos 		fwdev_freebuf(it);
218af09db11Skiyohara 		it->flag &=
219af09db11Skiyohara 		    ~(FWXFERQ_OPEN | FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
220c1a84a4dSkiyohara 		d->it = NULL;
221c1a84a4dSkiyohara 	}
2221ebf7dd1Sriastradh 	cv_destroy(&d->cv);
22332e80c5dSchristos 	free(sc->si_drv1, M_FW);
224af09db11Skiyohara 	sc->si_drv1 = NULL;
225c1a84a4dSkiyohara 
226c1a84a4dSkiyohara 	return err;
227c1a84a4dSkiyohara }
228c1a84a4dSkiyohara 
229af09db11Skiyohara int
fw_read(dev_t dev,struct uio * uio,int ioflag)230af09db11Skiyohara fw_read(dev_t dev, struct uio *uio, int ioflag)
231c1a84a4dSkiyohara {
232af09db11Skiyohara 	struct firewire_softc *sc;
233af09db11Skiyohara 	struct firewire_comm *fc;
234c1a84a4dSkiyohara 	struct fw_drv1 *d;
235c1a84a4dSkiyohara 	struct fw_xferq *ir;
236c1a84a4dSkiyohara 	struct fw_pkt *fp;
237af09db11Skiyohara 	int err = 0, slept = 0;
238c1a84a4dSkiyohara 
239af09db11Skiyohara 	sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev));
240af09db11Skiyohara 	if (sc == NULL)
241af09db11Skiyohara 		return ENXIO;
242c1a84a4dSkiyohara 
243af09db11Skiyohara 	if (DEV_FWMEM(dev))
244af09db11Skiyohara 		return physio(fw_strategy, NULL, dev, ioflag, minphys, uio);
245af09db11Skiyohara 
246af09db11Skiyohara 	d = (struct fw_drv1 *)sc->si_drv1;
247c1a84a4dSkiyohara 	fc = d->fc;
248c1a84a4dSkiyohara 	ir = d->ir;
249c1a84a4dSkiyohara 
250c1a84a4dSkiyohara 	if (ir == NULL)
251af09db11Skiyohara 		return fw_read_async(d, uio, ioflag);
252c1a84a4dSkiyohara 
253c1a84a4dSkiyohara 	if (ir->buf == NULL)
254af09db11Skiyohara 		return EIO;
255c1a84a4dSkiyohara 
256af09db11Skiyohara 	mutex_enter(&fc->fc_mtx);
257c1a84a4dSkiyohara readloop:
258c1a84a4dSkiyohara 	if (ir->stproc == NULL) {
259c1a84a4dSkiyohara 		/* iso bulkxfer */
260c1a84a4dSkiyohara 		ir->stproc = STAILQ_FIRST(&ir->stvalid);
261c1a84a4dSkiyohara 		if (ir->stproc != NULL) {
262c1a84a4dSkiyohara 			STAILQ_REMOVE_HEAD(&ir->stvalid, link);
263c1a84a4dSkiyohara 			ir->queued = 0;
264c1a84a4dSkiyohara 		}
265c1a84a4dSkiyohara 	}
266c1a84a4dSkiyohara 	if (ir->stproc == NULL) {
267*94f62ba6Smsaitoh 		/* no data available */
268c1a84a4dSkiyohara 		if (slept == 0) {
269c1a84a4dSkiyohara 			slept = 1;
270c1a84a4dSkiyohara 			ir->flag |= FWXFERQ_WAKEUP;
2711ebf7dd1Sriastradh 			err = cv_timedwait_sig(&ir->cv, &fc->fc_mtx, hz);
272c1a84a4dSkiyohara 			ir->flag &= ~FWXFERQ_WAKEUP;
273c1a84a4dSkiyohara 			if (err == 0)
274c1a84a4dSkiyohara 				goto readloop;
275c1a84a4dSkiyohara 		} else if (slept == 1)
276c1a84a4dSkiyohara 			err = EIO;
277af09db11Skiyohara 		mutex_exit(&fc->fc_mtx);
278c1a84a4dSkiyohara 		return err;
279c1a84a4dSkiyohara 	} else if (ir->stproc != NULL) {
280c1a84a4dSkiyohara 		/* iso bulkxfer */
281af09db11Skiyohara 		mutex_exit(&fc->fc_mtx);
282c1a84a4dSkiyohara 		fp = (struct fw_pkt *)fwdma_v_addr(ir->buf,
283c1a84a4dSkiyohara 		    ir->stproc->poffset + ir->queued);
284c1a84a4dSkiyohara 		if (fc->irx_post != NULL)
285c1a84a4dSkiyohara 			fc->irx_post(fc, fp->mode.ld);
286af09db11Skiyohara 		if (fp->mode.stream.len == 0)
287af09db11Skiyohara 			return EIO;
28853524e44Schristos 		err = uiomove((void *)fp,
289c1a84a4dSkiyohara 		    fp->mode.stream.len + sizeof(uint32_t), uio);
290c1a84a4dSkiyohara 		ir->queued++;
291c1a84a4dSkiyohara 		if (ir->queued >= ir->bnpacket) {
292c1a84a4dSkiyohara 			STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link);
293c1a84a4dSkiyohara 			fc->irx_enable(fc, ir->dmach);
294c1a84a4dSkiyohara 			ir->stproc = NULL;
295c1a84a4dSkiyohara 		}
296c1a84a4dSkiyohara 		if (uio->uio_resid >= ir->psize) {
297c1a84a4dSkiyohara 			slept = -1;
298af09db11Skiyohara 			mutex_enter(&fc->fc_mtx);
299c1a84a4dSkiyohara 			goto readloop;
300c1a84a4dSkiyohara 		}
301af09db11Skiyohara 	} else
302af09db11Skiyohara 		mutex_exit(&fc->fc_mtx);
303c1a84a4dSkiyohara 	return err;
304c1a84a4dSkiyohara }
305c1a84a4dSkiyohara 
306af09db11Skiyohara int
fw_write(dev_t dev,struct uio * uio,int ioflag)307af09db11Skiyohara fw_write(dev_t dev, struct uio *uio, int ioflag)
308c1a84a4dSkiyohara {
309af09db11Skiyohara 	struct firewire_softc *sc;
310af09db11Skiyohara 	struct firewire_comm *fc;
311c1a84a4dSkiyohara 	struct fw_drv1 *d;
312c1a84a4dSkiyohara 	struct fw_pkt *fp;
313c1a84a4dSkiyohara 	struct fw_xferq *it;
314af09db11Skiyohara         int slept = 0, err = 0;
315c1a84a4dSkiyohara 
316af09db11Skiyohara 	sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev));
317af09db11Skiyohara 	if (sc == NULL)
318af09db11Skiyohara 		return ENXIO;
319af09db11Skiyohara 
320af09db11Skiyohara 	if (DEV_FWMEM(dev))
321af09db11Skiyohara 		return physio(fw_strategy, NULL, dev, ioflag, minphys, uio);
322af09db11Skiyohara 
323af09db11Skiyohara 	d = (struct fw_drv1 *)sc->si_drv1;
324c1a84a4dSkiyohara 	fc = d->fc;
325c1a84a4dSkiyohara 	it = d->it;
326c1a84a4dSkiyohara 
327c1a84a4dSkiyohara 	if (it == NULL)
328af09db11Skiyohara 		return fw_write_async(d, uio, ioflag);
329c1a84a4dSkiyohara 
330c1a84a4dSkiyohara 	if (it->buf == NULL)
331af09db11Skiyohara 		return EIO;
332c33e2714Skiyohara 
333af09db11Skiyohara 	mutex_enter(&fc->fc_mtx);
334c1a84a4dSkiyohara isoloop:
335c1a84a4dSkiyohara 	if (it->stproc == NULL) {
336c1a84a4dSkiyohara 		it->stproc = STAILQ_FIRST(&it->stfree);
337c1a84a4dSkiyohara 		if (it->stproc != NULL) {
338c1a84a4dSkiyohara 			STAILQ_REMOVE_HEAD(&it->stfree, link);
339c1a84a4dSkiyohara 			it->queued = 0;
340c1a84a4dSkiyohara 		} else if (slept == 0) {
341c1a84a4dSkiyohara 			slept = 1;
342c33e2714Skiyohara #if 0   /* XXX to avoid lock recursion */
343c1a84a4dSkiyohara 			err = fc->itx_enable(fc, it->dmach);
344c1a84a4dSkiyohara 			if (err)
345c33e2714Skiyohara 				goto out;
346c33e2714Skiyohara #endif
3471ebf7dd1Sriastradh 			err = cv_timedwait_sig(&it->cv, &fc->fc_mtx, hz);
348c1a84a4dSkiyohara 			if (err)
349c33e2714Skiyohara 				goto out;
350c1a84a4dSkiyohara 			goto isoloop;
351c1a84a4dSkiyohara 		} else {
352c1a84a4dSkiyohara 			err = EIO;
353c33e2714Skiyohara 			goto out;
354c1a84a4dSkiyohara 		}
355c1a84a4dSkiyohara 	}
356af09db11Skiyohara 	mutex_exit(&fc->fc_mtx);
357c1a84a4dSkiyohara 	fp = (struct fw_pkt *)fwdma_v_addr(it->buf,
358c1a84a4dSkiyohara 	    it->stproc->poffset + it->queued);
35953524e44Schristos 	err = uiomove((void *)fp, sizeof(struct fw_isohdr), uio);
360af09db11Skiyohara 	if (err != 0)
361af09db11Skiyohara 		return err;
362af09db11Skiyohara 	err =
363af09db11Skiyohara 	    uiomove((void *)fp->mode.stream.payload, fp->mode.stream.len, uio);
364c1a84a4dSkiyohara 	it->queued++;
365c1a84a4dSkiyohara 	if (it->queued >= it->bnpacket) {
366c1a84a4dSkiyohara 		STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
367c1a84a4dSkiyohara 		it->stproc = NULL;
368c1a84a4dSkiyohara 		err = fc->itx_enable(fc, it->dmach);
369c1a84a4dSkiyohara 	}
370c1a84a4dSkiyohara 	if (uio->uio_resid >= sizeof(struct fw_isohdr)) {
371c1a84a4dSkiyohara 		slept = 0;
372af09db11Skiyohara 		mutex_enter(&fc->fc_mtx);
373c1a84a4dSkiyohara 		goto isoloop;
374c1a84a4dSkiyohara 	}
375c1a84a4dSkiyohara 	return err;
376c33e2714Skiyohara 
377c33e2714Skiyohara out:
378af09db11Skiyohara 	mutex_exit(&fc->fc_mtx);
379c33e2714Skiyohara 	return err;
380c1a84a4dSkiyohara }
381c1a84a4dSkiyohara 
382af09db11Skiyohara int
fw_ioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * td)383af09db11Skiyohara fw_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *td)
384c1a84a4dSkiyohara {
385af09db11Skiyohara 	struct firewire_softc *sc;
386c1a84a4dSkiyohara 	struct firewire_comm *fc;
387c1a84a4dSkiyohara 	struct fw_drv1 *d;
388c1a84a4dSkiyohara 	struct fw_device *fwdev;
389c1a84a4dSkiyohara 	struct fw_bind *fwb;
390c1a84a4dSkiyohara 	struct fw_xferq *ir, *it;
391c1a84a4dSkiyohara 	struct fw_xfer *xfer;
392c1a84a4dSkiyohara 	struct fw_pkt *fp;
393c1a84a4dSkiyohara 	struct fw_devinfo *devinfo;
394c1a84a4dSkiyohara 	struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data;
395c1a84a4dSkiyohara 	struct fw_asyreq *asyreq = (struct fw_asyreq *)data;
396c1a84a4dSkiyohara 	struct fw_isochreq *ichreq = (struct fw_isochreq *)data;
397c1a84a4dSkiyohara 	struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data;
398c1a84a4dSkiyohara 	struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data;
399c1a84a4dSkiyohara 	struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data;
400af09db11Skiyohara 	int i, len, err = 0;
401af09db11Skiyohara 	void *ptr;
402c1a84a4dSkiyohara 
403af09db11Skiyohara 	sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev));
404af09db11Skiyohara 	if (sc == NULL)
405af09db11Skiyohara 		return ENXIO;
406af09db11Skiyohara 
407af09db11Skiyohara 	if (DEV_FWMEM(dev))
408af09db11Skiyohara 		return fwmem_ioctl(dev, cmd, data, flag, td);
409c1a84a4dSkiyohara 
410c1a84a4dSkiyohara 	if (!data)
411af09db11Skiyohara 		return EINVAL;
412c1a84a4dSkiyohara 
413af09db11Skiyohara 	d = (struct fw_drv1 *)sc->si_drv1;
414c1a84a4dSkiyohara 	fc = d->fc;
415c1a84a4dSkiyohara 	ir = d->ir;
416c1a84a4dSkiyohara 	it = d->it;
417c1a84a4dSkiyohara 
418c1a84a4dSkiyohara 	switch (cmd) {
419c1a84a4dSkiyohara 	case FW_STSTREAM:
420c1a84a4dSkiyohara 		if (it == NULL) {
421c33e2714Skiyohara 			i = fw_open_isodma(fc, /* tx */1);
422c33e2714Skiyohara 			if (i < 0) {
423c1a84a4dSkiyohara 				err = EBUSY;
424c1a84a4dSkiyohara 				break;
425c1a84a4dSkiyohara 			}
426c33e2714Skiyohara 			it = fc->it[i];
427c1a84a4dSkiyohara 			err = fwdev_allocbuf(fc, it, &d->bufreq.tx);
428c33e2714Skiyohara 			if (err) {
429c33e2714Skiyohara 				it->flag &= ~FWXFERQ_OPEN;
430c1a84a4dSkiyohara 				break;
431c33e2714Skiyohara 			}
432c1a84a4dSkiyohara 		}
433c1a84a4dSkiyohara 		it->flag &= ~0xff;
434c1a84a4dSkiyohara 		it->flag |= (0x3f & ichreq->ch);
435c1a84a4dSkiyohara 		it->flag |= ((0x3 & ichreq->tag) << 6);
436c1a84a4dSkiyohara 		d->it = it;
437c1a84a4dSkiyohara 		break;
438af09db11Skiyohara 
439c1a84a4dSkiyohara 	case FW_GTSTREAM:
440c1a84a4dSkiyohara 		if (it != NULL) {
441c1a84a4dSkiyohara 			ichreq->ch = it->flag & 0x3f;
442c1a84a4dSkiyohara 			ichreq->tag = it->flag >> 2 & 0x3;
443c1a84a4dSkiyohara 		} else
444c1a84a4dSkiyohara 			err = EINVAL;
445c1a84a4dSkiyohara 		break;
446af09db11Skiyohara 
447c1a84a4dSkiyohara 	case FW_SRSTREAM:
448c1a84a4dSkiyohara 		if (ir == NULL) {
449c33e2714Skiyohara 			i = fw_open_isodma(fc, /* tx */0);
450c33e2714Skiyohara 			if (i < 0) {
451c1a84a4dSkiyohara 				err = EBUSY;
452c1a84a4dSkiyohara 				break;
453c1a84a4dSkiyohara 			}
454c33e2714Skiyohara 			ir = fc->ir[i];
455c1a84a4dSkiyohara 			err = fwdev_allocbuf(fc, ir, &d->bufreq.rx);
456c33e2714Skiyohara 			if (err) {
457c33e2714Skiyohara 				ir->flag &= ~FWXFERQ_OPEN;
458c1a84a4dSkiyohara 				break;
459c33e2714Skiyohara 			}
460c1a84a4dSkiyohara 		}
461c1a84a4dSkiyohara 		ir->flag &= ~0xff;
462c1a84a4dSkiyohara 		ir->flag |= (0x3f & ichreq->ch);
463c1a84a4dSkiyohara 		ir->flag |= ((0x3 & ichreq->tag) << 6);
464c1a84a4dSkiyohara 		d->ir = ir;
465c1a84a4dSkiyohara 		err = fc->irx_enable(fc, ir->dmach);
466c1a84a4dSkiyohara 		break;
467af09db11Skiyohara 
468c1a84a4dSkiyohara 	case FW_GRSTREAM:
469c1a84a4dSkiyohara 		if (d->ir != NULL) {
470c1a84a4dSkiyohara 			ichreq->ch = ir->flag & 0x3f;
471c1a84a4dSkiyohara 			ichreq->tag = ir->flag >> 2 & 0x3;
472c1a84a4dSkiyohara 		} else
473c1a84a4dSkiyohara 			err = EINVAL;
474c1a84a4dSkiyohara 		break;
475af09db11Skiyohara 
476c1a84a4dSkiyohara 	case FW_SSTBUF:
477e2cb8590Scegger 		memcpy(&d->bufreq, ibufreq, sizeof(d->bufreq));
478c1a84a4dSkiyohara 		break;
479af09db11Skiyohara 
480c1a84a4dSkiyohara 	case FW_GSTBUF:
481c363a9cbScegger 		memset(&ibufreq->rx, 0, sizeof(ibufreq->rx));
482c1a84a4dSkiyohara 		if (ir != NULL) {
483c1a84a4dSkiyohara 			ibufreq->rx.nchunk = ir->bnchunk;
484c1a84a4dSkiyohara 			ibufreq->rx.npacket = ir->bnpacket;
485c1a84a4dSkiyohara 			ibufreq->rx.psize = ir->psize;
486c1a84a4dSkiyohara 		}
487c363a9cbScegger 		memset(&ibufreq->tx, 0, sizeof(ibufreq->tx));
488c1a84a4dSkiyohara 		if (it != NULL) {
489c1a84a4dSkiyohara 			ibufreq->tx.nchunk = it->bnchunk;
490c1a84a4dSkiyohara 			ibufreq->tx.npacket = it->bnpacket;
491c1a84a4dSkiyohara 			ibufreq->tx.psize = it->psize;
492c1a84a4dSkiyohara 		}
493c1a84a4dSkiyohara 		break;
494af09db11Skiyohara 
495c1a84a4dSkiyohara 	case FW_ASYREQ:
496c1a84a4dSkiyohara 	{
497e7bf69a7Sdrochner 		const struct tcode_info *tinfo;
498c1a84a4dSkiyohara 		int pay_len = 0;
499c1a84a4dSkiyohara 
500c1a84a4dSkiyohara 		fp = &asyreq->pkt;
501c1a84a4dSkiyohara 		tinfo = &fc->tcode[fp->mode.hdr.tcode];
502c1a84a4dSkiyohara 
503c1a84a4dSkiyohara 		if ((tinfo->flag & FWTI_BLOCK_ASY) != 0)
504c1a84a4dSkiyohara 			pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len);
505c1a84a4dSkiyohara 
506fc04895eSdsl 		xfer = fw_xfer_alloc_buf(M_FW, pay_len, PAGE_SIZE/*XXX*/);
507c1a84a4dSkiyohara 		if (xfer == NULL)
508af09db11Skiyohara 			return ENOMEM;
509c1a84a4dSkiyohara 
510c1a84a4dSkiyohara 		switch (asyreq->req.type) {
511c1a84a4dSkiyohara 		case FWASREQNODE:
512c1a84a4dSkiyohara 			break;
513af09db11Skiyohara 
514c1a84a4dSkiyohara 		case FWASREQEUI:
515af09db11Skiyohara 			fwdev = fw_noderesolve_eui64(fc, &asyreq->req.dst.eui);
516c1a84a4dSkiyohara 			if (fwdev == NULL) {
517af09db11Skiyohara 				aprint_error_dev(fc->bdev,
518af09db11Skiyohara 				    "cannot find node\n");
519c1a84a4dSkiyohara 				err = EINVAL;
520c1a84a4dSkiyohara 				goto out;
521c1a84a4dSkiyohara 			}
522c1a84a4dSkiyohara 			fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst;
523c1a84a4dSkiyohara 			break;
524af09db11Skiyohara 
525c1a84a4dSkiyohara 		case FWASRESTL:
526c1a84a4dSkiyohara 			/* XXX what's this? */
527c1a84a4dSkiyohara 			break;
528af09db11Skiyohara 
529c1a84a4dSkiyohara 		case FWASREQSTREAM:
530c1a84a4dSkiyohara 			/* nothing to do */
531c1a84a4dSkiyohara 			break;
532c1a84a4dSkiyohara 		}
533c1a84a4dSkiyohara 
534fc309475Skiyohara 		memcpy(&xfer->send.hdr, fp, tinfo->hdr_len);
535c1a84a4dSkiyohara 		if (pay_len > 0)
536fc309475Skiyohara 			memcpy(xfer->send.payload, (char *)fp + tinfo->hdr_len,
537fc309475Skiyohara 			    pay_len);
538c1a84a4dSkiyohara 		xfer->send.spd = asyreq->req.sped;
539c33e2714Skiyohara 		xfer->hand = fw_xferwake;
540c1a84a4dSkiyohara 
541c1a84a4dSkiyohara 		if ((err = fw_asyreq(fc, -1, xfer)) != 0)
542c1a84a4dSkiyohara 			goto out;
543c33e2714Skiyohara 		if ((err = fw_xferwait(xfer)) != 0)
544c1a84a4dSkiyohara 			goto out;
545c1a84a4dSkiyohara 		if (xfer->resp != 0) {
546c1a84a4dSkiyohara 			err = EIO;
547c1a84a4dSkiyohara 			goto out;
548c1a84a4dSkiyohara 		}
549c1a84a4dSkiyohara 		if ((tinfo->flag & FWTI_TLABEL) == 0)
550c1a84a4dSkiyohara 			goto out;
551c1a84a4dSkiyohara 
552c1a84a4dSkiyohara 		/* copy response */
553c1a84a4dSkiyohara 		tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode];
554c1a84a4dSkiyohara 		if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB ||
555c1a84a4dSkiyohara 		    xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) {
556c1a84a4dSkiyohara 			pay_len = xfer->recv.pay_len;
557af09db11Skiyohara 			if (asyreq->req.len >=
558af09db11Skiyohara 			    xfer->recv.pay_len + tinfo->hdr_len)
559af09db11Skiyohara 				asyreq->req.len =
560af09db11Skiyohara 				    xfer->recv.pay_len + tinfo->hdr_len;
561af09db11Skiyohara 			else {
562c1a84a4dSkiyohara 				err = EINVAL;
563c1a84a4dSkiyohara 				pay_len = 0;
564c1a84a4dSkiyohara 			}
565af09db11Skiyohara 		} else
566c1a84a4dSkiyohara 			pay_len = 0;
567e2cb8590Scegger 		memcpy(fp, &xfer->recv.hdr, tinfo->hdr_len);
568af09db11Skiyohara 		memcpy((char *)fp + tinfo->hdr_len, xfer->recv.payload,
569af09db11Skiyohara 		    pay_len);
570c1a84a4dSkiyohara out:
571c1a84a4dSkiyohara 		fw_xfer_free_buf(xfer);
572c1a84a4dSkiyohara 		break;
573c1a84a4dSkiyohara 	}
574af09db11Skiyohara 
575c1a84a4dSkiyohara 	case FW_IBUSRST:
576c1a84a4dSkiyohara 		fc->ibr(fc);
577c1a84a4dSkiyohara 		break;
578af09db11Skiyohara 
579c1a84a4dSkiyohara 	case FW_CBINDADDR:
580af09db11Skiyohara 		fwb = fw_bindlookup(fc, bindreq->start.hi, bindreq->start.lo);
581c1a84a4dSkiyohara 		if (fwb == NULL) {
582c1a84a4dSkiyohara 			err = EINVAL;
583c1a84a4dSkiyohara 			break;
584c1a84a4dSkiyohara 		}
585c1a84a4dSkiyohara 		fw_bindremove(fc, fwb);
586c1a84a4dSkiyohara 		STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist);
587c1a84a4dSkiyohara 		fw_xferlist_remove(&fwb->xferlist);
588c1a84a4dSkiyohara 		free(fwb, M_FW);
589c1a84a4dSkiyohara 		break;
590af09db11Skiyohara 
591c1a84a4dSkiyohara 	case FW_SBINDADDR:
592c1a84a4dSkiyohara 		if (bindreq->len <= 0 ) {
593c1a84a4dSkiyohara 			err = EINVAL;
594c1a84a4dSkiyohara 			break;
595c1a84a4dSkiyohara 		}
596c1a84a4dSkiyohara 		if (bindreq->start.hi > 0xffff ) {
597c1a84a4dSkiyohara 			err = EINVAL;
598c1a84a4dSkiyohara 			break;
599c1a84a4dSkiyohara 		}
60032e80c5dSchristos 		fwb = (struct fw_bind *)malloc(sizeof(struct fw_bind),
60132e80c5dSchristos 		    M_FW, M_WAITOK);
602c1a84a4dSkiyohara 		if (fwb == NULL) {
603c1a84a4dSkiyohara 			err = ENOMEM;
604c1a84a4dSkiyohara 			break;
605c1a84a4dSkiyohara 		}
606c1a84a4dSkiyohara 		fwb->start = ((u_int64_t)bindreq->start.hi << 32) |
607c1a84a4dSkiyohara 		    bindreq->start.lo;
608c1a84a4dSkiyohara 		fwb->end = fwb->start +  bindreq->len;
609c1a84a4dSkiyohara 		fwb->sc = (void *)d;
610c1a84a4dSkiyohara 		STAILQ_INIT(&fwb->xferlist);
611c1a84a4dSkiyohara 		err = fw_bindadd(fc, fwb);
612c1a84a4dSkiyohara 		if (err == 0) {
613fc04895eSdsl 			fw_xferlist_add(&fwb->xferlist, M_FW,
614c1a84a4dSkiyohara 			    /* XXX */
615af09db11Skiyohara 			    PAGE_SIZE, PAGE_SIZE, 5, fc, (void *)fwb, fw_hand);
616c1a84a4dSkiyohara 			STAILQ_INSERT_TAIL(&d->binds, fwb, chlist);
617b76f52ceSmaxv 		} else {
618b76f52ceSmaxv 			free(fwb, M_FW);
619c1a84a4dSkiyohara 		}
620c1a84a4dSkiyohara 		break;
621af09db11Skiyohara 
622c1a84a4dSkiyohara 	case FW_GDEVLST:
623c1a84a4dSkiyohara 		i = len = 1;
624c1a84a4dSkiyohara 		/* myself */
625af09db11Skiyohara 		devinfo = fwdevlst->dev;
626c1a84a4dSkiyohara 		devinfo->dst = fc->nodeid;
627c1a84a4dSkiyohara 		devinfo->status = 0;	/* XXX */
628c1a84a4dSkiyohara 		devinfo->eui.hi = fc->eui.hi;
629c1a84a4dSkiyohara 		devinfo->eui.lo = fc->eui.lo;
630c1a84a4dSkiyohara 		STAILQ_FOREACH(fwdev, &fc->devices, link) {
631c1a84a4dSkiyohara 			if (len < FW_MAX_DEVLST) {
632c1a84a4dSkiyohara 				devinfo = &fwdevlst->dev[len++];
633c1a84a4dSkiyohara 				devinfo->dst = fwdev->dst;
634c1a84a4dSkiyohara 				devinfo->status =
635c1a84a4dSkiyohara 				    (fwdev->status == FWDEVINVAL) ? 0 : 1;
636c1a84a4dSkiyohara 				devinfo->eui.hi = fwdev->eui.hi;
637c1a84a4dSkiyohara 				devinfo->eui.lo = fwdev->eui.lo;
638c1a84a4dSkiyohara 			}
639c1a84a4dSkiyohara 			i++;
640c1a84a4dSkiyohara 		}
641c1a84a4dSkiyohara 		fwdevlst->n = i;
642c1a84a4dSkiyohara 		fwdevlst->info_len = len;
643c1a84a4dSkiyohara 		break;
644af09db11Skiyohara 
645c1a84a4dSkiyohara 	case FW_GTPMAP:
646e2cb8590Scegger 		memcpy(data, fc->topology_map,
647c1a84a4dSkiyohara 		    (fc->topology_map->crc_len + 1) * 4);
648c1a84a4dSkiyohara 		break;
649af09db11Skiyohara 
650c1a84a4dSkiyohara 	case FW_GCROM:
651c1a84a4dSkiyohara 		STAILQ_FOREACH(fwdev, &fc->devices, link)
652c1a84a4dSkiyohara 			if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui))
653c1a84a4dSkiyohara 				break;
654c1a84a4dSkiyohara 		if (fwdev == NULL) {
655c1a84a4dSkiyohara 			if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) {
656c1a84a4dSkiyohara 				err = FWNODE_INVAL;
657c1a84a4dSkiyohara 				break;
658c1a84a4dSkiyohara 			}
659c1a84a4dSkiyohara 			/* myself */
66032e80c5dSchristos 			ptr = malloc(CROMSIZE, M_FW, M_WAITOK);
661c1a84a4dSkiyohara 			len = CROMSIZE;
662c1a84a4dSkiyohara 			for (i = 0; i < CROMSIZE/4; i++)
663af09db11Skiyohara 				((uint32_t *)ptr)[i] = ntohl(fc->config_rom[i]);
664c1a84a4dSkiyohara 		} else {
665c1a84a4dSkiyohara 			/* found */
666af09db11Skiyohara 			ptr = (void *)fwdev->csrrom;
667c1a84a4dSkiyohara 			if (fwdev->rommax < CSRROMOFF)
668c1a84a4dSkiyohara 				len = 0;
669c1a84a4dSkiyohara 			else
670c1a84a4dSkiyohara 				len = fwdev->rommax - CSRROMOFF + 4;
671c1a84a4dSkiyohara 		}
672e0f8f596Sjdolecek 		if (crom_buf->len < len)
673c1a84a4dSkiyohara 			len = crom_buf->len;
674c1a84a4dSkiyohara 		else
675c1a84a4dSkiyohara 			crom_buf->len = len;
676c1a84a4dSkiyohara 		err = copyout(ptr, crom_buf->ptr, len);
677c1a84a4dSkiyohara 		if (fwdev == NULL)
678c1a84a4dSkiyohara 			/* myself */
67932e80c5dSchristos 			free(ptr, M_FW);
680c1a84a4dSkiyohara 		break;
681af09db11Skiyohara 
682c1a84a4dSkiyohara 	default:
683af09db11Skiyohara 		fc->ioctl(dev, cmd, data, flag, td);
684c1a84a4dSkiyohara 		break;
685c1a84a4dSkiyohara 	}
686c1a84a4dSkiyohara 	return err;
687c1a84a4dSkiyohara }
688c1a84a4dSkiyohara 
689af09db11Skiyohara int
fw_poll(dev_t dev,int events,struct lwp * td)690af09db11Skiyohara fw_poll(dev_t dev, int events, struct lwp *td)
691c1a84a4dSkiyohara {
692af09db11Skiyohara 	struct firewire_softc *sc;
693c1a84a4dSkiyohara 	struct fw_xferq *ir;
694af09db11Skiyohara 	int revents, tmp;
695c1a84a4dSkiyohara 
696af09db11Skiyohara 	sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev));
697af09db11Skiyohara 	if (sc == NULL)
698af09db11Skiyohara 		return ENXIO;
699c1a84a4dSkiyohara 
700af09db11Skiyohara 	ir = ((struct fw_drv1 *)sc->si_drv1)->ir;
701c1a84a4dSkiyohara 	revents = 0;
702c1a84a4dSkiyohara 	tmp = POLLIN | POLLRDNORM;
703c1a84a4dSkiyohara 	if (events & tmp) {
704c1a84a4dSkiyohara 		if (STAILQ_FIRST(&ir->q) != NULL)
705c1a84a4dSkiyohara 			revents |= tmp;
706c1a84a4dSkiyohara 		else
707c1a84a4dSkiyohara 			selrecord(td, &ir->rsel);
708c1a84a4dSkiyohara 	}
709c1a84a4dSkiyohara 	tmp = POLLOUT | POLLWRNORM;
710af09db11Skiyohara 	if (events & tmp)
711c1a84a4dSkiyohara 		/* XXX should be fixed */
712c1a84a4dSkiyohara 		revents |= tmp;
713c1a84a4dSkiyohara 
714c1a84a4dSkiyohara 	return revents;
715c1a84a4dSkiyohara }
716c1a84a4dSkiyohara 
717af09db11Skiyohara paddr_t
fw_mmap(dev_t dev,off_t offset,int nproto)718af09db11Skiyohara fw_mmap(dev_t dev, off_t offset, int nproto)
719c1a84a4dSkiyohara {
720af09db11Skiyohara 	struct firewire_softc *sc;
721c1a84a4dSkiyohara 
722af09db11Skiyohara 	sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev));
723af09db11Skiyohara 	if (sc == NULL)
724af09db11Skiyohara 		return ENXIO;
725c1a84a4dSkiyohara 
726c1a84a4dSkiyohara 	return EINVAL;
727c1a84a4dSkiyohara }
728c1a84a4dSkiyohara 
729c1a84a4dSkiyohara void
fw_strategy(struct bio * bp)730c1a84a4dSkiyohara fw_strategy(struct bio *bp)
731c1a84a4dSkiyohara {
732af09db11Skiyohara 	struct firewire_softc *sc;
733af09db11Skiyohara 	dev_t dev = bp->bio_dev;
734c1a84a4dSkiyohara 
735af09db11Skiyohara 	sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev));
736af09db11Skiyohara 	if (sc == NULL)
737af09db11Skiyohara 		return;
738af09db11Skiyohara 
739af09db11Skiyohara 	if (DEV_FWMEM(dev)) {
740af09db11Skiyohara 		fwmem_strategy(bp);
741af09db11Skiyohara 		return;
742af09db11Skiyohara 	}
743c1a84a4dSkiyohara 
744c1a84a4dSkiyohara 	bp->bio_error = EOPNOTSUPP;
745c1a84a4dSkiyohara 	bp->bio_resid = bp->bio_bcount;
746c1a84a4dSkiyohara 	biodone(bp);
747c1a84a4dSkiyohara }
748c1a84a4dSkiyohara 
749af09db11Skiyohara 
750af09db11Skiyohara static int
fwdev_allocbuf(struct firewire_comm * fc,struct fw_xferq * q,struct fw_bufspec * b)751af09db11Skiyohara fwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q,
752af09db11Skiyohara 	       struct fw_bufspec *b)
753c1a84a4dSkiyohara {
754af09db11Skiyohara 	int i;
755af09db11Skiyohara 
756af09db11Skiyohara 	if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF))
757af09db11Skiyohara 		return EBUSY;
758af09db11Skiyohara 
759af09db11Skiyohara 	q->bulkxfer =
76032e80c5dSchristos 	    (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * b->nchunk,
76132e80c5dSchristos 								M_FW, M_WAITOK);
762af09db11Skiyohara 	if (q->bulkxfer == NULL)
763af09db11Skiyohara 		return ENOMEM;
764af09db11Skiyohara 
765af09db11Skiyohara 	b->psize = roundup2(b->psize, sizeof(uint32_t));
766af09db11Skiyohara 	q->buf = fwdma_malloc_multiseg(fc, sizeof(uint32_t), b->psize,
767af09db11Skiyohara 	    b->nchunk * b->npacket, BUS_DMA_WAITOK);
768af09db11Skiyohara 
769af09db11Skiyohara 	if (q->buf == NULL) {
77032e80c5dSchristos 		free(q->bulkxfer, M_FW);
771af09db11Skiyohara 		q->bulkxfer = NULL;
772af09db11Skiyohara 		return ENOMEM;
773af09db11Skiyohara 	}
774af09db11Skiyohara 	q->bnchunk = b->nchunk;
775af09db11Skiyohara 	q->bnpacket = b->npacket;
776af09db11Skiyohara 	q->psize = (b->psize + 3) & ~3;
777af09db11Skiyohara 	q->queued = 0;
778af09db11Skiyohara 
779af09db11Skiyohara 	STAILQ_INIT(&q->stvalid);
780af09db11Skiyohara 	STAILQ_INIT(&q->stfree);
781af09db11Skiyohara 	STAILQ_INIT(&q->stdma);
782af09db11Skiyohara 	q->stproc = NULL;
783af09db11Skiyohara 
784af09db11Skiyohara 	for (i = 0 ; i < q->bnchunk; i++) {
785af09db11Skiyohara 		q->bulkxfer[i].poffset = i * q->bnpacket;
786af09db11Skiyohara 		q->bulkxfer[i].mbuf = NULL;
787af09db11Skiyohara 		STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link);
788af09db11Skiyohara 	}
789af09db11Skiyohara 
790af09db11Skiyohara 	q->flag &= ~FWXFERQ_MODEMASK;
791af09db11Skiyohara 	q->flag |= FWXFERQ_STREAM;
792af09db11Skiyohara 	q->flag |= FWXFERQ_EXTBUF;
793af09db11Skiyohara 
794af09db11Skiyohara 	return 0;
795af09db11Skiyohara }
796af09db11Skiyohara 
797af09db11Skiyohara static int
fwdev_freebuf(struct fw_xferq * q)79832e80c5dSchristos fwdev_freebuf(struct fw_xferq *q)
799af09db11Skiyohara {
800af09db11Skiyohara 
801af09db11Skiyohara 	if (q->flag & FWXFERQ_EXTBUF) {
802af09db11Skiyohara 		if (q->buf != NULL)
803af09db11Skiyohara 			fwdma_free_multiseg(q->buf);
804af09db11Skiyohara 		q->buf = NULL;
80532e80c5dSchristos 		free(q->bulkxfer, M_FW);
806af09db11Skiyohara 		q->bulkxfer = NULL;
807af09db11Skiyohara 		q->flag &= ~FWXFERQ_EXTBUF;
808af09db11Skiyohara 		q->psize = 0;
809af09db11Skiyohara 		q->maxq = FWMAXQUEUE;
810af09db11Skiyohara 	}
811af09db11Skiyohara 	return 0;
812af09db11Skiyohara }
813af09db11Skiyohara 
814af09db11Skiyohara static int
fw_read_async(struct fw_drv1 * d,struct uio * uio,int ioflag)815af09db11Skiyohara fw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag)
816af09db11Skiyohara {
817af09db11Skiyohara 	struct fw_xfer *xfer;
818af09db11Skiyohara 	struct fw_bind *fwb;
819af09db11Skiyohara 	struct fw_pkt *fp;
820af09db11Skiyohara 	const struct tcode_info *tinfo;
821c1a84a4dSkiyohara 	int err = 0;
822c1a84a4dSkiyohara 
823af09db11Skiyohara 	mutex_enter(&d->fc->fc_mtx);
824c1a84a4dSkiyohara 
8250fd1c016Scegger 	for (;;) {
8260fd1c016Scegger 		xfer = STAILQ_FIRST(&d->rq);
8270fd1c016Scegger 		if (xfer == NULL && err == 0) {
8281ebf7dd1Sriastradh 			err = cv_wait_sig(&d->cv, &d->fc->fc_mtx);
8291ebf7dd1Sriastradh 			if (err) {
830af09db11Skiyohara 				mutex_exit(&d->fc->fc_mtx);
831af09db11Skiyohara 				return err;
8321ebf7dd1Sriastradh 			}
8330fd1c016Scegger 			continue;
8340fd1c016Scegger 		}
8350fd1c016Scegger 		break;
836c1a84a4dSkiyohara 	}
837c1a84a4dSkiyohara 
838af09db11Skiyohara 	STAILQ_REMOVE_HEAD(&d->rq, link);
839af09db11Skiyohara 	mutex_exit(&d->fc->fc_mtx);
840af09db11Skiyohara 	fp = &xfer->recv.hdr;
841af09db11Skiyohara #if 0 /* for GASP ?? */
842af09db11Skiyohara 	if (fc->irx_post != NULL)
843af09db11Skiyohara 		fc->irx_post(fc, fp->mode.ld);
844af09db11Skiyohara #endif
845af09db11Skiyohara 	tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode];
846af09db11Skiyohara 	err = uiomove((void *)fp, tinfo->hdr_len, uio);
847af09db11Skiyohara 	if (err)
848af09db11Skiyohara 		goto out;
849af09db11Skiyohara 	err = uiomove((void *)xfer->recv.payload, xfer->recv.pay_len, uio);
850af09db11Skiyohara 
851af09db11Skiyohara out:
852af09db11Skiyohara 	/* recycle this xfer */
853af09db11Skiyohara 	fwb = (struct fw_bind *)xfer->sc;
854af09db11Skiyohara 	fw_xfer_unload(xfer);
855af09db11Skiyohara 	xfer->recv.pay_len = PAGE_SIZE;
856af09db11Skiyohara 	mutex_enter(&d->fc->fc_mtx);
857af09db11Skiyohara 	STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link);
858af09db11Skiyohara 	mutex_exit(&d->fc->fc_mtx);
859af09db11Skiyohara 	return err;
860af09db11Skiyohara }
861af09db11Skiyohara 
862af09db11Skiyohara static int
fw_write_async(struct fw_drv1 * d,struct uio * uio,int ioflag)863af09db11Skiyohara fw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag)
864c1a84a4dSkiyohara {
865af09db11Skiyohara 	struct fw_xfer *xfer;
866af09db11Skiyohara 	struct fw_pkt pkt;
867af09db11Skiyohara 	const struct tcode_info *tinfo;
868af09db11Skiyohara 	int err;
869c1a84a4dSkiyohara 
870af09db11Skiyohara 	memset(&pkt, 0, sizeof(struct fw_pkt));
871af09db11Skiyohara 	if ((err = uiomove((void *)&pkt, sizeof(uint32_t), uio)))
872af09db11Skiyohara 		return err;
873af09db11Skiyohara 	tinfo = &d->fc->tcode[pkt.mode.hdr.tcode];
874af09db11Skiyohara 	if ((err = uiomove((char *)&pkt + sizeof(uint32_t),
875af09db11Skiyohara 	    tinfo->hdr_len - sizeof(uint32_t), uio)))
876af09db11Skiyohara 		return err;
877c1a84a4dSkiyohara 
878fc04895eSdsl 	if ((xfer = fw_xfer_alloc_buf(M_FW, uio->uio_resid,
879af09db11Skiyohara 	    PAGE_SIZE/*XXX*/)) == NULL)
880af09db11Skiyohara 		return ENOMEM;
881af09db11Skiyohara 
882af09db11Skiyohara 	memcpy(&xfer->send.hdr, &pkt, sizeof(struct fw_pkt));
883af09db11Skiyohara 	xfer->send.pay_len = uio->uio_resid;
884af09db11Skiyohara 	if (uio->uio_resid > 0) {
885af09db11Skiyohara 		if ((err =
886af09db11Skiyohara 		    uiomove((void *)xfer->send.payload, uio->uio_resid, uio)))
887af09db11Skiyohara 			goto out;
888c1a84a4dSkiyohara 	}
889c1a84a4dSkiyohara 
890af09db11Skiyohara 	xfer->fc = d->fc;
891af09db11Skiyohara 	xfer->sc = NULL;
892af09db11Skiyohara 	xfer->hand = fw_xferwake;
893af09db11Skiyohara 	xfer->send.spd = 2 /* XXX */;
894af09db11Skiyohara 
895af09db11Skiyohara 	if ((err = fw_asyreq(xfer->fc, -1, xfer)))
896af09db11Skiyohara 		goto out;
897af09db11Skiyohara 
898af09db11Skiyohara 	if ((err = fw_xferwait(xfer)))
899af09db11Skiyohara 		goto out;
900af09db11Skiyohara 
901af09db11Skiyohara 	if (xfer->resp != 0) {
902af09db11Skiyohara 		err = xfer->resp;
903af09db11Skiyohara 		goto out;
904af09db11Skiyohara 	}
905af09db11Skiyohara 
906af09db11Skiyohara 	if (xfer->flag == FWXF_RCVD) {
907af09db11Skiyohara 		mutex_enter(&xfer->fc->fc_mtx);
908af09db11Skiyohara 		STAILQ_INSERT_TAIL(&d->rq, xfer, link);
909af09db11Skiyohara 		mutex_exit(&xfer->fc->fc_mtx);
910af09db11Skiyohara 		return 0;
911af09db11Skiyohara 	}
912af09db11Skiyohara 
913af09db11Skiyohara out:
914af09db11Skiyohara 	fw_xfer_free(xfer);
915af09db11Skiyohara 	return err;
916af09db11Skiyohara }
917af09db11Skiyohara 
918af09db11Skiyohara static void
fw_hand(struct fw_xfer * xfer)919af09db11Skiyohara fw_hand(struct fw_xfer *xfer)
920c1a84a4dSkiyohara {
921af09db11Skiyohara 	struct fw_bind *fwb;
922af09db11Skiyohara 	struct fw_drv1 *d;
923c1a84a4dSkiyohara 
924af09db11Skiyohara 	fwb = (struct fw_bind *)xfer->sc;
925af09db11Skiyohara 	d = (struct fw_drv1 *)fwb->sc;
926af09db11Skiyohara 	mutex_enter(&xfer->fc->fc_mtx);
927af09db11Skiyohara 	STAILQ_INSERT_TAIL(&d->rq, xfer, link);
9281ebf7dd1Sriastradh 	cv_broadcast(&d->cv);
929af09db11Skiyohara 	mutex_exit(&xfer->fc->fc_mtx);
930c1a84a4dSkiyohara }
931