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
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/types.h>
45 #include <sys/kernel.h>
46 #include <sys/malloc.h>
48 #include <sys/sysctl.h>
52 #include <machine/bus.h>
54 #include <sys/signal.h>
56 #include <sys/ioccom.h>
57 #include <sys/fcntl.h>
59 #include <dev/firewire/firewire.h>
60 #include <dev/firewire/firewirereg.h>
61 #include <dev/firewire/fwmem.h>
63 static int fwmem_speed = 2, fwmem_debug = 0;
64 static struct fw_eui64 fwmem_eui64;
65 SYSCTL_DECL(_hw_firewire);
66 static SYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0,
67 "FireWire Memory Access");
68 SYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW,
69 &fwmem_eui64.hi, 0, "Fwmem target EUI64 high");
70 SYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_lo, CTLFLAG_RW,
71 &fwmem_eui64.lo, 0, "Fwmem target EUI64 low");
72 SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0,
74 SYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0,
75 "Fwmem driver debug flag");
77 static MALLOC_DEFINE(M_FWMEM, "fwmem", "fwmem/FireWire");
79 #define MAXLEN (512 << fwmem_speed)
83 struct firewire_softc *sc;
87 static struct fw_xfer *
89 struct fw_device *fwdev,
98 xfer = fw_xfer_alloc(M_FWMEM);
102 xfer->fc = fwdev->fc;
103 xfer->send.hdr.mode.hdr.dst = FWLOCALBUS | fwdev->dst;
105 xfer->send.spd = fwdev->speed;
107 xfer->send.spd = min(spd, fwdev->speed);
110 xfer->send.pay_len = slen;
111 xfer->recv.pay_len = rlen;
118 struct fw_device *fwdev,
124 void (*hand)(struct fw_xfer *))
126 struct fw_xfer *xfer;
129 xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 4, hand);
134 fp = &xfer->send.hdr;
135 fp->mode.rreqq.tcode = FWTCODE_RREQQ;
136 fp->mode.rreqq.dest_hi = dst_hi;
137 fp->mode.rreqq.dest_lo = dst_lo;
139 xfer->send.payload = NULL;
140 xfer->recv.payload = (uint32_t *)data;
143 printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst,
146 if (fw_asyreq(xfer->fc, -1, xfer) == 0)
155 struct fw_device *fwdev,
161 void (*hand)(struct fw_xfer *))
163 struct fw_xfer *xfer;
166 xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 0, hand);
170 fp = &xfer->send.hdr;
171 fp->mode.wreqq.tcode = FWTCODE_WREQQ;
172 fp->mode.wreqq.dest_hi = dst_hi;
173 fp->mode.wreqq.dest_lo = dst_lo;
174 fp->mode.wreqq.data = *(uint32_t *)data;
176 xfer->send.payload = xfer->recv.payload = NULL;
179 printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst,
180 dst_hi, dst_lo, *(uint32_t *)data);
182 if (fw_asyreq(xfer->fc, -1, xfer) == 0)
191 struct fw_device *fwdev,
198 void (*hand)(struct fw_xfer *))
200 struct fw_xfer *xfer;
203 xfer = fwmem_xfer_req(fwdev, sc, spd, 0, roundup2(len, 4), hand);
207 fp = &xfer->send.hdr;
208 fp->mode.rreqb.tcode = FWTCODE_RREQB;
209 fp->mode.rreqb.dest_hi = dst_hi;
210 fp->mode.rreqb.dest_lo = dst_lo;
211 fp->mode.rreqb.len = len;
212 fp->mode.rreqb.extcode = 0;
214 xfer->send.payload = NULL;
215 xfer->recv.payload = data;
218 printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst,
219 dst_hi, dst_lo, len);
220 if (fw_asyreq(xfer->fc, -1, xfer) == 0)
229 struct fw_device *fwdev,
236 void (*hand)(struct fw_xfer *))
238 struct fw_xfer *xfer;
241 xfer = fwmem_xfer_req(fwdev, sc, spd, len, 0, hand);
245 fp = &xfer->send.hdr;
246 fp->mode.wreqb.tcode = FWTCODE_WREQB;
247 fp->mode.wreqb.dest_hi = dst_hi;
248 fp->mode.wreqb.dest_lo = dst_lo;
249 fp->mode.wreqb.len = len;
250 fp->mode.wreqb.extcode = 0;
252 xfer->send.payload = data;
253 xfer->recv.payload = NULL;
256 printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev->dst,
257 dst_hi, dst_lo, len);
258 if (fw_asyreq(xfer->fc, -1, xfer) == 0)
266 fwmem_open(struct cdev *dev, int flags, int fmt, fw_proc *td)
268 struct fwmem_softc *fms;
269 struct firewire_softc *sc;
270 int unit = DEV2UNIT(dev);
272 sc = devclass_get_softc(firewire_devclass, unit);
277 if (dev->si_drv1 != NULL) {
278 if ((flags & FWRITE) != 0) {
286 dev->si_drv1 = (void *)-1;
288 dev->si_drv1 = malloc(sizeof(struct fwmem_softc),
290 dev->si_iosize_max = DFLTPHYS;
292 bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64));
297 printf("%s: refcount=%d\n", __func__, fms->refcount);
303 fwmem_close (struct cdev *dev, int flags, int fmt, fw_proc *td)
305 struct fwmem_softc *fms;
309 FW_GLOCK(fms->sc->fc);
311 FW_GUNLOCK(fms->sc->fc);
313 printf("%s: refcount=%d\n", __func__, fms->refcount);
314 if (fms->refcount < 1) {
315 free(dev->si_drv1, M_FWMEM);
324 fwmem_biodone(struct fw_xfer *xfer)
328 bp = (struct bio *)xfer->sc;
329 bp->bio_error = xfer->resp;
331 if (bp->bio_error != 0) {
333 printf("%s: err=%d\n", __func__, bp->bio_error);
334 bp->bio_flags |= BIO_ERROR;
335 bp->bio_resid = bp->bio_bcount;
343 fwmem_strategy(struct bio *bp)
345 struct fwmem_softc *fms;
346 struct fw_device *fwdev;
347 struct fw_xfer *xfer;
352 /* XXX check request length */
355 fwdev = fw_noderesolve_eui64(fms->sc->fc, &fms->eui);
358 printf("fwmem: no such device ID:%08x%08x\n",
359 fms->eui.hi, fms->eui.lo);
364 iolen = MIN(bp->bio_bcount, MAXLEN);
365 if (bp->bio_cmd == BIO_READ) {
366 if (iolen == 4 && (bp->bio_offset & 3) == 0)
367 xfer = fwmem_read_quad(fwdev,
368 (void *)bp, fwmem_speed,
369 bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
370 bp->bio_data, fwmem_biodone);
372 xfer = fwmem_read_block(fwdev,
373 (void *)bp, fwmem_speed,
374 bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
375 iolen, bp->bio_data, fwmem_biodone);
377 if (iolen == 4 && (bp->bio_offset & 3) == 0)
378 xfer = fwmem_write_quad(fwdev,
379 (void *)bp, fwmem_speed,
380 bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
381 bp->bio_data, fwmem_biodone);
383 xfer = fwmem_write_block(fwdev,
384 (void *)bp, fwmem_speed,
385 bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
386 iolen, bp->bio_data, fwmem_biodone);
393 bp->bio_resid = bp->bio_bcount - iolen;
397 printf("%s: err=%d\n", __func__, err);
399 bp->bio_flags |= BIO_ERROR;
400 bp->bio_resid = bp->bio_bcount;
406 fwmem_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
408 struct fwmem_softc *fms;
414 bcopy(data, &fms->eui, sizeof(struct fw_eui64));
417 bcopy(&fms->eui, data, sizeof(struct fw_eui64));
426 fwmem_poll(struct cdev *dev, int events, fw_proc *td)
432 fwmem_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
433 int nproto, vm_memattr_t *memattr)