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 * $DragonFly: src/sys/bus/firewire/fwmem.c,v 1.16 2008/01/06 16:55:49 swildner Exp $
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD: src/sys/dev/firewire/fwmem.c,v 1.26 2004/01/05 14:21:18 simokawa Exp $");
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/types.h>
46 #include <sys/kernel.h>
47 #include <sys/malloc.h>
50 #include <sys/sysctl.h>
51 #if defined(__DragonFly__) || __FreeBSD_version < 500000
57 #include <sys/signal.h>
59 #include <sys/fcntl.h>
60 #include <sys/thread2.h>
64 #include "firewirereg.h"
67 #include <dev/firewire/firewire.h>
68 #include <dev/firewire/firewirereg.h>
69 #include <dev/firewire/fwmem.h>
72 static int fwmem_speed
=2, fwmem_debug
=0;
73 static struct fw_eui64 fwmem_eui64
;
74 SYSCTL_DECL(_hw_firewire
);
75 SYSCTL_NODE(_hw_firewire
, OID_AUTO
, fwmem
, CTLFLAG_RD
, 0,
76 "FireWire Memory Access");
77 SYSCTL_UINT(_hw_firewire_fwmem
, OID_AUTO
, eui64_hi
, CTLFLAG_RW
,
78 &fwmem_eui64
.hi
, 0, "Fwmem target EUI64 high");
79 SYSCTL_UINT(_hw_firewire_fwmem
, OID_AUTO
, eui64_lo
, CTLFLAG_RW
,
80 &fwmem_eui64
.lo
, 0, "Fwmem target EUI64 low");
81 SYSCTL_INT(_hw_firewire_fwmem
, OID_AUTO
, speed
, CTLFLAG_RW
, &fwmem_speed
, 0,
83 SYSCTL_INT(_debug
, OID_AUTO
, fwmem_debug
, CTLFLAG_RW
, &fwmem_debug
, 0,
84 "Fwmem driver debug flag");
86 MALLOC_DEFINE(M_FWMEM
, "fwmem", "fwmem/FireWire");
88 #define MAXLEN (512 << fwmem_speed)
95 static struct fw_xfer
*
97 struct fw_device
*fwdev
,
104 struct fw_xfer
*xfer
;
106 xfer
= fw_xfer_alloc(M_FWMEM
);
110 xfer
->fc
= fwdev
->fc
;
111 xfer
->send
.hdr
.mode
.hdr
.dst
= FWLOCALBUS
| fwdev
->dst
;
113 xfer
->send
.spd
= fwdev
->speed
;
115 xfer
->send
.spd
= min(spd
, fwdev
->speed
);
116 xfer
->act
.hand
= hand
;
117 xfer
->retry_req
= fw_asybusy
;
119 xfer
->send
.pay_len
= slen
;
120 xfer
->recv
.pay_len
= rlen
;
127 struct fw_device
*fwdev
,
133 void (*hand
)(struct fw_xfer
*))
135 struct fw_xfer
*xfer
;
138 xfer
= fwmem_xfer_req(fwdev
, (void *)sc
, spd
, 0, 4, hand
);
143 fp
= &xfer
->send
.hdr
;
144 fp
->mode
.rreqq
.tcode
= FWTCODE_RREQQ
;
145 fp
->mode
.rreqq
.dest_hi
= dst_hi
;
146 fp
->mode
.rreqq
.dest_lo
= dst_lo
;
148 xfer
->send
.payload
= NULL
;
149 xfer
->recv
.payload
= (u_int32_t
*)data
;
152 kprintf("fwmem_read_quad: %d %04x:%08x\n", fwdev
->dst
,
155 if (fw_asyreq(xfer
->fc
, -1, xfer
) == 0)
164 struct fw_device
*fwdev
,
170 void (*hand
)(struct fw_xfer
*))
172 struct fw_xfer
*xfer
;
175 xfer
= fwmem_xfer_req(fwdev
, sc
, spd
, 0, 0, hand
);
179 fp
= &xfer
->send
.hdr
;
180 fp
->mode
.wreqq
.tcode
= FWTCODE_WREQQ
;
181 fp
->mode
.wreqq
.dest_hi
= dst_hi
;
182 fp
->mode
.wreqq
.dest_lo
= dst_lo
;
183 fp
->mode
.wreqq
.data
= *(u_int32_t
*)data
;
185 xfer
->send
.payload
= xfer
->recv
.payload
= NULL
;
188 kprintf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev
->dst
,
189 dst_hi
, dst_lo
, *(u_int32_t
*)data
);
191 if (fw_asyreq(xfer
->fc
, -1, xfer
) == 0)
200 struct fw_device
*fwdev
,
207 void (*hand
)(struct fw_xfer
*))
209 struct fw_xfer
*xfer
;
212 xfer
= fwmem_xfer_req(fwdev
, sc
, spd
, 0, roundup2(len
, 4), hand
);
216 fp
= &xfer
->send
.hdr
;
217 fp
->mode
.rreqb
.tcode
= FWTCODE_RREQB
;
218 fp
->mode
.rreqb
.dest_hi
= dst_hi
;
219 fp
->mode
.rreqb
.dest_lo
= dst_lo
;
220 fp
->mode
.rreqb
.len
= len
;
221 fp
->mode
.rreqb
.extcode
= 0;
223 xfer
->send
.payload
= NULL
;
224 xfer
->recv
.payload
= data
;
227 kprintf("fwmem_read_block: %d %04x:%08x %d\n", fwdev
->dst
,
228 dst_hi
, dst_lo
, len
);
229 if (fw_asyreq(xfer
->fc
, -1, xfer
) == 0)
238 struct fw_device
*fwdev
,
245 void (*hand
)(struct fw_xfer
*))
247 struct fw_xfer
*xfer
;
250 xfer
= fwmem_xfer_req(fwdev
, sc
, spd
, len
, 0, hand
);
254 fp
= &xfer
->send
.hdr
;
255 fp
->mode
.wreqb
.tcode
= FWTCODE_WREQB
;
256 fp
->mode
.wreqb
.dest_hi
= dst_hi
;
257 fp
->mode
.wreqb
.dest_lo
= dst_lo
;
258 fp
->mode
.wreqb
.len
= len
;
259 fp
->mode
.wreqb
.extcode
= 0;
261 xfer
->send
.payload
= data
;
262 xfer
->recv
.payload
= NULL
;
265 kprintf("fwmem_write_block: %d %04x:%08x %d\n", fwdev
->dst
,
266 dst_hi
, dst_lo
, len
);
267 if (fw_asyreq(xfer
->fc
, -1, xfer
) == 0)
276 fwmem_open (struct dev_open_args
*ap
)
278 cdev_t dev
= ap
->a_head
.a_dev
;
279 struct fwmem_softc
*fms
;
281 if (dev
->si_drv1
!= NULL
) {
282 if ((ap
->a_oflags
& FWRITE
) != 0)
284 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
287 fms
= (struct fwmem_softc
*)kmalloc(sizeof(struct fwmem_softc
),
289 bcopy(&fwmem_eui64
, &fms
->eui
, sizeof(struct fw_eui64
));
290 dev
->si_drv1
= (void *)fms
;
291 dev
->si_iosize_max
= DFLTPHYS
;
295 kprintf("%s: refcount=%d\n", __func__
, fms
->refcount
);
301 fwmem_close (struct dev_close_args
*ap
)
303 cdev_t dev
= ap
->a_head
.a_dev
;
304 struct fwmem_softc
*fms
;
306 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
309 kprintf("%s: refcount=%d\n", __func__
, fms
->refcount
);
310 if (fms
->refcount
< 1) {
311 kfree(dev
->si_drv1
, M_FW
);
320 fwmem_biodone(struct fw_xfer
*xfer
)
325 bio
= (struct bio
*)xfer
->sc
;
327 bp
->b_error
= xfer
->resp
;
329 if (bp
->b_error
!= 0) {
331 kprintf("%s: err=%d\n", __func__
, bp
->b_error
);
332 bp
->b_flags
|= B_ERROR
;
333 bp
->b_resid
= bp
->b_bcount
;
340 fwmem_strategy(struct dev_strategy_args
*ap
)
342 cdev_t dev
= ap
->a_head
.a_dev
;
343 struct bio
*bio
= ap
->a_bio
;
344 struct buf
*bp
= bio
->bio_buf
;
345 struct firewire_softc
*sc
;
346 struct fwmem_softc
*fms
;
347 struct fw_device
*fwdev
;
348 struct fw_xfer
*xfer
;
349 int unit
, err
=0, iolen
;
351 /* XXX check request length */
353 unit
= DEV2UNIT(dev
);
354 sc
= devclass_get_softc(firewire_devclass
, unit
);
357 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
358 fwdev
= fw_noderesolve_eui64(sc
->fc
, &fms
->eui
);
361 kprintf("fwmem: no such device ID:%08x%08x\n",
362 fms
->eui
.hi
, fms
->eui
.lo
);
366 if (bio
->bio_offset
== NOOFFSET
) {
367 kprintf("fwmem: offset was not set bp %p\n", bp
);
372 iolen
= MIN(bp
->b_bcount
, MAXLEN
);
373 if (bp
->b_cmd
== BUF_CMD_READ
) {
374 if (iolen
== 4 && (bio
->bio_offset
& 3) == 0)
375 xfer
= fwmem_read_quad(fwdev
,
376 (void *) bio
, fwmem_speed
,
377 bio
->bio_offset
>> 32, bio
->bio_offset
& 0xffffffff,
378 bp
->b_data
, fwmem_biodone
);
380 xfer
= fwmem_read_block(fwdev
,
381 (void *) bio
, fwmem_speed
,
382 bio
->bio_offset
>> 32, bio
->bio_offset
& 0xffffffff,
383 iolen
, bp
->b_data
, fwmem_biodone
);
385 if (iolen
== 4 && (bio
->bio_offset
& 3) == 0)
386 xfer
= fwmem_write_quad(fwdev
,
387 (void *)bio
, fwmem_speed
,
388 bio
->bio_offset
>> 32, bio
->bio_offset
& 0xffffffff,
389 bp
->b_data
, fwmem_biodone
);
391 xfer
= fwmem_write_block(fwdev
,
392 (void *)bio
, fwmem_speed
,
393 bio
->bio_offset
>> 32, bio
->bio_offset
& 0xffffffff,
394 iolen
, bp
->b_data
, fwmem_biodone
);
401 bp
->b_resid
= bp
->b_bcount
- iolen
;
406 kprintf("%s: err=%d\n", __func__
, err
);
408 bp
->b_flags
|= B_ERROR
;
409 bp
->b_resid
= bp
->b_bcount
;
416 fwmem_ioctl(struct dev_ioctl_args
*ap
)
418 cdev_t dev
= ap
->a_head
.a_dev
;
419 struct fwmem_softc
*fms
;
422 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
425 bcopy(ap
->a_data
, &fms
->eui
, sizeof(struct fw_eui64
));
428 bcopy(&fms
->eui
, ap
->a_data
, sizeof(struct fw_eui64
));
436 fwmem_poll(struct dev_poll_args
*ap
)
441 fwmem_mmap(struct dev_mmap_args
*ap
)