fwmem.c revision 108281
1103285Sikob/* 2103285Sikob * Copyright (C) 2002 3103285Sikob * Hidetoshi Shimokawa. All rights reserved. 4103285Sikob * 5103285Sikob * Redistribution and use in source and binary forms, with or without 6103285Sikob * modification, are permitted provided that the following conditions 7103285Sikob * are met: 8103285Sikob * 1. Redistributions of source code must retain the above copyright 9103285Sikob * notice, this list of conditions and the following disclaimer. 10103285Sikob * 2. Redistributions in binary form must reproduce the above copyright 11103285Sikob * notice, this list of conditions and the following disclaimer in the 12103285Sikob * documentation and/or other materials provided with the distribution. 13103285Sikob * 3. All advertising materials mentioning features or use of this software 14103285Sikob * must display the following acknowledgement: 15103285Sikob * 16103285Sikob * This product includes software developed by Hidetoshi Shimokawa. 17103285Sikob * 18103285Sikob * 4. Neither the name of the author nor the names of its contributors 19103285Sikob * may be used to endorse or promote products derived from this software 20103285Sikob * without specific prior written permission. 21103285Sikob * 22103285Sikob * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23103285Sikob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24103285Sikob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25103285Sikob * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26103285Sikob * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27103285Sikob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28103285Sikob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29103285Sikob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30103285Sikob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31103285Sikob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32103285Sikob * SUCH DAMAGE. 33103285Sikob * 34103285Sikob * $FreeBSD: head/sys/dev/firewire/fwmem.c 108281 2002-12-26 06:50:09Z simokawa $ 35103285Sikob */ 36103285Sikob 37103285Sikob#include <sys/param.h> 38103285Sikob#include <sys/systm.h> 39103285Sikob#include <sys/types.h> 40103285Sikob 41103285Sikob#include <sys/kernel.h> 42103285Sikob#include <sys/malloc.h> 43103285Sikob#include <sys/conf.h> 44103285Sikob#include <sys/uio.h> 45103285Sikob#include <sys/sysctl.h> 46103285Sikob 47103285Sikob#include <sys/bus.h> 48103285Sikob 49103285Sikob#include <sys/signal.h> 50103285Sikob#include <sys/mman.h> 51103285Sikob#include <sys/ioccom.h> 52103285Sikob 53103285Sikob#include <dev/firewire/firewire.h> 54103285Sikob#include <dev/firewire/firewirereg.h> 55103285Sikob#include <dev/firewire/fwmem.h> 56103285Sikob 57106810Ssimokawastatic int fwmem_speed=2, fwmem_debug=0; 58106810Ssimokawastatic struct fw_eui64 fwmem_eui64; 59103285SikobSYSCTL_DECL(_hw_firewire); 60103285SikobSYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0, 61108281Ssimokawa "FireWire Memory Access"); 62106810SsimokawaSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW, 63106810Ssimokawa &fwmem_eui64.hi, 0, "Fwmem target EUI64 high"); 64106810SsimokawaSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_low, CTLFLAG_RW, 65106810Ssimokawa &fwmem_eui64.lo, 0, "Fwmem target EUI64 low"); 66103285SikobSYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0, 67103285Sikob "Fwmem link speed"); 68103285SikobSYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0, 69103285Sikob "Fwmem driver debug flag"); 70103285Sikob 71106816Ssimokawastatic struct fw_xfer *fwmem_xfer_req(struct fw_device *, caddr_t, 72106816Ssimokawa int, int, void *); 73106816Ssimokawa 74106816Ssimokawastatic struct fw_xfer * 75106816Ssimokawafwmem_xfer_req( 76106810Ssimokawa struct fw_device *fwdev, 77106816Ssimokawa caddr_t sc, 78106816Ssimokawa int spd, 79106816Ssimokawa int len, 80106816Ssimokawa void *hand) 81103285Sikob{ 82103285Sikob struct fw_xfer *xfer; 83103285Sikob 84103285Sikob xfer = fw_xfer_alloc(); 85106804Ssimokawa if (xfer == NULL) 86103285Sikob return NULL; 87106804Ssimokawa 88106810Ssimokawa xfer->fc = fwdev->fc; 89106810Ssimokawa xfer->dst = FWLOCALBUS | fwdev->dst; 90106816Ssimokawa if (spd < 0) 91106816Ssimokawa xfer->spd = fwdev->speed; 92106816Ssimokawa else 93106816Ssimokawa xfer->spd = min(spd, fwdev->speed); 94106816Ssimokawa xfer->send.len = len; 95106816Ssimokawa xfer->send.buf = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO); 96106804Ssimokawa 97106816Ssimokawa if (xfer->send.buf == NULL) { 98106816Ssimokawa fw_xfer_free(xfer); 99106816Ssimokawa return NULL; 100106816Ssimokawa } 101106804Ssimokawa 102103285Sikob xfer->send.off = 0; 103106804Ssimokawa xfer->act.hand = hand; 104103285Sikob xfer->retry_req = fw_asybusy; 105106816Ssimokawa xfer->sc = sc; 106103285Sikob 107106816Ssimokawa return xfer; 108106816Ssimokawa} 109106816Ssimokawa 110106816Ssimokawastruct fw_xfer * 111106816Ssimokawafwmem_read_quad( 112106816Ssimokawa struct fw_device *fwdev, 113106816Ssimokawa caddr_t sc, 114106816Ssimokawa u_int8_t spd, 115106816Ssimokawa u_int16_t dst_hi, 116106816Ssimokawa u_int32_t dst_lo, 117106816Ssimokawa void (*hand)(struct fw_xfer *)) 118106816Ssimokawa{ 119106816Ssimokawa struct fw_xfer *xfer; 120106816Ssimokawa struct fw_pkt *fp; 121106816Ssimokawa 122106816Ssimokawa xfer = fwmem_xfer_req(fwdev, sc, spd, 12, hand); 123106816Ssimokawa if (xfer == NULL) 124106816Ssimokawa return NULL; 125106816Ssimokawa 126103285Sikob fp = (struct fw_pkt *)xfer->send.buf; 127103285Sikob fp->mode.rreqq.tcode = FWTCODE_RREQQ; 128103285Sikob fp->mode.rreqq.dst = htons(xfer->dst); 129103285Sikob fp->mode.rreqq.dest_hi = htons(dst_hi); 130103285Sikob fp->mode.rreqq.dest_lo = htonl(dst_lo); 131103285Sikob 132103285Sikob if (fwmem_debug) 133106816Ssimokawa printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst, 134106816Ssimokawa dst_hi, dst_lo); 135106804Ssimokawa 136106810Ssimokawa if (fw_asyreq(xfer->fc, -1, xfer) == 0) 137103285Sikob return xfer; 138106804Ssimokawa 139103285Sikob fw_xfer_free(xfer); 140103285Sikob return NULL; 141103285Sikob} 142103285Sikob 143103285Sikobstruct fw_xfer * 144106810Ssimokawafwmem_write_quad( 145106810Ssimokawa struct fw_device *fwdev, 146106810Ssimokawa caddr_t sc, 147106810Ssimokawa u_int8_t spd, 148106810Ssimokawa u_int16_t dst_hi, 149106810Ssimokawa u_int32_t dst_lo, 150106810Ssimokawa u_int32_t data, 151106810Ssimokawa void (*hand)(struct fw_xfer *)) 152106810Ssimokawa{ 153106810Ssimokawa struct fw_xfer *xfer; 154106810Ssimokawa struct fw_pkt *fp; 155106810Ssimokawa 156106816Ssimokawa xfer = fwmem_xfer_req(fwdev, sc, spd, 16, hand); 157106810Ssimokawa if (xfer == NULL) 158106810Ssimokawa return NULL; 159106810Ssimokawa 160106810Ssimokawa fp = (struct fw_pkt *)xfer->send.buf; 161106810Ssimokawa fp->mode.wreqq.tcode = FWTCODE_RREQQ; 162106810Ssimokawa fp->mode.wreqq.dst = htons(xfer->dst); 163106810Ssimokawa fp->mode.wreqq.dest_hi = htons(dst_hi); 164106810Ssimokawa fp->mode.wreqq.dest_lo = htonl(dst_lo); 165106810Ssimokawa 166106810Ssimokawa fp->mode.wreqq.data = htonl(data); 167106810Ssimokawa 168106810Ssimokawa if (fwmem_debug) 169106816Ssimokawa printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst, 170106816Ssimokawa dst_hi, dst_lo, data); 171106810Ssimokawa 172106810Ssimokawa if (fw_asyreq(xfer->fc, -1, xfer) == 0) 173106810Ssimokawa return xfer; 174106810Ssimokawa 175106810Ssimokawa fw_xfer_free(xfer); 176106810Ssimokawa return NULL; 177106810Ssimokawa} 178106810Ssimokawa 179106810Ssimokawastruct fw_xfer * 180103285Sikobfwmem_read_block( 181106810Ssimokawa struct fw_device *fwdev, 182106810Ssimokawa caddr_t sc, 183106804Ssimokawa u_int8_t spd, 184103285Sikob u_int16_t dst_hi, 185103285Sikob u_int32_t dst_lo, 186106804Ssimokawa int len, 187106804Ssimokawa void (*hand)(struct fw_xfer *)) 188103285Sikob{ 189103285Sikob struct fw_xfer *xfer; 190103285Sikob struct fw_pkt *fp; 191103285Sikob 192106816Ssimokawa xfer = fwmem_xfer_req(fwdev, sc, spd, 16, hand); 193106804Ssimokawa if (xfer == NULL) 194103285Sikob return NULL; 195106804Ssimokawa 196103285Sikob fp = (struct fw_pkt *)xfer->send.buf; 197103285Sikob fp->mode.rreqb.tcode = FWTCODE_RREQB; 198103285Sikob fp->mode.rreqb.dst = htons(xfer->dst); 199103285Sikob fp->mode.rreqb.dest_hi = htons(dst_hi); 200103285Sikob fp->mode.rreqb.dest_lo = htonl(dst_lo); 201103285Sikob fp->mode.rreqb.len = htons(len); 202103285Sikob 203103285Sikob if (fwmem_debug) 204106816Ssimokawa printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst, 205106810Ssimokawa dst_hi, dst_lo, len); 206106810Ssimokawa if (fw_asyreq(xfer->fc, -1, xfer) == 0) 207103285Sikob return xfer; 208106804Ssimokawa 209103285Sikob fw_xfer_free(xfer); 210103285Sikob return NULL; 211103285Sikob} 212103285Sikob 213103285Sikobint 214103285Sikobfwmem_open (dev_t dev, int flags, int fmt, fw_proc *td) 215103285Sikob{ 216103285Sikob int err = 0; 217103285Sikob return err; 218103285Sikob} 219103285Sikob 220103285Sikobint 221103285Sikobfwmem_close (dev_t dev, int flags, int fmt, fw_proc *td) 222103285Sikob{ 223103285Sikob int err = 0; 224103285Sikob return err; 225103285Sikob} 226103285Sikob 227103285Sikob#define MAXLEN 2048 228103285Sikob#define USE_QUAD 0 229103285Sikobint 230103285Sikobfwmem_read (dev_t dev, struct uio *uio, int ioflag) 231103285Sikob{ 232103285Sikob struct firewire_softc *sc; 233106810Ssimokawa struct fw_device *fwdev; 234103285Sikob struct fw_xfer *xfer; 235103285Sikob int err = 0, pad; 236103285Sikob int unit = DEV2UNIT(dev); 237103285Sikob u_int16_t dst_hi; 238103285Sikob u_int32_t dst_lo; 239103285Sikob off_t offset; 240103285Sikob int len; 241103285Sikob 242103285Sikob sc = devclass_get_softc(firewire_devclass, unit); 243106810Ssimokawa fwdev = fw_noderesolve(sc->fc, fwmem_eui64); 244106810Ssimokawa if (fwdev == NULL) { 245106810Ssimokawa printf("fwmem: no such device ID:%08x%08x\n", 246106810Ssimokawa fwmem_eui64.hi, fwmem_eui64.lo); 247106810Ssimokawa return EINVAL; 248106810Ssimokawa } 249103285Sikob 250103285Sikob pad = uio->uio_offset % 4; 251103285Sikob if (fwmem_debug && pad != 0) 252103285Sikob printf("unaligned\n"); 253103285Sikob while(uio->uio_resid > 0) { 254103285Sikob offset = uio->uio_offset; 255103285Sikob offset -= pad; 256103285Sikob dst_hi = (offset >> 32) & 0xffff; 257103285Sikob dst_lo = offset & 0xffffffff; 258103285Sikob#if USE_QUAD 259106810Ssimokawa xfer = fwmem_read_quad(fwdev, NULL, fwmem_speed, 260106804Ssimokawa dst_hi, dst_lo, fw_asy_callback); 261106804Ssimokawa if (xfer == NULL) 262106804Ssimokawa return EINVAL; 263106804Ssimokawa err = tsleep((caddr_t)xfer, FWPRI, "fwmem", hz); 264106804Ssimokawa if (err !=0 || xfer->resp != 0 || xfer->recv.buf == NULL) 265103285Sikob return EINVAL; /* XXX */ 266103285Sikob err = uiomove(xfer->recv.buf + xfer->recv.off + 4*3 + pad, 267103285Sikob 4 - pad, uio); 268103285Sikob#else 269103285Sikob len = uio->uio_resid; 270103285Sikob if (len > MAXLEN) 271103285Sikob len = MAXLEN; 272106810Ssimokawa xfer = fwmem_read_block(fwdev, NULL, fwmem_speed, 273106804Ssimokawa dst_hi, dst_lo, len, fw_asy_callback); 274106804Ssimokawa if (xfer == NULL) 275106804Ssimokawa return EINVAL; 276106804Ssimokawa err = tsleep((caddr_t)xfer, FWPRI, "fwmem", hz); 277106804Ssimokawa if (err != 0 || xfer->resp != 0 || xfer->recv.buf == NULL) 278103285Sikob return EINVAL; /* XXX */ 279103285Sikob err = uiomove(xfer->recv.buf + xfer->recv.off + 4*4 + pad, 280103285Sikob len - pad, uio); 281103285Sikob#endif 282103285Sikob if (err) 283103285Sikob return err; 284103285Sikob fw_xfer_free(xfer); 285103285Sikob pad = 0; 286103285Sikob } 287103285Sikob return err; 288103285Sikob} 289103285Sikobint 290103285Sikobfwmem_write (dev_t dev, struct uio *uio, int ioflag) 291103285Sikob{ 292103285Sikob return EINVAL; 293103285Sikob} 294103285Sikobint 295103285Sikobfwmem_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 296103285Sikob{ 297103285Sikob return EINVAL; 298103285Sikob} 299103285Sikobint 300103285Sikobfwmem_poll (dev_t dev, int events, fw_proc *td) 301103285Sikob{ 302103285Sikob return EINVAL; 303103285Sikob} 304103285Sikobint 305103285Sikobfwmem_mmap (dev_t dev, vm_offset_t offset, int nproto) 306103285Sikob{ 307103285Sikob return EINVAL; 308103285Sikob} 309