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