2 * Copyright (c) 2002-2003
3 * Hidetoshi Shimokawa. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
16 * This product includes software developed by Hidetoshi Shimokawa.
18 * 4. Neither the name of the author nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $FreeBSD: src/sys/dev/firewire/fwmem.c,v 1.1.2.9 2003/04/28 03:29:18 simokawa Exp $
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/types.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
44 #include <sys/sysctl.h>
47 #include <machine/bus.h>
49 #include <sys/signal.h>
51 #include <sys/ioccom.h>
53 #include <dev/firewire/firewire.h>
54 #include <dev/firewire/firewirereg.h>
55 #include <dev/firewire/fwmem.h>
57 static int fwmem_speed=2, fwmem_debug=0;
58 static struct fw_eui64 fwmem_eui64;
59 SYSCTL_DECL(_hw_firewire);
60 SYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0,
61 "FireWire Memory Access");
62 SYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW,
63 &fwmem_eui64.hi, 0, "Fwmem target EUI64 high");
64 SYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_lo, CTLFLAG_RW,
65 &fwmem_eui64.lo, 0, "Fwmem target EUI64 low");
66 SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0,
68 SYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0,
69 "Fwmem driver debug flag");
71 static struct fw_xfer *
73 struct fw_device *fwdev,
82 xfer = fw_xfer_alloc_buf(M_FWXFER, slen, rlen);
87 xfer->dst = FWLOCALBUS | fwdev->dst;
89 xfer->spd = fwdev->speed;
91 xfer->spd = min(spd, fwdev->speed);
92 xfer->act.hand = hand;
93 xfer->retry_req = fw_asybusy;
101 struct fw_device *fwdev,
106 void (*hand)(struct fw_xfer *))
108 struct fw_xfer *xfer;
111 xfer = fwmem_xfer_req(fwdev, sc, spd, 12, 16, hand);
115 fp = (struct fw_pkt *)xfer->send.buf;
116 fp->mode.rreqq.tcode = FWTCODE_RREQQ;
117 fp->mode.rreqq.dst = xfer->dst;
118 fp->mode.rreqq.dest_hi = dst_hi;
119 fp->mode.rreqq.dest_lo = dst_lo;
122 printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst,
125 if (fw_asyreq(xfer->fc, -1, xfer) == 0)
134 struct fw_device *fwdev,
140 void (*hand)(struct fw_xfer *))
142 struct fw_xfer *xfer;
145 xfer = fwmem_xfer_req(fwdev, sc, spd, 16, 12, hand);
149 fp = (struct fw_pkt *)xfer->send.buf;
150 fp->mode.wreqq.tcode = FWTCODE_WREQQ;
151 fp->mode.wreqq.dst = xfer->dst;
152 fp->mode.wreqq.dest_hi = dst_hi;
153 fp->mode.wreqq.dest_lo = dst_lo;
155 fp->mode.wreqq.data = data;
158 printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst,
159 dst_hi, dst_lo, data);
161 if (fw_asyreq(xfer->fc, -1, xfer) == 0)
170 struct fw_device *fwdev,
176 void (*hand)(struct fw_xfer *))
178 struct fw_xfer *xfer;
181 xfer = fwmem_xfer_req(fwdev, sc, spd, 16, roundup2(16+len,4), hand);
185 fp = (struct fw_pkt *)xfer->send.buf;
186 fp->mode.rreqb.tcode = FWTCODE_RREQB;
187 fp->mode.rreqb.dst = xfer->dst;
188 fp->mode.rreqb.dest_hi = dst_hi;
189 fp->mode.rreqb.dest_lo = dst_lo;
190 fp->mode.rreqb.len = len;
193 printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst,
194 dst_hi, dst_lo, len);
195 if (fw_asyreq(xfer->fc, -1, xfer) == 0)
204 struct fw_device *fwdev,
211 void (*hand)(struct fw_xfer *))
213 struct fw_xfer *xfer;
216 xfer = fwmem_xfer_req(fwdev, sc, spd, roundup(16+len, 4), 12, hand);
220 fp = (struct fw_pkt *)xfer->send.buf;
221 fp->mode.wreqb.tcode = FWTCODE_WREQB;
222 fp->mode.wreqb.dst = xfer->dst;
223 fp->mode.wreqb.dest_hi = dst_hi;
224 fp->mode.wreqb.dest_lo = dst_lo;
225 fp->mode.wreqb.len = len;
226 bcopy(data, &fp->mode.wreqb.payload[0], len);
229 printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev->dst,
230 dst_hi, dst_lo, len);
231 if (fw_asyreq(xfer->fc, -1, xfer) == 0)
240 fwmem_open (dev_t dev, int flags, int fmt, fw_proc *td)
242 struct fw_eui64 *eui;
244 eui = (struct fw_eui64 *)malloc(sizeof(struct fw_eui64),
248 bcopy(&fwmem_eui64, eui, sizeof(struct fw_eui64));
249 dev->si_drv1 = (void *)eui;
255 fwmem_close (dev_t dev, int flags, int fmt, fw_proc *td)
257 free(dev->si_drv1, M_FW);
264 fwmem_read (dev_t dev, struct uio *uio, int ioflag)
266 struct firewire_softc *sc;
267 struct fw_device *fwdev;
268 struct fw_xfer *xfer;
270 int unit = DEV2UNIT(dev);
276 sc = devclass_get_softc(firewire_devclass, unit);
277 fwdev = fw_noderesolve_eui64(sc->fc, (struct fw_eui64 *)dev->si_drv1);
280 printf("fwmem: no such device ID:%08x%08x\n",
281 fwmem_eui64.hi, fwmem_eui64.lo);
285 while(uio->uio_resid > 0 && !err) {
286 offset = uio->uio_offset;
287 dst_hi = (offset >> 32) & 0xffff;
288 dst_lo = offset & 0xffffffff;
289 len = uio->uio_resid;
290 if (len == 4 && (dst_lo & 3) == 0) {
291 xfer = fwmem_read_quad(fwdev, NULL, fwmem_speed,
292 dst_hi, dst_lo, fw_asy_callback);
297 err = tsleep((caddr_t)xfer, FWPRI, "fwmrq", 0);
298 if (xfer->recv.buf == NULL)
300 else if (xfer->resp != 0)
303 err = uiomove(xfer->recv.buf + 4*3, 4, uio);
307 xfer = fwmem_read_block(fwdev, NULL, fwmem_speed,
308 dst_hi, dst_lo, len, fw_asy_callback);
313 err = tsleep((caddr_t)xfer, FWPRI, "fwmrb", 0);
314 if (xfer->recv.buf == NULL)
316 else if (xfer->resp != 0)
319 err = uiomove(xfer->recv.buf + 4*4, len, uio);
326 fwmem_write (dev_t dev, struct uio *uio, int ioflag)
328 struct firewire_softc *sc;
329 struct fw_device *fwdev;
330 struct fw_xfer *xfer;
332 int unit = DEV2UNIT(dev);
334 u_int32_t dst_lo, quad;
339 sc = devclass_get_softc(firewire_devclass, unit);
340 fwdev = fw_noderesolve_eui64(sc->fc, (struct fw_eui64 *)dev->si_drv1);
343 printf("fwmem: no such device ID:%08x%08x\n",
344 fwmem_eui64.hi, fwmem_eui64.lo);
348 data = malloc(MAXLEN, M_FW, M_WAITOK);
352 while(uio->uio_resid > 0 && !err) {
353 offset = uio->uio_offset;
354 dst_hi = (offset >> 32) & 0xffff;
355 dst_lo = offset & 0xffffffff;
356 len = uio->uio_resid;
357 if (len == 4 && (dst_lo & 3) == 0) {
358 err = uiomove((char *)&quad, sizeof(quad), uio);
359 xfer = fwmem_write_quad(fwdev, NULL, fwmem_speed,
360 dst_hi, dst_lo, quad, fw_asy_callback);
365 err = tsleep((caddr_t)xfer, FWPRI, "fwmwq", 0);
371 err = uiomove(data, len, uio);
374 xfer = fwmem_write_block(fwdev, NULL, fwmem_speed,
375 dst_hi, dst_lo, len, data, fw_asy_callback);
380 err = tsleep((caddr_t)xfer, FWPRI, "fwmwb", 0);
391 fwmem_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
396 bcopy(data, dev->si_drv1, sizeof(struct fw_eui64));
399 bcopy(dev->si_drv1, data, sizeof(struct fw_eui64));
407 fwmem_poll (dev_t dev, int events, fw_proc *td)
412 #if __FreeBSD_version < 500102
413 fwmem_mmap (dev_t dev, vm_offset_t offset, int nproto)
415 fwmem_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto)