13c60ba66SKatsushi Kobayashi /* 23c60ba66SKatsushi Kobayashi * Copyright (C) 2002 33c60ba66SKatsushi Kobayashi * Hidetoshi Shimokawa. All rights reserved. 43c60ba66SKatsushi Kobayashi * 53c60ba66SKatsushi Kobayashi * Redistribution and use in source and binary forms, with or without 63c60ba66SKatsushi Kobayashi * modification, are permitted provided that the following conditions 73c60ba66SKatsushi Kobayashi * are met: 83c60ba66SKatsushi Kobayashi * 1. Redistributions of source code must retain the above copyright 93c60ba66SKatsushi Kobayashi * notice, this list of conditions and the following disclaimer. 103c60ba66SKatsushi Kobayashi * 2. Redistributions in binary form must reproduce the above copyright 113c60ba66SKatsushi Kobayashi * notice, this list of conditions and the following disclaimer in the 123c60ba66SKatsushi Kobayashi * documentation and/or other materials provided with the distribution. 133c60ba66SKatsushi Kobayashi * 3. All advertising materials mentioning features or use of this software 143c60ba66SKatsushi Kobayashi * must display the following acknowledgement: 153c60ba66SKatsushi Kobayashi * 163c60ba66SKatsushi Kobayashi * This product includes software developed by Hidetoshi Shimokawa. 173c60ba66SKatsushi Kobayashi * 183c60ba66SKatsushi Kobayashi * 4. Neither the name of the author nor the names of its contributors 193c60ba66SKatsushi Kobayashi * may be used to endorse or promote products derived from this software 203c60ba66SKatsushi Kobayashi * without specific prior written permission. 213c60ba66SKatsushi Kobayashi * 223c60ba66SKatsushi Kobayashi * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 233c60ba66SKatsushi Kobayashi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 243c60ba66SKatsushi Kobayashi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 253c60ba66SKatsushi Kobayashi * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 263c60ba66SKatsushi Kobayashi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 273c60ba66SKatsushi Kobayashi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 283c60ba66SKatsushi Kobayashi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 293c60ba66SKatsushi Kobayashi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 303c60ba66SKatsushi Kobayashi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 313c60ba66SKatsushi Kobayashi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 323c60ba66SKatsushi Kobayashi * SUCH DAMAGE. 333c60ba66SKatsushi Kobayashi * 343c60ba66SKatsushi Kobayashi * $FreeBSD$ 353c60ba66SKatsushi Kobayashi */ 363c60ba66SKatsushi Kobayashi 373c60ba66SKatsushi Kobayashi #include <sys/param.h> 383c60ba66SKatsushi Kobayashi #include <sys/systm.h> 393c60ba66SKatsushi Kobayashi #include <sys/types.h> 403c60ba66SKatsushi Kobayashi 413c60ba66SKatsushi Kobayashi #include <sys/kernel.h> 423c60ba66SKatsushi Kobayashi #include <sys/malloc.h> 433c60ba66SKatsushi Kobayashi #include <sys/conf.h> 443c60ba66SKatsushi Kobayashi #include <sys/uio.h> 453c60ba66SKatsushi Kobayashi #include <sys/sysctl.h> 463c60ba66SKatsushi Kobayashi 473c60ba66SKatsushi Kobayashi #include <sys/bus.h> 483c60ba66SKatsushi Kobayashi 493c60ba66SKatsushi Kobayashi #include <sys/signal.h> 503c60ba66SKatsushi Kobayashi #include <sys/mman.h> 513c60ba66SKatsushi Kobayashi #include <sys/ioccom.h> 523c60ba66SKatsushi Kobayashi 533c60ba66SKatsushi Kobayashi #include <dev/firewire/firewire.h> 543c60ba66SKatsushi Kobayashi #include <dev/firewire/firewirereg.h> 553c60ba66SKatsushi Kobayashi #include <dev/firewire/fwmem.h> 563c60ba66SKatsushi Kobayashi 573c60ba66SKatsushi Kobayashi static int fwmem_node=0, fwmem_speed=2, fwmem_debug=0; 583c60ba66SKatsushi Kobayashi SYSCTL_DECL(_hw_firewire); 593c60ba66SKatsushi Kobayashi SYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0, 603c60ba66SKatsushi Kobayashi "Firewire Memory Access"); 613c60ba66SKatsushi Kobayashi SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, node, CTLFLAG_RW, &fwmem_node, 0, 623c60ba66SKatsushi Kobayashi "Fwmem target node"); 633c60ba66SKatsushi Kobayashi SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0, 643c60ba66SKatsushi Kobayashi "Fwmem link speed"); 653c60ba66SKatsushi Kobayashi SYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0, 663c60ba66SKatsushi Kobayashi "Fwmem driver debug flag"); 673c60ba66SKatsushi Kobayashi 683c60ba66SKatsushi Kobayashi struct fw_xfer * 693c60ba66SKatsushi Kobayashi fwmem_read_quad( 703c60ba66SKatsushi Kobayashi struct firewire_comm *fc, 713c60ba66SKatsushi Kobayashi int dst, 723c60ba66SKatsushi Kobayashi u_int16_t dst_hi, 733c60ba66SKatsushi Kobayashi u_int32_t dst_lo 743c60ba66SKatsushi Kobayashi ) 753c60ba66SKatsushi Kobayashi { 763c60ba66SKatsushi Kobayashi struct fw_xfer *xfer; 773c60ba66SKatsushi Kobayashi struct fw_pkt *fp; 783c60ba66SKatsushi Kobayashi int err = 0; 793c60ba66SKatsushi Kobayashi 803c60ba66SKatsushi Kobayashi xfer = fw_xfer_alloc(); 813c60ba66SKatsushi Kobayashi if (xfer == NULL) { 823c60ba66SKatsushi Kobayashi err = ENOMEM; 833c60ba66SKatsushi Kobayashi return NULL; 843c60ba66SKatsushi Kobayashi } 853c60ba66SKatsushi Kobayashi xfer->fc = fc; 863c60ba66SKatsushi Kobayashi xfer->dst = FWLOCALBUS | dst; 873c60ba66SKatsushi Kobayashi xfer->spd = fwmem_speed; /* XXX */ 883c60ba66SKatsushi Kobayashi xfer->send.len = 12; 893c60ba66SKatsushi Kobayashi xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT | M_ZERO); 903c60ba66SKatsushi Kobayashi if (xfer->send.buf == NULL) { 913c60ba66SKatsushi Kobayashi err = ENOMEM; 923c60ba66SKatsushi Kobayashi goto error; 933c60ba66SKatsushi Kobayashi } 943c60ba66SKatsushi Kobayashi xfer->send.off = 0; 953c60ba66SKatsushi Kobayashi xfer->act.hand = fw_asy_callback; 963c60ba66SKatsushi Kobayashi xfer->retry_req = fw_asybusy; 973c60ba66SKatsushi Kobayashi xfer->sc = NULL; 983c60ba66SKatsushi Kobayashi 993c60ba66SKatsushi Kobayashi fp = (struct fw_pkt *)xfer->send.buf; 1003c60ba66SKatsushi Kobayashi fp->mode.rreqq.tcode = FWTCODE_RREQQ; 1013c60ba66SKatsushi Kobayashi fp->mode.rreqq.dst = htons(xfer->dst); 1023c60ba66SKatsushi Kobayashi fp->mode.rreqq.dest_hi = htons(dst_hi); 1033c60ba66SKatsushi Kobayashi fp->mode.rreqq.dest_lo = htonl(dst_lo); 1043c60ba66SKatsushi Kobayashi 1053c60ba66SKatsushi Kobayashi if (fwmem_debug) 1063c60ba66SKatsushi Kobayashi printf("fwmem: %d %04x:%08x\n", dst, dst_hi, dst_lo); 1073c60ba66SKatsushi Kobayashi err = fw_asyreq(fc, -1, xfer); 1083c60ba66SKatsushi Kobayashi if (err) 1093c60ba66SKatsushi Kobayashi goto error; 1103c60ba66SKatsushi Kobayashi err = tsleep((caddr_t)xfer, FWPRI, "fwmem", hz); 1113c60ba66SKatsushi Kobayashi if (err == 0) { 1123c60ba66SKatsushi Kobayashi return xfer; 1133c60ba66SKatsushi Kobayashi } 1143c60ba66SKatsushi Kobayashi error: 1153c60ba66SKatsushi Kobayashi fw_xfer_free(xfer); 1163c60ba66SKatsushi Kobayashi return NULL; 1173c60ba66SKatsushi Kobayashi } 1183c60ba66SKatsushi Kobayashi 1193c60ba66SKatsushi Kobayashi struct fw_xfer * 1203c60ba66SKatsushi Kobayashi fwmem_read_block( 1213c60ba66SKatsushi Kobayashi struct firewire_comm *fc, 1223c60ba66SKatsushi Kobayashi int dst, 1233c60ba66SKatsushi Kobayashi u_int16_t dst_hi, 1243c60ba66SKatsushi Kobayashi u_int32_t dst_lo, 1253c60ba66SKatsushi Kobayashi int len 1263c60ba66SKatsushi Kobayashi ) 1273c60ba66SKatsushi Kobayashi { 1283c60ba66SKatsushi Kobayashi struct fw_xfer *xfer; 1293c60ba66SKatsushi Kobayashi struct fw_pkt *fp; 1303c60ba66SKatsushi Kobayashi int err = 0; 1313c60ba66SKatsushi Kobayashi 1323c60ba66SKatsushi Kobayashi xfer = fw_xfer_alloc(); 1333c60ba66SKatsushi Kobayashi if (xfer == NULL) { 1343c60ba66SKatsushi Kobayashi err = ENOMEM; 1353c60ba66SKatsushi Kobayashi return NULL; 1363c60ba66SKatsushi Kobayashi } 1373c60ba66SKatsushi Kobayashi xfer->fc = fc; 1383c60ba66SKatsushi Kobayashi xfer->dst = FWLOCALBUS | dst; 1393c60ba66SKatsushi Kobayashi xfer->spd = fwmem_speed; /* XXX */ 1403c60ba66SKatsushi Kobayashi xfer->send.len = 16; 1413c60ba66SKatsushi Kobayashi xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT | M_ZERO); 1423c60ba66SKatsushi Kobayashi if (xfer->send.buf == NULL) { 1433c60ba66SKatsushi Kobayashi err = ENOMEM; 1443c60ba66SKatsushi Kobayashi goto error; 1453c60ba66SKatsushi Kobayashi } 1463c60ba66SKatsushi Kobayashi xfer->send.off = 0; 1473c60ba66SKatsushi Kobayashi xfer->act.hand = fw_asy_callback; 1483c60ba66SKatsushi Kobayashi xfer->retry_req = fw_asybusy; 1493c60ba66SKatsushi Kobayashi xfer->sc = NULL; 1503c60ba66SKatsushi Kobayashi 1513c60ba66SKatsushi Kobayashi fp = (struct fw_pkt *)xfer->send.buf; 1523c60ba66SKatsushi Kobayashi fp->mode.rreqb.tcode = FWTCODE_RREQB; 1533c60ba66SKatsushi Kobayashi fp->mode.rreqb.dst = htons(xfer->dst); 1543c60ba66SKatsushi Kobayashi fp->mode.rreqb.dest_hi = htons(dst_hi); 1553c60ba66SKatsushi Kobayashi fp->mode.rreqb.dest_lo = htonl(dst_lo); 1563c60ba66SKatsushi Kobayashi fp->mode.rreqb.len = htons(len); 1573c60ba66SKatsushi Kobayashi 1583c60ba66SKatsushi Kobayashi if (fwmem_debug) 1593c60ba66SKatsushi Kobayashi printf("fwmem: %d %04x:%08x %d\n", dst, dst_hi, dst_lo, len); 1603c60ba66SKatsushi Kobayashi err = fw_asyreq(fc, -1, xfer); 1613c60ba66SKatsushi Kobayashi if (err) 1623c60ba66SKatsushi Kobayashi goto error; 1633c60ba66SKatsushi Kobayashi err = tsleep((caddr_t)xfer, FWPRI, "fwmem", hz); 1643c60ba66SKatsushi Kobayashi if (err == 0) { 1653c60ba66SKatsushi Kobayashi return xfer; 1663c60ba66SKatsushi Kobayashi } 1673c60ba66SKatsushi Kobayashi error: 1683c60ba66SKatsushi Kobayashi fw_xfer_free(xfer); 1693c60ba66SKatsushi Kobayashi return NULL; 1703c60ba66SKatsushi Kobayashi } 1713c60ba66SKatsushi Kobayashi 1723c60ba66SKatsushi Kobayashi int 1733c60ba66SKatsushi Kobayashi fwmem_open (dev_t dev, int flags, int fmt, fw_proc *td) 1743c60ba66SKatsushi Kobayashi { 1753c60ba66SKatsushi Kobayashi int err = 0; 1763c60ba66SKatsushi Kobayashi return err; 1773c60ba66SKatsushi Kobayashi } 1783c60ba66SKatsushi Kobayashi 1793c60ba66SKatsushi Kobayashi int 1803c60ba66SKatsushi Kobayashi fwmem_close (dev_t dev, int flags, int fmt, fw_proc *td) 1813c60ba66SKatsushi Kobayashi { 1823c60ba66SKatsushi Kobayashi int err = 0; 1833c60ba66SKatsushi Kobayashi return err; 1843c60ba66SKatsushi Kobayashi } 1853c60ba66SKatsushi Kobayashi 1863c60ba66SKatsushi Kobayashi #define MAXLEN 2048 1873c60ba66SKatsushi Kobayashi #define USE_QUAD 0 1883c60ba66SKatsushi Kobayashi int 1893c60ba66SKatsushi Kobayashi fwmem_read (dev_t dev, struct uio *uio, int ioflag) 1903c60ba66SKatsushi Kobayashi { 1913c60ba66SKatsushi Kobayashi struct firewire_softc *sc; 1923c60ba66SKatsushi Kobayashi struct firewire_comm *fc; 1933c60ba66SKatsushi Kobayashi struct fw_xfer *xfer; 1943c60ba66SKatsushi Kobayashi int err = 0, pad; 1953c60ba66SKatsushi Kobayashi int unit = DEV2UNIT(dev); 1963c60ba66SKatsushi Kobayashi u_int16_t dst_hi; 1973c60ba66SKatsushi Kobayashi u_int32_t dst_lo; 1983c60ba66SKatsushi Kobayashi off_t offset; 1993c60ba66SKatsushi Kobayashi int len; 2003c60ba66SKatsushi Kobayashi 2013c60ba66SKatsushi Kobayashi sc = devclass_get_softc(firewire_devclass, unit); 2023c60ba66SKatsushi Kobayashi fc = sc->fc; 2033c60ba66SKatsushi Kobayashi 2043c60ba66SKatsushi Kobayashi pad = uio->uio_offset % 4; 2053c60ba66SKatsushi Kobayashi if (fwmem_debug && pad != 0) 2063c60ba66SKatsushi Kobayashi printf("unaligned\n"); 2073c60ba66SKatsushi Kobayashi while(uio->uio_resid > 0) { 2083c60ba66SKatsushi Kobayashi offset = uio->uio_offset; 2093c60ba66SKatsushi Kobayashi offset -= pad; 2103c60ba66SKatsushi Kobayashi dst_hi = (offset >> 32) & 0xffff; 2113c60ba66SKatsushi Kobayashi dst_lo = offset & 0xffffffff; 2123c60ba66SKatsushi Kobayashi #if USE_QUAD 2133c60ba66SKatsushi Kobayashi xfer = fwmem_read_quad(fc, fwmem_node, dst_hi, dst_lo); 2143c60ba66SKatsushi Kobayashi if (xfer == NULL || xfer->resp != 0 || xfer->recv.buf == NULL) 2153c60ba66SKatsushi Kobayashi return EINVAL; /* XXX */ 2163c60ba66SKatsushi Kobayashi err = uiomove(xfer->recv.buf + xfer->recv.off + 4*3 + pad, 2173c60ba66SKatsushi Kobayashi 4 - pad, uio); 2183c60ba66SKatsushi Kobayashi #else 2193c60ba66SKatsushi Kobayashi len = uio->uio_resid; 2203c60ba66SKatsushi Kobayashi if (len > MAXLEN) 2213c60ba66SKatsushi Kobayashi len = MAXLEN; 2223c60ba66SKatsushi Kobayashi xfer = fwmem_read_block(fc, fwmem_node, dst_hi, dst_lo, len); 2233c60ba66SKatsushi Kobayashi if (xfer == NULL || xfer->resp != 0 || xfer->recv.buf == NULL) 2243c60ba66SKatsushi Kobayashi return EINVAL; /* XXX */ 2253c60ba66SKatsushi Kobayashi err = uiomove(xfer->recv.buf + xfer->recv.off + 4*4 + pad, 2263c60ba66SKatsushi Kobayashi len - pad, uio); 2273c60ba66SKatsushi Kobayashi #endif 2283c60ba66SKatsushi Kobayashi if (err) 2293c60ba66SKatsushi Kobayashi return err; 2303c60ba66SKatsushi Kobayashi fw_xfer_free(xfer); 2313c60ba66SKatsushi Kobayashi pad = 0; 2323c60ba66SKatsushi Kobayashi } 2333c60ba66SKatsushi Kobayashi return err; 2343c60ba66SKatsushi Kobayashi } 2353c60ba66SKatsushi Kobayashi int 2363c60ba66SKatsushi Kobayashi fwmem_write (dev_t dev, struct uio *uio, int ioflag) 2373c60ba66SKatsushi Kobayashi { 2383c60ba66SKatsushi Kobayashi return EINVAL; 2393c60ba66SKatsushi Kobayashi } 2403c60ba66SKatsushi Kobayashi int 2413c60ba66SKatsushi Kobayashi fwmem_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 2423c60ba66SKatsushi Kobayashi { 2433c60ba66SKatsushi Kobayashi return EINVAL; 2443c60ba66SKatsushi Kobayashi } 2453c60ba66SKatsushi Kobayashi int 2463c60ba66SKatsushi Kobayashi fwmem_poll (dev_t dev, int events, fw_proc *td) 2473c60ba66SKatsushi Kobayashi { 2483c60ba66SKatsushi Kobayashi return EINVAL; 2493c60ba66SKatsushi Kobayashi } 2503c60ba66SKatsushi Kobayashi int 2513c60ba66SKatsushi Kobayashi fwmem_mmap (dev_t dev, vm_offset_t offset, int nproto) 2523c60ba66SKatsushi Kobayashi { 2533c60ba66SKatsushi Kobayashi return EINVAL; 2543c60ba66SKatsushi Kobayashi } 255