xref: /freebsd/sys/dev/firewire/fwmem.c (revision 1bba1572a057d2c6201a7f1aaba5b92763cf9773)
13c60ba66SKatsushi Kobayashi /*
277ee030bSHidetoshi Shimokawa  * Copyright (c) 2002-2003
33c60ba66SKatsushi Kobayashi  * 	Hidetoshi Shimokawa. All rights reserved.
43c60ba66SKatsushi Kobayashi  *
53c60ba66SKatsushi Kobayashi  * Redistribution and use in source and binary forms, with or without
63c60ba66SKatsushi Kobayashi  * modification, are permitted provided that the following conditions
73c60ba66SKatsushi Kobayashi  * are met:
83c60ba66SKatsushi Kobayashi  * 1. Redistributions of source code must retain the above copyright
93c60ba66SKatsushi Kobayashi  *    notice, this list of conditions and the following disclaimer.
103c60ba66SKatsushi Kobayashi  * 2. Redistributions in binary form must reproduce the above copyright
113c60ba66SKatsushi Kobayashi  *    notice, this list of conditions and the following disclaimer in the
123c60ba66SKatsushi Kobayashi  *    documentation and/or other materials provided with the distribution.
133c60ba66SKatsushi Kobayashi  * 3. All advertising materials mentioning features or use of this software
143c60ba66SKatsushi Kobayashi  *    must display the following acknowledgement:
153c60ba66SKatsushi Kobayashi  *
163c60ba66SKatsushi Kobayashi  *	This product includes software developed by Hidetoshi Shimokawa.
173c60ba66SKatsushi Kobayashi  *
183c60ba66SKatsushi Kobayashi  * 4. Neither the name of the author nor the names of its contributors
193c60ba66SKatsushi Kobayashi  *    may be used to endorse or promote products derived from this software
203c60ba66SKatsushi Kobayashi  *    without specific prior written permission.
213c60ba66SKatsushi Kobayashi  *
223c60ba66SKatsushi Kobayashi  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
233c60ba66SKatsushi Kobayashi  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
243c60ba66SKatsushi Kobayashi  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
253c60ba66SKatsushi Kobayashi  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
263c60ba66SKatsushi Kobayashi  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
273c60ba66SKatsushi Kobayashi  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
283c60ba66SKatsushi Kobayashi  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
293c60ba66SKatsushi Kobayashi  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
303c60ba66SKatsushi Kobayashi  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
313c60ba66SKatsushi Kobayashi  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
323c60ba66SKatsushi Kobayashi  * SUCH DAMAGE.
333c60ba66SKatsushi Kobayashi  *
343c60ba66SKatsushi Kobayashi  * $FreeBSD$
353c60ba66SKatsushi Kobayashi  */
363c60ba66SKatsushi Kobayashi 
373c60ba66SKatsushi Kobayashi #include <sys/param.h>
383c60ba66SKatsushi Kobayashi #include <sys/systm.h>
393c60ba66SKatsushi Kobayashi #include <sys/types.h>
403c60ba66SKatsushi Kobayashi 
413c60ba66SKatsushi Kobayashi #include <sys/kernel.h>
423c60ba66SKatsushi Kobayashi #include <sys/malloc.h>
433c60ba66SKatsushi Kobayashi #include <sys/conf.h>
443c60ba66SKatsushi Kobayashi #include <sys/sysctl.h>
453c60ba66SKatsushi Kobayashi 
463c60ba66SKatsushi Kobayashi #include <sys/bus.h>
4777ee030bSHidetoshi Shimokawa #include <machine/bus.h>
483c60ba66SKatsushi Kobayashi 
493c60ba66SKatsushi Kobayashi #include <sys/signal.h>
503c60ba66SKatsushi Kobayashi #include <sys/mman.h>
513c60ba66SKatsushi Kobayashi #include <sys/ioccom.h>
523c60ba66SKatsushi Kobayashi 
533c60ba66SKatsushi Kobayashi #include <dev/firewire/firewire.h>
543c60ba66SKatsushi Kobayashi #include <dev/firewire/firewirereg.h>
553c60ba66SKatsushi Kobayashi #include <dev/firewire/fwmem.h>
563c60ba66SKatsushi Kobayashi 
57f90ce7b1SHidetoshi Shimokawa static int fwmem_speed=2, fwmem_debug=0;
58f90ce7b1SHidetoshi Shimokawa static struct fw_eui64 fwmem_eui64;
593c60ba66SKatsushi Kobayashi SYSCTL_DECL(_hw_firewire);
603c60ba66SKatsushi Kobayashi SYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0,
61ee126d67SHidetoshi Shimokawa 	"FireWire Memory Access");
62f90ce7b1SHidetoshi Shimokawa SYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW,
63f90ce7b1SHidetoshi Shimokawa 	&fwmem_eui64.hi, 0, "Fwmem target EUI64 high");
64233b1b97SHidetoshi Shimokawa SYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_lo, CTLFLAG_RW,
65f90ce7b1SHidetoshi Shimokawa 	&fwmem_eui64.lo, 0, "Fwmem target EUI64 low");
663c60ba66SKatsushi Kobayashi SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0,
673c60ba66SKatsushi Kobayashi 	"Fwmem link speed");
683c60ba66SKatsushi Kobayashi SYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0,
693c60ba66SKatsushi Kobayashi 	"Fwmem driver debug flag");
703c60ba66SKatsushi Kobayashi 
71d6ec5885SHidetoshi Shimokawa static struct fw_xfer *
72d6ec5885SHidetoshi Shimokawa fwmem_xfer_req(
73d6ec5885SHidetoshi Shimokawa 	struct fw_device *fwdev,
74d6ec5885SHidetoshi Shimokawa 	caddr_t sc,
75d6ec5885SHidetoshi Shimokawa 	int spd,
7677ee030bSHidetoshi Shimokawa 	int slen,
7777ee030bSHidetoshi Shimokawa 	int rlen,
78d6ec5885SHidetoshi Shimokawa 	void *hand)
79d6ec5885SHidetoshi Shimokawa {
80d6ec5885SHidetoshi Shimokawa 	struct fw_xfer *xfer;
81d6ec5885SHidetoshi Shimokawa 
8277ee030bSHidetoshi Shimokawa 	xfer = fw_xfer_alloc_buf(M_FWXFER, slen, rlen);
83d6ec5885SHidetoshi Shimokawa 	if (xfer == NULL)
84d6ec5885SHidetoshi Shimokawa 		return NULL;
85d6ec5885SHidetoshi Shimokawa 
86d6ec5885SHidetoshi Shimokawa 	xfer->fc = fwdev->fc;
87d6ec5885SHidetoshi Shimokawa 	xfer->dst = FWLOCALBUS | fwdev->dst;
88d6ec5885SHidetoshi Shimokawa 	if (spd < 0)
89d6ec5885SHidetoshi Shimokawa 		xfer->spd = fwdev->speed;
90d6ec5885SHidetoshi Shimokawa 	else
91d6ec5885SHidetoshi Shimokawa 		xfer->spd = min(spd, fwdev->speed);
92d6ec5885SHidetoshi Shimokawa 	xfer->act.hand = hand;
93d6ec5885SHidetoshi Shimokawa 	xfer->retry_req = fw_asybusy;
94d6ec5885SHidetoshi Shimokawa 	xfer->sc = sc;
95d6ec5885SHidetoshi Shimokawa 
96d6ec5885SHidetoshi Shimokawa 	return xfer;
97d6ec5885SHidetoshi Shimokawa }
98d6ec5885SHidetoshi Shimokawa 
993c60ba66SKatsushi Kobayashi struct fw_xfer *
1003c60ba66SKatsushi Kobayashi fwmem_read_quad(
101f90ce7b1SHidetoshi Shimokawa 	struct fw_device *fwdev,
102f90ce7b1SHidetoshi Shimokawa 	caddr_t	sc,
103c3b09522SHidetoshi Shimokawa 	u_int8_t spd,
1043c60ba66SKatsushi Kobayashi 	u_int16_t dst_hi,
105c3b09522SHidetoshi Shimokawa 	u_int32_t dst_lo,
106c3b09522SHidetoshi Shimokawa 	void (*hand)(struct fw_xfer *))
1073c60ba66SKatsushi Kobayashi {
1083c60ba66SKatsushi Kobayashi 	struct fw_xfer *xfer;
1093c60ba66SKatsushi Kobayashi 	struct fw_pkt *fp;
1103c60ba66SKatsushi Kobayashi 
11177ee030bSHidetoshi Shimokawa 	xfer = fwmem_xfer_req(fwdev, sc, spd, 12, 16, hand);
112c3b09522SHidetoshi Shimokawa 	if (xfer == NULL)
1133c60ba66SKatsushi Kobayashi 		return NULL;
114c3b09522SHidetoshi Shimokawa 
1153c60ba66SKatsushi Kobayashi 	fp = (struct fw_pkt *)xfer->send.buf;
1163c60ba66SKatsushi Kobayashi 	fp->mode.rreqq.tcode = FWTCODE_RREQQ;
11777ee030bSHidetoshi Shimokawa 	fp->mode.rreqq.dst = xfer->dst;
11877ee030bSHidetoshi Shimokawa 	fp->mode.rreqq.dest_hi = dst_hi;
11977ee030bSHidetoshi Shimokawa 	fp->mode.rreqq.dest_lo = dst_lo;
1203c60ba66SKatsushi Kobayashi 
1213c60ba66SKatsushi Kobayashi 	if (fwmem_debug)
122d6ec5885SHidetoshi Shimokawa 		printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst,
123d6ec5885SHidetoshi Shimokawa 				dst_hi, dst_lo);
124c3b09522SHidetoshi Shimokawa 
125f90ce7b1SHidetoshi Shimokawa 	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
126f90ce7b1SHidetoshi Shimokawa 		return xfer;
127f90ce7b1SHidetoshi Shimokawa 
128f90ce7b1SHidetoshi Shimokawa 	fw_xfer_free(xfer);
129f90ce7b1SHidetoshi Shimokawa 	return NULL;
130f90ce7b1SHidetoshi Shimokawa }
131f90ce7b1SHidetoshi Shimokawa 
132f90ce7b1SHidetoshi Shimokawa struct fw_xfer *
133f90ce7b1SHidetoshi Shimokawa fwmem_write_quad(
134f90ce7b1SHidetoshi Shimokawa 	struct fw_device *fwdev,
135f90ce7b1SHidetoshi Shimokawa 	caddr_t	sc,
136f90ce7b1SHidetoshi Shimokawa 	u_int8_t spd,
137f90ce7b1SHidetoshi Shimokawa 	u_int16_t dst_hi,
138f90ce7b1SHidetoshi Shimokawa 	u_int32_t dst_lo,
139f90ce7b1SHidetoshi Shimokawa 	u_int32_t data,
140f90ce7b1SHidetoshi Shimokawa 	void (*hand)(struct fw_xfer *))
141f90ce7b1SHidetoshi Shimokawa {
142f90ce7b1SHidetoshi Shimokawa 	struct fw_xfer *xfer;
143f90ce7b1SHidetoshi Shimokawa 	struct fw_pkt *fp;
144f90ce7b1SHidetoshi Shimokawa 
14577ee030bSHidetoshi Shimokawa 	xfer = fwmem_xfer_req(fwdev, sc, spd, 16, 12, hand);
146f90ce7b1SHidetoshi Shimokawa 	if (xfer == NULL)
147f90ce7b1SHidetoshi Shimokawa 		return NULL;
148f90ce7b1SHidetoshi Shimokawa 
149f90ce7b1SHidetoshi Shimokawa 	fp = (struct fw_pkt *)xfer->send.buf;
150958c7749SHidetoshi Shimokawa 	fp->mode.wreqq.tcode = FWTCODE_WREQQ;
15177ee030bSHidetoshi Shimokawa 	fp->mode.wreqq.dst = xfer->dst;
15277ee030bSHidetoshi Shimokawa 	fp->mode.wreqq.dest_hi = dst_hi;
15377ee030bSHidetoshi Shimokawa 	fp->mode.wreqq.dest_lo = dst_lo;
154f90ce7b1SHidetoshi Shimokawa 
15573aa55baSHidetoshi Shimokawa 	fp->mode.wreqq.data = data;
156f90ce7b1SHidetoshi Shimokawa 
157f90ce7b1SHidetoshi Shimokawa 	if (fwmem_debug)
158d6ec5885SHidetoshi Shimokawa 		printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst,
159d6ec5885SHidetoshi Shimokawa 			dst_hi, dst_lo, data);
160f90ce7b1SHidetoshi Shimokawa 
161f90ce7b1SHidetoshi Shimokawa 	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
1623c60ba66SKatsushi Kobayashi 		return xfer;
163c3b09522SHidetoshi Shimokawa 
1643c60ba66SKatsushi Kobayashi 	fw_xfer_free(xfer);
1653c60ba66SKatsushi Kobayashi 	return NULL;
1663c60ba66SKatsushi Kobayashi }
1673c60ba66SKatsushi Kobayashi 
1683c60ba66SKatsushi Kobayashi struct fw_xfer *
1693c60ba66SKatsushi Kobayashi fwmem_read_block(
170f90ce7b1SHidetoshi Shimokawa 	struct fw_device *fwdev,
171f90ce7b1SHidetoshi Shimokawa 	caddr_t	sc,
172c3b09522SHidetoshi Shimokawa 	u_int8_t spd,
1733c60ba66SKatsushi Kobayashi 	u_int16_t dst_hi,
1743c60ba66SKatsushi Kobayashi 	u_int32_t dst_lo,
175c3b09522SHidetoshi Shimokawa 	int len,
176c3b09522SHidetoshi Shimokawa 	void (*hand)(struct fw_xfer *))
1773c60ba66SKatsushi Kobayashi {
1783c60ba66SKatsushi Kobayashi 	struct fw_xfer *xfer;
1793c60ba66SKatsushi Kobayashi 	struct fw_pkt *fp;
1803c60ba66SKatsushi Kobayashi 
18177ee030bSHidetoshi Shimokawa 	xfer = fwmem_xfer_req(fwdev, sc, spd, 16, roundup2(16+len,4), hand);
182c3b09522SHidetoshi Shimokawa 	if (xfer == NULL)
1833c60ba66SKatsushi Kobayashi 		return NULL;
184c3b09522SHidetoshi Shimokawa 
1853c60ba66SKatsushi Kobayashi 	fp = (struct fw_pkt *)xfer->send.buf;
1863c60ba66SKatsushi Kobayashi 	fp->mode.rreqb.tcode = FWTCODE_RREQB;
18777ee030bSHidetoshi Shimokawa 	fp->mode.rreqb.dst = xfer->dst;
18877ee030bSHidetoshi Shimokawa 	fp->mode.rreqb.dest_hi = dst_hi;
18977ee030bSHidetoshi Shimokawa 	fp->mode.rreqb.dest_lo = dst_lo;
19077ee030bSHidetoshi Shimokawa 	fp->mode.rreqb.len = len;
1913c60ba66SKatsushi Kobayashi 
1923c60ba66SKatsushi Kobayashi 	if (fwmem_debug)
193d6ec5885SHidetoshi Shimokawa 		printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst,
194f90ce7b1SHidetoshi Shimokawa 				dst_hi, dst_lo, len);
195f90ce7b1SHidetoshi Shimokawa 	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
1963c60ba66SKatsushi Kobayashi 		return xfer;
197c3b09522SHidetoshi Shimokawa 
1983c60ba66SKatsushi Kobayashi 	fw_xfer_free(xfer);
1993c60ba66SKatsushi Kobayashi 	return NULL;
2003c60ba66SKatsushi Kobayashi }
2013c60ba66SKatsushi Kobayashi 
2028a45d99bSHidetoshi Shimokawa struct fw_xfer *
2038a45d99bSHidetoshi Shimokawa fwmem_write_block(
2048a45d99bSHidetoshi Shimokawa 	struct fw_device *fwdev,
2058a45d99bSHidetoshi Shimokawa 	caddr_t	sc,
2068a45d99bSHidetoshi Shimokawa 	u_int8_t spd,
2078a45d99bSHidetoshi Shimokawa 	u_int16_t dst_hi,
2088a45d99bSHidetoshi Shimokawa 	u_int32_t dst_lo,
2098a45d99bSHidetoshi Shimokawa 	int len,
2108a45d99bSHidetoshi Shimokawa 	char *data,
2118a45d99bSHidetoshi Shimokawa 	void (*hand)(struct fw_xfer *))
2128a45d99bSHidetoshi Shimokawa {
2138a45d99bSHidetoshi Shimokawa 	struct fw_xfer *xfer;
2148a45d99bSHidetoshi Shimokawa 	struct fw_pkt *fp;
2158a45d99bSHidetoshi Shimokawa 
21677ee030bSHidetoshi Shimokawa 	xfer = fwmem_xfer_req(fwdev, sc, spd, roundup(16+len, 4), 12, hand);
2178a45d99bSHidetoshi Shimokawa 	if (xfer == NULL)
2188a45d99bSHidetoshi Shimokawa 		return NULL;
2198a45d99bSHidetoshi Shimokawa 
2208a45d99bSHidetoshi Shimokawa 	fp = (struct fw_pkt *)xfer->send.buf;
2215db3899dSHidetoshi Shimokawa 	fp->mode.wreqb.tcode = FWTCODE_WREQB;
22277ee030bSHidetoshi Shimokawa 	fp->mode.wreqb.dst = xfer->dst;
22377ee030bSHidetoshi Shimokawa 	fp->mode.wreqb.dest_hi = dst_hi;
22477ee030bSHidetoshi Shimokawa 	fp->mode.wreqb.dest_lo = dst_lo;
22577ee030bSHidetoshi Shimokawa 	fp->mode.wreqb.len = len;
2268a45d99bSHidetoshi Shimokawa 	bcopy(data, &fp->mode.wreqb.payload[0], len);
2278a45d99bSHidetoshi Shimokawa 
2288a45d99bSHidetoshi Shimokawa 	if (fwmem_debug)
2298a45d99bSHidetoshi Shimokawa 		printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev->dst,
2308a45d99bSHidetoshi Shimokawa 				dst_hi, dst_lo, len);
2318a45d99bSHidetoshi Shimokawa 	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
2328a45d99bSHidetoshi Shimokawa 		return xfer;
2338a45d99bSHidetoshi Shimokawa 
2348a45d99bSHidetoshi Shimokawa 	fw_xfer_free(xfer);
2358a45d99bSHidetoshi Shimokawa 	return NULL;
2368a45d99bSHidetoshi Shimokawa }
2378a45d99bSHidetoshi Shimokawa 
2388a45d99bSHidetoshi Shimokawa 
2393c60ba66SKatsushi Kobayashi int
2403c60ba66SKatsushi Kobayashi fwmem_open (dev_t dev, int flags, int fmt, fw_proc *td)
2413c60ba66SKatsushi Kobayashi {
242233b1b97SHidetoshi Shimokawa 	struct fw_eui64 *eui;
243233b1b97SHidetoshi Shimokawa 
2441bba1572SHidetoshi Shimokawa 	if (dev->si_drv1 != NULL)
2451bba1572SHidetoshi Shimokawa 		return (EBUSY);
2461bba1572SHidetoshi Shimokawa 
24777ee030bSHidetoshi Shimokawa 	eui = (struct fw_eui64 *)malloc(sizeof(struct fw_eui64),
24877ee030bSHidetoshi Shimokawa 							M_FW, M_WAITOK);
249233b1b97SHidetoshi Shimokawa 	if (eui == NULL)
250233b1b97SHidetoshi Shimokawa 		return ENOMEM;
251233b1b97SHidetoshi Shimokawa 	bcopy(&fwmem_eui64, eui, sizeof(struct fw_eui64));
252233b1b97SHidetoshi Shimokawa 	dev->si_drv1 = (void *)eui;
253233b1b97SHidetoshi Shimokawa 
254233b1b97SHidetoshi Shimokawa 	return (0);
2553c60ba66SKatsushi Kobayashi }
2563c60ba66SKatsushi Kobayashi 
2573c60ba66SKatsushi Kobayashi int
2583c60ba66SKatsushi Kobayashi fwmem_close (dev_t dev, int flags, int fmt, fw_proc *td)
2593c60ba66SKatsushi Kobayashi {
260233b1b97SHidetoshi Shimokawa 	free(dev->si_drv1, M_FW);
2611bba1572SHidetoshi Shimokawa 	dev->si_drv1 = NULL;
2621bba1572SHidetoshi Shimokawa 
263233b1b97SHidetoshi Shimokawa 	return (0);
2643c60ba66SKatsushi Kobayashi }
2653c60ba66SKatsushi Kobayashi 
2663c60ba66SKatsushi Kobayashi #define MAXLEN 2048
2673c60ba66SKatsushi Kobayashi #define USE_QUAD 0
2683c60ba66SKatsushi Kobayashi int
2693c60ba66SKatsushi Kobayashi fwmem_read (dev_t dev, struct uio *uio, int ioflag)
2703c60ba66SKatsushi Kobayashi {
2713c60ba66SKatsushi Kobayashi 	struct firewire_softc *sc;
272f90ce7b1SHidetoshi Shimokawa 	struct fw_device *fwdev;
2733c60ba66SKatsushi Kobayashi 	struct fw_xfer *xfer;
2748a45d99bSHidetoshi Shimokawa 	int err = 0;
2753c60ba66SKatsushi Kobayashi         int unit = DEV2UNIT(dev);
2763c60ba66SKatsushi Kobayashi 	u_int16_t dst_hi;
2773c60ba66SKatsushi Kobayashi 	u_int32_t dst_lo;
2783c60ba66SKatsushi Kobayashi 	off_t offset;
2793c60ba66SKatsushi Kobayashi 	int len;
2803c60ba66SKatsushi Kobayashi 
2813c60ba66SKatsushi Kobayashi 	sc = devclass_get_softc(firewire_devclass, unit);
282233b1b97SHidetoshi Shimokawa 	fwdev = fw_noderesolve_eui64(sc->fc, (struct fw_eui64 *)dev->si_drv1);
283f90ce7b1SHidetoshi Shimokawa 	if (fwdev == NULL) {
284864d7e72SHidetoshi Shimokawa 		if (fwmem_debug)
285f90ce7b1SHidetoshi Shimokawa 			printf("fwmem: no such device ID:%08x%08x\n",
286f90ce7b1SHidetoshi Shimokawa 					fwmem_eui64.hi, fwmem_eui64.lo);
287f90ce7b1SHidetoshi Shimokawa 		return EINVAL;
288f90ce7b1SHidetoshi Shimokawa 	}
2893c60ba66SKatsushi Kobayashi 
290d3539e97SHidetoshi Shimokawa 	while(uio->uio_resid > 0 && !err) {
2913c60ba66SKatsushi Kobayashi 		offset = uio->uio_offset;
2923c60ba66SKatsushi Kobayashi 		dst_hi = (offset >> 32) & 0xffff;
2933c60ba66SKatsushi Kobayashi 		dst_lo = offset & 0xffffffff;
2948a45d99bSHidetoshi Shimokawa 		len = uio->uio_resid;
2958a45d99bSHidetoshi Shimokawa 		if (len == 4 && (dst_lo & 3) == 0) {
296f90ce7b1SHidetoshi Shimokawa 			xfer = fwmem_read_quad(fwdev, NULL, fwmem_speed,
297c3b09522SHidetoshi Shimokawa 				dst_hi, dst_lo, fw_asy_callback);
298d3539e97SHidetoshi Shimokawa 			if (xfer == NULL) {
299d3539e97SHidetoshi Shimokawa 				err = EINVAL;
300d3539e97SHidetoshi Shimokawa 				break;
301d3539e97SHidetoshi Shimokawa 			}
3023b79dd16SHidetoshi Shimokawa 			err = tsleep((caddr_t)xfer, FWPRI, "fwmrq", 0);
3033b79dd16SHidetoshi Shimokawa 			if (xfer->recv.buf == NULL)
3045db3899dSHidetoshi Shimokawa 				err = EIO;
3053b79dd16SHidetoshi Shimokawa 			else if (xfer->resp != 0)
3063b79dd16SHidetoshi Shimokawa 				err = xfer->resp;
3073b79dd16SHidetoshi Shimokawa 			else if (err == 0)
30877ee030bSHidetoshi Shimokawa 				err = uiomove(xfer->recv.buf + 4*3, 4, uio);
3098a45d99bSHidetoshi Shimokawa 		} else {
3103c60ba66SKatsushi Kobayashi 			if (len > MAXLEN)
3113c60ba66SKatsushi Kobayashi 				len = MAXLEN;
312f90ce7b1SHidetoshi Shimokawa 			xfer = fwmem_read_block(fwdev, NULL, fwmem_speed,
313c3b09522SHidetoshi Shimokawa 				dst_hi, dst_lo, len, fw_asy_callback);
314d3539e97SHidetoshi Shimokawa 			if (xfer == NULL) {
315d3539e97SHidetoshi Shimokawa 				err = EINVAL;
316d3539e97SHidetoshi Shimokawa 				break;
317d3539e97SHidetoshi Shimokawa 			}
3183b79dd16SHidetoshi Shimokawa 			err = tsleep((caddr_t)xfer, FWPRI, "fwmrb", 0);
3193b79dd16SHidetoshi Shimokawa 			if (xfer->recv.buf == NULL)
3205db3899dSHidetoshi Shimokawa 				err = EIO;
3213b79dd16SHidetoshi Shimokawa 			else if (xfer->resp != 0)
3223b79dd16SHidetoshi Shimokawa 				err = xfer->resp;
3233b79dd16SHidetoshi Shimokawa 			else if (err == 0)
32477ee030bSHidetoshi Shimokawa 				err = uiomove(xfer->recv.buf + 4*4, len, uio);
3258a45d99bSHidetoshi Shimokawa 		}
3268a45d99bSHidetoshi Shimokawa 		fw_xfer_free(xfer);
3273c60ba66SKatsushi Kobayashi 	}
3283c60ba66SKatsushi Kobayashi 	return err;
3293c60ba66SKatsushi Kobayashi }
3303c60ba66SKatsushi Kobayashi int
3313c60ba66SKatsushi Kobayashi fwmem_write (dev_t dev, struct uio *uio, int ioflag)
3323c60ba66SKatsushi Kobayashi {
3338a45d99bSHidetoshi Shimokawa 	struct firewire_softc *sc;
3348a45d99bSHidetoshi Shimokawa 	struct fw_device *fwdev;
3358a45d99bSHidetoshi Shimokawa 	struct fw_xfer *xfer;
3368a45d99bSHidetoshi Shimokawa 	int err = 0;
3378a45d99bSHidetoshi Shimokawa         int unit = DEV2UNIT(dev);
3388a45d99bSHidetoshi Shimokawa 	u_int16_t dst_hi;
3398a45d99bSHidetoshi Shimokawa 	u_int32_t dst_lo, quad;
3408a45d99bSHidetoshi Shimokawa 	char *data;
3418a45d99bSHidetoshi Shimokawa 	off_t offset;
3428a45d99bSHidetoshi Shimokawa 	int len;
3438a45d99bSHidetoshi Shimokawa 
3448a45d99bSHidetoshi Shimokawa 	sc = devclass_get_softc(firewire_devclass, unit);
345233b1b97SHidetoshi Shimokawa 	fwdev = fw_noderesolve_eui64(sc->fc, (struct fw_eui64 *)dev->si_drv1);
3468a45d99bSHidetoshi Shimokawa 	if (fwdev == NULL) {
347864d7e72SHidetoshi Shimokawa 		if (fwmem_debug)
3488a45d99bSHidetoshi Shimokawa 			printf("fwmem: no such device ID:%08x%08x\n",
3498a45d99bSHidetoshi Shimokawa 					fwmem_eui64.hi, fwmem_eui64.lo);
3503c60ba66SKatsushi Kobayashi 		return EINVAL;
3513c60ba66SKatsushi Kobayashi 	}
3528a45d99bSHidetoshi Shimokawa 
35377ee030bSHidetoshi Shimokawa 	data = malloc(MAXLEN, M_FW, M_WAITOK);
3548a45d99bSHidetoshi Shimokawa 	if (data == NULL)
3558a45d99bSHidetoshi Shimokawa 		return ENOMEM;
3568a45d99bSHidetoshi Shimokawa 
357d3539e97SHidetoshi Shimokawa 	while(uio->uio_resid > 0 && !err) {
3588a45d99bSHidetoshi Shimokawa 		offset = uio->uio_offset;
3598a45d99bSHidetoshi Shimokawa 		dst_hi = (offset >> 32) & 0xffff;
3608a45d99bSHidetoshi Shimokawa 		dst_lo = offset & 0xffffffff;
3618a45d99bSHidetoshi Shimokawa 		len = uio->uio_resid;
3628a45d99bSHidetoshi Shimokawa 		if (len == 4 && (dst_lo & 3) == 0) {
3638a45d99bSHidetoshi Shimokawa 			err = uiomove((char *)&quad, sizeof(quad), uio);
3648a45d99bSHidetoshi Shimokawa 			xfer = fwmem_write_quad(fwdev, NULL, fwmem_speed,
3658a45d99bSHidetoshi Shimokawa 				dst_hi, dst_lo, quad, fw_asy_callback);
366d3539e97SHidetoshi Shimokawa 			if (xfer == NULL) {
367d3539e97SHidetoshi Shimokawa 				err = EINVAL;
368d3539e97SHidetoshi Shimokawa 				break;
369d3539e97SHidetoshi Shimokawa 			}
3703b79dd16SHidetoshi Shimokawa 			err = tsleep((caddr_t)xfer, FWPRI, "fwmwq", 0);
3713b79dd16SHidetoshi Shimokawa 			if (xfer->resp != 0)
3723b79dd16SHidetoshi Shimokawa 				err = xfer->resp;
3738a45d99bSHidetoshi Shimokawa 		} else {
3748a45d99bSHidetoshi Shimokawa 			if (len > MAXLEN)
3758a45d99bSHidetoshi Shimokawa 				len = MAXLEN;
3768a45d99bSHidetoshi Shimokawa 			err = uiomove(data, len, uio);
3778a45d99bSHidetoshi Shimokawa 			if (err)
378d3539e97SHidetoshi Shimokawa 				break;
3798a45d99bSHidetoshi Shimokawa 			xfer = fwmem_write_block(fwdev, NULL, fwmem_speed,
3808a45d99bSHidetoshi Shimokawa 				dst_hi, dst_lo, len, data, fw_asy_callback);
381d3539e97SHidetoshi Shimokawa 			if (xfer == NULL) {
382d3539e97SHidetoshi Shimokawa 				err = EINVAL;
383d3539e97SHidetoshi Shimokawa 				break;
384d3539e97SHidetoshi Shimokawa 			}
3853b79dd16SHidetoshi Shimokawa 			err = tsleep((caddr_t)xfer, FWPRI, "fwmwb", 0);
3863b79dd16SHidetoshi Shimokawa 			if (xfer->resp != 0)
3873b79dd16SHidetoshi Shimokawa 				err = xfer->resp;
3888a45d99bSHidetoshi Shimokawa 		}
3895db3899dSHidetoshi Shimokawa 		fw_xfer_free(xfer);
3908a45d99bSHidetoshi Shimokawa 	}
391d3539e97SHidetoshi Shimokawa 	free(data, M_FW);
3928a45d99bSHidetoshi Shimokawa 	return err;
3938a45d99bSHidetoshi Shimokawa }
3948a45d99bSHidetoshi Shimokawa 
3953c60ba66SKatsushi Kobayashi int
3963c60ba66SKatsushi Kobayashi fwmem_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
3973c60ba66SKatsushi Kobayashi {
398233b1b97SHidetoshi Shimokawa 	int err = 0;
399233b1b97SHidetoshi Shimokawa 	switch (cmd) {
400233b1b97SHidetoshi Shimokawa 	case FW_SDEUI64:
401233b1b97SHidetoshi Shimokawa 		bcopy(data, dev->si_drv1, sizeof(struct fw_eui64));
402233b1b97SHidetoshi Shimokawa 		break;
403233b1b97SHidetoshi Shimokawa 	case FW_GDEUI64:
404233b1b97SHidetoshi Shimokawa 		bcopy(dev->si_drv1, data, sizeof(struct fw_eui64));
405233b1b97SHidetoshi Shimokawa 		break;
406233b1b97SHidetoshi Shimokawa 	default:
407233b1b97SHidetoshi Shimokawa 		err = EINVAL;
408233b1b97SHidetoshi Shimokawa 	}
409233b1b97SHidetoshi Shimokawa 	return(err);
4103c60ba66SKatsushi Kobayashi }
4113c60ba66SKatsushi Kobayashi int
4123c60ba66SKatsushi Kobayashi fwmem_poll (dev_t dev, int events, fw_proc *td)
4133c60ba66SKatsushi Kobayashi {
4143c60ba66SKatsushi Kobayashi 	return EINVAL;
4153c60ba66SKatsushi Kobayashi }
4163c60ba66SKatsushi Kobayashi int
41777ee030bSHidetoshi Shimokawa #if __FreeBSD_version < 500102
41845545499SHidetoshi Shimokawa fwmem_mmap (dev_t dev, vm_offset_t offset, int nproto)
41945545499SHidetoshi Shimokawa #else
42077ee030bSHidetoshi Shimokawa fwmem_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto)
42145545499SHidetoshi Shimokawa #endif
4223c60ba66SKatsushi Kobayashi {
4233c60ba66SKatsushi Kobayashi 	return EINVAL;
4243c60ba66SKatsushi Kobayashi }
425