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 $
35 * $DragonFly: src/sys/bus/firewire/fwmem.c,v 1.2 2003/06/17 04:28:25 dillon Exp $
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/types.h>
42 #include <sys/kernel.h>
43 #include <sys/malloc.h>
45 #include <sys/sysctl.h>
48 #include <machine/bus.h>
50 #include <sys/signal.h>
52 #include <sys/ioccom.h>
54 #include <dev/firewire/firewire.h>
55 #include <dev/firewire/firewirereg.h>
56 #include <dev/firewire/fwmem.h>
58 static int fwmem_speed=2, fwmem_debug=0;
59 static struct fw_eui64 fwmem_eui64;
60 SYSCTL_DECL(_hw_firewire);
61 SYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0,
62 "FireWire Memory Access");
63 SYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW,
64 &fwmem_eui64.hi, 0, "Fwmem target EUI64 high");
65 SYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_lo, CTLFLAG_RW,
66 &fwmem_eui64.lo, 0, "Fwmem target EUI64 low");
67 SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0,
69 SYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0,
70 "Fwmem driver debug flag");
72 static struct fw_xfer *
74 struct fw_device *fwdev,
83 xfer = fw_xfer_alloc_buf(M_FWXFER, slen, rlen);
88 xfer->dst = FWLOCALBUS | fwdev->dst;
90 xfer->spd = fwdev->speed;
92 xfer->spd = min(spd, fwdev->speed);
93 xfer->act.hand = hand;
94 xfer->retry_req = fw_asybusy;
102 struct fw_device *fwdev,
107 void (*hand)(struct fw_xfer *))
109 struct fw_xfer *xfer;
112 xfer = fwmem_xfer_req(fwdev, sc, spd, 12, 16, hand);
116 fp = (struct fw_pkt *)xfer->send.buf;
117 fp->mode.rreqq.tcode = FWTCODE_RREQQ;
118 fp->mode.rreqq.dst = xfer->dst;
119 fp->mode.rreqq.dest_hi = dst_hi;
120 fp->mode.rreqq.dest_lo = dst_lo;
123 printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst,
126 if (fw_asyreq(xfer->fc, -1, xfer) == 0)
135 struct fw_device *fwdev,
141 void (*hand)(struct fw_xfer *))
143 struct fw_xfer *xfer;
146 xfer = fwmem_xfer_req(fwdev, sc, spd, 16, 12, hand);
150 fp = (struct fw_pkt *)xfer->send.buf;
151 fp->mode.wreqq.tcode = FWTCODE_WREQQ;
152 fp->mode.wreqq.dst = xfer->dst;
153 fp->mode.wreqq.dest_hi = dst_hi;
154 fp->mode.wreqq.dest_lo = dst_lo;
156 fp->mode.wreqq.data = data;
159 printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst,
160 dst_hi, dst_lo, data);
162 if (fw_asyreq(xfer->fc, -1, xfer) == 0)
171 struct fw_device *fwdev,
177 void (*hand)(struct fw_xfer *))
179 struct fw_xfer *xfer;
182 xfer = fwmem_xfer_req(fwdev, sc, spd, 16, roundup2(16+len,4), hand);
186 fp = (struct fw_pkt *)xfer->send.buf;
187 fp->mode.rreqb.tcode = FWTCODE_RREQB;
188 fp->mode.rreqb.dst = xfer->dst;
189 fp->mode.rreqb.dest_hi = dst_hi;
190 fp->mode.rreqb.dest_lo = dst_lo;
191 fp->mode.rreqb.len = len;
194 printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst,
195 dst_hi, dst_lo, len);
196 if (fw_asyreq(xfer->fc, -1, xfer) == 0)
205 struct fw_device *fwdev,
212 void (*hand)(struct fw_xfer *))
214 struct fw_xfer *xfer;
217 xfer = fwmem_xfer_req(fwdev, sc, spd, roundup(16+len, 4), 12, hand);
221 fp = (struct fw_pkt *)xfer->send.buf;
222 fp->mode.wreqb.tcode = FWTCODE_WREQB;
223 fp->mode.wreqb.dst = xfer->dst;
224 fp->mode.wreqb.dest_hi = dst_hi;
225 fp->mode.wreqb.dest_lo = dst_lo;
226 fp->mode.wreqb.len = len;
227 bcopy(data, &fp->mode.wreqb.payload[0], len);
230 printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev->dst,
231 dst_hi, dst_lo, len);
232 if (fw_asyreq(xfer->fc, -1, xfer) == 0)
241 fwmem_open (dev_t dev, int flags, int fmt, fw_proc *td)
243 struct fw_eui64 *eui;
245 eui = (struct fw_eui64 *)malloc(sizeof(struct fw_eui64),
249 bcopy(&fwmem_eui64, eui, sizeof(struct fw_eui64));
250 dev->si_drv1 = (void *)eui;
256 fwmem_close (dev_t dev, int flags, int fmt, fw_proc *td)
258 free(dev->si_drv1, M_FW);
265 fwmem_read (dev_t dev, struct uio *uio, int ioflag)
267 struct firewire_softc *sc;
268 struct fw_device *fwdev;
269 struct fw_xfer *xfer;
271 int unit = DEV2UNIT(dev);
277 sc = devclass_get_softc(firewire_devclass, unit);
278 fwdev = fw_noderesolve_eui64(sc->fc, (struct fw_eui64 *)dev->si_drv1);
281 printf("fwmem: no such device ID:%08x%08x\n",
282 fwmem_eui64.hi, fwmem_eui64.lo);
286 while(uio->uio_resid > 0 && !err) {
287 offset = uio->uio_offset;
288 dst_hi = (offset >> 32) & 0xffff;
289 dst_lo = offset & 0xffffffff;
290 len = uio->uio_resid;
291 if (len == 4 && (dst_lo & 3) == 0) {
292 xfer = fwmem_read_quad(fwdev, NULL, fwmem_speed,
293 dst_hi, dst_lo, fw_asy_callback);
298 err = tsleep((caddr_t)xfer, FWPRI, "fwmrq", 0);
299 if (xfer->recv.buf == NULL)
301 else if (xfer->resp != 0)
304 err = uiomove(xfer->recv.buf + 4*3, 4, uio);
308 xfer = fwmem_read_block(fwdev, NULL, fwmem_speed,
309 dst_hi, dst_lo, len, fw_asy_callback);
314 err = tsleep((caddr_t)xfer, FWPRI, "fwmrb", 0);
315 if (xfer->recv.buf == NULL)
317 else if (xfer->resp != 0)
320 err = uiomove(xfer->recv.buf + 4*4, len, uio);
327 fwmem_write (dev_t dev, struct uio *uio, int ioflag)
329 struct firewire_softc *sc;
330 struct fw_device *fwdev;
331 struct fw_xfer *xfer;
333 int unit = DEV2UNIT(dev);
335 u_int32_t dst_lo, quad;
340 sc = devclass_get_softc(firewire_devclass, unit);
341 fwdev = fw_noderesolve_eui64(sc->fc, (struct fw_eui64 *)dev->si_drv1);
344 printf("fwmem: no such device ID:%08x%08x\n",
345 fwmem_eui64.hi, fwmem_eui64.lo);
349 data = malloc(MAXLEN, M_FW, M_WAITOK);
353 while(uio->uio_resid > 0 && !err) {
354 offset = uio->uio_offset;
355 dst_hi = (offset >> 32) & 0xffff;
356 dst_lo = offset & 0xffffffff;
357 len = uio->uio_resid;
358 if (len == 4 && (dst_lo & 3) == 0) {
359 err = uiomove((char *)&quad, sizeof(quad), uio);
360 xfer = fwmem_write_quad(fwdev, NULL, fwmem_speed,
361 dst_hi, dst_lo, quad, fw_asy_callback);
366 err = tsleep((caddr_t)xfer, FWPRI, "fwmwq", 0);
372 err = uiomove(data, len, uio);
375 xfer = fwmem_write_block(fwdev, NULL, fwmem_speed,
376 dst_hi, dst_lo, len, data, fw_asy_callback);
381 err = tsleep((caddr_t)xfer, FWPRI, "fwmwb", 0);
392 fwmem_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
397 bcopy(data, dev->si_drv1, sizeof(struct fw_eui64));
400 bcopy(dev->si_drv1, data, sizeof(struct fw_eui64));
408 fwmem_poll (dev_t dev, int events, fw_proc *td)
413 #if __FreeBSD_version < 500102
414 fwmem_mmap (dev_t dev, vm_offset_t offset, int nproto)
416 fwmem_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto)