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/ioccom.h>
60 #include <sys/fcntl.h>
61 #include <sys/thread2.h>
65 #include "firewirereg.h"
68 #include <dev/firewire/firewire.h>
69 #include <dev/firewire/firewirereg.h>
70 #include <dev/firewire/fwmem.h>
73 static int fwmem_speed
=2, fwmem_debug
=0;
74 static struct fw_eui64 fwmem_eui64
;
75 SYSCTL_DECL(_hw_firewire
);
76 SYSCTL_NODE(_hw_firewire
, OID_AUTO
, fwmem
, CTLFLAG_RD
, 0,
77 "FireWire Memory Access");
78 SYSCTL_UINT(_hw_firewire_fwmem
, OID_AUTO
, eui64_hi
, CTLFLAG_RW
,
79 &fwmem_eui64
.hi
, 0, "Fwmem target EUI64 high");
80 SYSCTL_UINT(_hw_firewire_fwmem
, OID_AUTO
, eui64_lo
, CTLFLAG_RW
,
81 &fwmem_eui64
.lo
, 0, "Fwmem target EUI64 low");
82 SYSCTL_INT(_hw_firewire_fwmem
, OID_AUTO
, speed
, CTLFLAG_RW
, &fwmem_speed
, 0,
84 SYSCTL_INT(_debug
, OID_AUTO
, fwmem_debug
, CTLFLAG_RW
, &fwmem_debug
, 0,
85 "Fwmem driver debug flag");
87 MALLOC_DEFINE(M_FWMEM
, "fwmem", "fwmem/FireWire");
89 #define MAXLEN (512 << fwmem_speed)
96 static struct fw_xfer
*
98 struct fw_device
*fwdev
,
105 struct fw_xfer
*xfer
;
107 xfer
= fw_xfer_alloc(M_FWMEM
);
111 xfer
->fc
= fwdev
->fc
;
112 xfer
->send
.hdr
.mode
.hdr
.dst
= FWLOCALBUS
| fwdev
->dst
;
114 xfer
->send
.spd
= fwdev
->speed
;
116 xfer
->send
.spd
= min(spd
, fwdev
->speed
);
117 xfer
->act
.hand
= hand
;
118 xfer
->retry_req
= fw_asybusy
;
120 xfer
->send
.pay_len
= slen
;
121 xfer
->recv
.pay_len
= rlen
;
128 struct fw_device
*fwdev
,
134 void (*hand
)(struct fw_xfer
*))
136 struct fw_xfer
*xfer
;
139 xfer
= fwmem_xfer_req(fwdev
, (void *)sc
, spd
, 0, 4, hand
);
144 fp
= &xfer
->send
.hdr
;
145 fp
->mode
.rreqq
.tcode
= FWTCODE_RREQQ
;
146 fp
->mode
.rreqq
.dest_hi
= dst_hi
;
147 fp
->mode
.rreqq
.dest_lo
= dst_lo
;
149 xfer
->send
.payload
= NULL
;
150 xfer
->recv
.payload
= (u_int32_t
*)data
;
153 kprintf("fwmem_read_quad: %d %04x:%08x\n", fwdev
->dst
,
156 if (fw_asyreq(xfer
->fc
, -1, xfer
) == 0)
165 struct fw_device
*fwdev
,
171 void (*hand
)(struct fw_xfer
*))
173 struct fw_xfer
*xfer
;
176 xfer
= fwmem_xfer_req(fwdev
, sc
, spd
, 0, 0, hand
);
180 fp
= &xfer
->send
.hdr
;
181 fp
->mode
.wreqq
.tcode
= FWTCODE_WREQQ
;
182 fp
->mode
.wreqq
.dest_hi
= dst_hi
;
183 fp
->mode
.wreqq
.dest_lo
= dst_lo
;
184 fp
->mode
.wreqq
.data
= *(u_int32_t
*)data
;
186 xfer
->send
.payload
= xfer
->recv
.payload
= NULL
;
189 kprintf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev
->dst
,
190 dst_hi
, dst_lo
, *(u_int32_t
*)data
);
192 if (fw_asyreq(xfer
->fc
, -1, xfer
) == 0)
201 struct fw_device
*fwdev
,
208 void (*hand
)(struct fw_xfer
*))
210 struct fw_xfer
*xfer
;
213 xfer
= fwmem_xfer_req(fwdev
, sc
, spd
, 0, roundup2(len
, 4), hand
);
217 fp
= &xfer
->send
.hdr
;
218 fp
->mode
.rreqb
.tcode
= FWTCODE_RREQB
;
219 fp
->mode
.rreqb
.dest_hi
= dst_hi
;
220 fp
->mode
.rreqb
.dest_lo
= dst_lo
;
221 fp
->mode
.rreqb
.len
= len
;
222 fp
->mode
.rreqb
.extcode
= 0;
224 xfer
->send
.payload
= NULL
;
225 xfer
->recv
.payload
= data
;
228 kprintf("fwmem_read_block: %d %04x:%08x %d\n", fwdev
->dst
,
229 dst_hi
, dst_lo
, len
);
230 if (fw_asyreq(xfer
->fc
, -1, xfer
) == 0)
239 struct fw_device
*fwdev
,
246 void (*hand
)(struct fw_xfer
*))
248 struct fw_xfer
*xfer
;
251 xfer
= fwmem_xfer_req(fwdev
, sc
, spd
, len
, 0, hand
);
255 fp
= &xfer
->send
.hdr
;
256 fp
->mode
.wreqb
.tcode
= FWTCODE_WREQB
;
257 fp
->mode
.wreqb
.dest_hi
= dst_hi
;
258 fp
->mode
.wreqb
.dest_lo
= dst_lo
;
259 fp
->mode
.wreqb
.len
= len
;
260 fp
->mode
.wreqb
.extcode
= 0;
262 xfer
->send
.payload
= data
;
263 xfer
->recv
.payload
= NULL
;
266 kprintf("fwmem_write_block: %d %04x:%08x %d\n", fwdev
->dst
,
267 dst_hi
, dst_lo
, len
);
268 if (fw_asyreq(xfer
->fc
, -1, xfer
) == 0)
277 fwmem_open (struct dev_open_args
*ap
)
279 cdev_t dev
= ap
->a_head
.a_dev
;
280 struct fwmem_softc
*fms
;
282 if (dev
->si_drv1
!= NULL
) {
283 if ((ap
->a_oflags
& FWRITE
) != 0)
285 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
288 fms
= (struct fwmem_softc
*)kmalloc(sizeof(struct fwmem_softc
),
290 bcopy(&fwmem_eui64
, &fms
->eui
, sizeof(struct fw_eui64
));
291 dev
->si_drv1
= (void *)fms
;
292 dev
->si_iosize_max
= DFLTPHYS
;
296 kprintf("%s: refcount=%d\n", __func__
, fms
->refcount
);
302 fwmem_close (struct dev_close_args
*ap
)
304 cdev_t dev
= ap
->a_head
.a_dev
;
305 struct fwmem_softc
*fms
;
307 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
310 kprintf("%s: refcount=%d\n", __func__
, fms
->refcount
);
311 if (fms
->refcount
< 1) {
312 kfree(dev
->si_drv1
, M_FW
);
321 fwmem_biodone(struct fw_xfer
*xfer
)
326 bio
= (struct bio
*)xfer
->sc
;
328 bp
->b_error
= xfer
->resp
;
330 if (bp
->b_error
!= 0) {
332 kprintf("%s: err=%d\n", __func__
, bp
->b_error
);
333 bp
->b_flags
|= B_ERROR
;
334 bp
->b_resid
= bp
->b_bcount
;
341 fwmem_strategy(struct dev_strategy_args
*ap
)
343 cdev_t dev
= ap
->a_head
.a_dev
;
344 struct bio
*bio
= ap
->a_bio
;
345 struct buf
*bp
= bio
->bio_buf
;
346 struct firewire_softc
*sc
;
347 struct fwmem_softc
*fms
;
348 struct fw_device
*fwdev
;
349 struct fw_xfer
*xfer
;
350 int unit
, err
=0, iolen
;
352 /* XXX check request length */
354 unit
= DEV2UNIT(dev
);
355 sc
= devclass_get_softc(firewire_devclass
, unit
);
358 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
359 fwdev
= fw_noderesolve_eui64(sc
->fc
, &fms
->eui
);
362 kprintf("fwmem: no such device ID:%08x%08x\n",
363 fms
->eui
.hi
, fms
->eui
.lo
);
367 if (bio
->bio_offset
== NOOFFSET
) {
368 kprintf("fwmem: offset was not set bp %p\n", bp
);
373 iolen
= MIN(bp
->b_bcount
, MAXLEN
);
374 if (bp
->b_cmd
== BUF_CMD_READ
) {
375 if (iolen
== 4 && (bio
->bio_offset
& 3) == 0)
376 xfer
= fwmem_read_quad(fwdev
,
377 (void *) bio
, fwmem_speed
,
378 bio
->bio_offset
>> 32, bio
->bio_offset
& 0xffffffff,
379 bp
->b_data
, fwmem_biodone
);
381 xfer
= fwmem_read_block(fwdev
,
382 (void *) bio
, fwmem_speed
,
383 bio
->bio_offset
>> 32, bio
->bio_offset
& 0xffffffff,
384 iolen
, bp
->b_data
, fwmem_biodone
);
386 if (iolen
== 4 && (bio
->bio_offset
& 3) == 0)
387 xfer
= fwmem_write_quad(fwdev
,
388 (void *)bio
, fwmem_speed
,
389 bio
->bio_offset
>> 32, bio
->bio_offset
& 0xffffffff,
390 bp
->b_data
, fwmem_biodone
);
392 xfer
= fwmem_write_block(fwdev
,
393 (void *)bio
, fwmem_speed
,
394 bio
->bio_offset
>> 32, bio
->bio_offset
& 0xffffffff,
395 iolen
, bp
->b_data
, fwmem_biodone
);
402 bp
->b_resid
= bp
->b_bcount
- iolen
;
407 kprintf("%s: err=%d\n", __func__
, err
);
409 bp
->b_flags
|= B_ERROR
;
410 bp
->b_resid
= bp
->b_bcount
;
417 fwmem_ioctl(struct dev_ioctl_args
*ap
)
419 cdev_t dev
= ap
->a_head
.a_dev
;
420 struct fwmem_softc
*fms
;
423 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
426 bcopy(ap
->a_data
, &fms
->eui
, sizeof(struct fw_eui64
));
429 bcopy(&fms
->eui
, ap
->a_data
, sizeof(struct fw_eui64
));
437 fwmem_poll(struct dev_poll_args
*ap
)
442 fwmem_mmap(struct dev_mmap_args
*ap
)