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.26 2004/01/05 14:21: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>
45 #include <sys/sysctl.h>
48 #include <sys/signal.h>
50 #include <sys/fcntl.h>
51 #include <sys/thread2.h>
53 #include <bus/firewire/firewire.h>
54 #include <bus/firewire/firewirereg.h>
55 #include <bus/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 MALLOC_DEFINE(M_FWMEM
, "fwmem", "fwmem/FireWire");
73 #define MAXLEN (512 << fwmem_speed)
80 static struct fw_xfer
*
82 struct fw_device
*fwdev
,
91 xfer
= fw_xfer_alloc(M_FWMEM
);
96 xfer
->send
.hdr
.mode
.hdr
.dst
= FWLOCALBUS
| fwdev
->dst
;
98 xfer
->send
.spd
= fwdev
->speed
;
100 xfer
->send
.spd
= min(spd
, fwdev
->speed
);
101 xfer
->act
.hand
= hand
;
102 xfer
->retry_req
= fw_asybusy
;
104 xfer
->send
.pay_len
= slen
;
105 xfer
->recv
.pay_len
= rlen
;
112 struct fw_device
*fwdev
,
118 void (*hand
)(struct fw_xfer
*))
120 struct fw_xfer
*xfer
;
123 xfer
= fwmem_xfer_req(fwdev
, (void *)sc
, spd
, 0, 4, hand
);
128 fp
= &xfer
->send
.hdr
;
129 fp
->mode
.rreqq
.tcode
= FWTCODE_RREQQ
;
130 fp
->mode
.rreqq
.dest_hi
= dst_hi
;
131 fp
->mode
.rreqq
.dest_lo
= dst_lo
;
133 xfer
->send
.payload
= NULL
;
134 xfer
->recv
.payload
= (u_int32_t
*)data
;
137 kprintf("fwmem_read_quad: %d %04x:%08x\n", fwdev
->dst
,
140 if (fw_asyreq(xfer
->fc
, -1, xfer
) == 0)
149 struct fw_device
*fwdev
,
155 void (*hand
)(struct fw_xfer
*))
157 struct fw_xfer
*xfer
;
160 xfer
= fwmem_xfer_req(fwdev
, sc
, spd
, 0, 0, hand
);
164 fp
= &xfer
->send
.hdr
;
165 fp
->mode
.wreqq
.tcode
= FWTCODE_WREQQ
;
166 fp
->mode
.wreqq
.dest_hi
= dst_hi
;
167 fp
->mode
.wreqq
.dest_lo
= dst_lo
;
168 fp
->mode
.wreqq
.data
= *(u_int32_t
*)data
;
170 xfer
->send
.payload
= xfer
->recv
.payload
= NULL
;
173 kprintf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev
->dst
,
174 dst_hi
, dst_lo
, *(u_int32_t
*)data
);
176 if (fw_asyreq(xfer
->fc
, -1, xfer
) == 0)
185 struct fw_device
*fwdev
,
192 void (*hand
)(struct fw_xfer
*))
194 struct fw_xfer
*xfer
;
197 xfer
= fwmem_xfer_req(fwdev
, sc
, spd
, 0, roundup2(len
, 4), hand
);
201 fp
= &xfer
->send
.hdr
;
202 fp
->mode
.rreqb
.tcode
= FWTCODE_RREQB
;
203 fp
->mode
.rreqb
.dest_hi
= dst_hi
;
204 fp
->mode
.rreqb
.dest_lo
= dst_lo
;
205 fp
->mode
.rreqb
.len
= len
;
206 fp
->mode
.rreqb
.extcode
= 0;
208 xfer
->send
.payload
= NULL
;
209 xfer
->recv
.payload
= data
;
212 kprintf("fwmem_read_block: %d %04x:%08x %d\n", fwdev
->dst
,
213 dst_hi
, dst_lo
, len
);
214 if (fw_asyreq(xfer
->fc
, -1, xfer
) == 0)
223 struct fw_device
*fwdev
,
230 void (*hand
)(struct fw_xfer
*))
232 struct fw_xfer
*xfer
;
235 xfer
= fwmem_xfer_req(fwdev
, sc
, spd
, len
, 0, hand
);
239 fp
= &xfer
->send
.hdr
;
240 fp
->mode
.wreqb
.tcode
= FWTCODE_WREQB
;
241 fp
->mode
.wreqb
.dest_hi
= dst_hi
;
242 fp
->mode
.wreqb
.dest_lo
= dst_lo
;
243 fp
->mode
.wreqb
.len
= len
;
244 fp
->mode
.wreqb
.extcode
= 0;
246 xfer
->send
.payload
= data
;
247 xfer
->recv
.payload
= NULL
;
250 kprintf("fwmem_write_block: %d %04x:%08x %d\n", fwdev
->dst
,
251 dst_hi
, dst_lo
, len
);
252 if (fw_asyreq(xfer
->fc
, -1, xfer
) == 0)
261 fwmem_open (struct dev_open_args
*ap
)
263 cdev_t dev
= ap
->a_head
.a_dev
;
264 struct fwmem_softc
*fms
;
266 if (dev
->si_drv1
!= NULL
) {
267 if ((ap
->a_oflags
& FWRITE
) != 0)
269 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
272 fms
= (struct fwmem_softc
*)kmalloc(sizeof(struct fwmem_softc
),
274 bcopy(&fwmem_eui64
, &fms
->eui
, sizeof(struct fw_eui64
));
275 dev
->si_drv1
= (void *)fms
;
276 dev
->si_iosize_max
= min(MAXPHYS
,64*1024);
280 kprintf("%s: refcount=%d\n", __func__
, fms
->refcount
);
286 fwmem_close (struct dev_close_args
*ap
)
288 cdev_t dev
= ap
->a_head
.a_dev
;
289 struct fwmem_softc
*fms
;
291 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
294 kprintf("%s: refcount=%d\n", __func__
, fms
->refcount
);
295 if (fms
->refcount
< 1) {
296 kfree(dev
->si_drv1
, M_FW
);
305 fwmem_biodone(struct fw_xfer
*xfer
)
310 bio
= (struct bio
*)xfer
->sc
;
312 bp
->b_error
= xfer
->resp
;
314 if (bp
->b_error
!= 0) {
316 kprintf("%s: err=%d\n", __func__
, bp
->b_error
);
317 bp
->b_flags
|= B_ERROR
;
318 bp
->b_resid
= bp
->b_bcount
;
325 fwmem_strategy(struct dev_strategy_args
*ap
)
327 cdev_t dev
= ap
->a_head
.a_dev
;
328 struct bio
*bio
= ap
->a_bio
;
329 struct buf
*bp
= bio
->bio_buf
;
330 struct firewire_softc
*sc
;
331 struct fwmem_softc
*fms
;
332 struct fw_device
*fwdev
;
333 struct fw_xfer
*xfer
;
334 int unit
, err
=0, iolen
;
336 /* XXX check request length */
338 unit
= DEV2UNIT(dev
);
339 sc
= devclass_get_softc(firewire_devclass
, unit
);
342 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
343 fwdev
= fw_noderesolve_eui64(sc
->fc
, &fms
->eui
);
346 kprintf("fwmem: no such device ID:%08x%08x\n",
347 fms
->eui
.hi
, fms
->eui
.lo
);
351 if (bio
->bio_offset
== NOOFFSET
) {
352 kprintf("fwmem: offset was not set bp %p\n", bp
);
357 iolen
= MIN(bp
->b_bcount
, MAXLEN
);
358 if (bp
->b_cmd
== BUF_CMD_READ
) {
359 if (iolen
== 4 && (bio
->bio_offset
& 3) == 0)
360 xfer
= fwmem_read_quad(fwdev
,
361 (void *) bio
, fwmem_speed
,
362 bio
->bio_offset
>> 32, bio
->bio_offset
& 0xffffffff,
363 bp
->b_data
, fwmem_biodone
);
365 xfer
= fwmem_read_block(fwdev
,
366 (void *) bio
, fwmem_speed
,
367 bio
->bio_offset
>> 32, bio
->bio_offset
& 0xffffffff,
368 iolen
, bp
->b_data
, fwmem_biodone
);
370 if (iolen
== 4 && (bio
->bio_offset
& 3) == 0)
371 xfer
= fwmem_write_quad(fwdev
,
372 (void *)bio
, fwmem_speed
,
373 bio
->bio_offset
>> 32, bio
->bio_offset
& 0xffffffff,
374 bp
->b_data
, fwmem_biodone
);
376 xfer
= fwmem_write_block(fwdev
,
377 (void *)bio
, fwmem_speed
,
378 bio
->bio_offset
>> 32, bio
->bio_offset
& 0xffffffff,
379 iolen
, bp
->b_data
, fwmem_biodone
);
386 bp
->b_resid
= bp
->b_bcount
- iolen
;
391 kprintf("%s: err=%d\n", __func__
, err
);
393 bp
->b_flags
|= B_ERROR
;
394 bp
->b_resid
= bp
->b_bcount
;
401 fwmem_ioctl(struct dev_ioctl_args
*ap
)
403 cdev_t dev
= ap
->a_head
.a_dev
;
404 struct fwmem_softc
*fms
;
407 fms
= (struct fwmem_softc
*)dev
->si_drv1
;
410 bcopy(ap
->a_data
, &fms
->eui
, sizeof(struct fw_eui64
));
413 bcopy(&fms
->eui
, ap
->a_data
, sizeof(struct fw_eui64
));
422 fwmem_mmap(struct dev_mmap_args
*ap
)