1098ca2bdSWarner Losh /*- 2*718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause 3*718cf2ccSPedro F. Giffuni * 477ee030bSHidetoshi Shimokawa * Copyright (c) 2003 Hidetoshi Shimokawa 517821895SHidetoshi Shimokawa * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 617821895SHidetoshi Shimokawa * All rights reserved. 717821895SHidetoshi Shimokawa * 817821895SHidetoshi Shimokawa * Redistribution and use in source and binary forms, with or without 917821895SHidetoshi Shimokawa * modification, are permitted provided that the following conditions 1017821895SHidetoshi Shimokawa * are met: 1117821895SHidetoshi Shimokawa * 1. Redistributions of source code must retain the above copyright 1217821895SHidetoshi Shimokawa * notice, this list of conditions and the following disclaimer. 1317821895SHidetoshi Shimokawa * 2. Redistributions in binary form must reproduce the above copyright 1417821895SHidetoshi Shimokawa * notice, this list of conditions and the following disclaimer in the 1517821895SHidetoshi Shimokawa * documentation and/or other materials provided with the distribution. 1617821895SHidetoshi Shimokawa * 3. All advertising materials mentioning features or use of this software 1717821895SHidetoshi Shimokawa * must display the acknowledgement as bellow: 1817821895SHidetoshi Shimokawa * 1917821895SHidetoshi Shimokawa * This product includes software developed by K. Kobayashi and H. Shimokawa 2017821895SHidetoshi Shimokawa * 2117821895SHidetoshi Shimokawa * 4. The name of the author may not be used to endorse or promote products 2217821895SHidetoshi Shimokawa * derived from this software without specific prior written permission. 2317821895SHidetoshi Shimokawa * 2417821895SHidetoshi Shimokawa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2517821895SHidetoshi Shimokawa * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2617821895SHidetoshi Shimokawa * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2717821895SHidetoshi Shimokawa * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 2817821895SHidetoshi Shimokawa * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2917821895SHidetoshi Shimokawa * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 3017821895SHidetoshi Shimokawa * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3117821895SHidetoshi Shimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3217821895SHidetoshi Shimokawa * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 3317821895SHidetoshi Shimokawa * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3417821895SHidetoshi Shimokawa * POSSIBILITY OF SUCH DAMAGE. 3517821895SHidetoshi Shimokawa * 3617821895SHidetoshi Shimokawa * $FreeBSD$ 3717821895SHidetoshi Shimokawa * 3817821895SHidetoshi Shimokawa */ 3917821895SHidetoshi Shimokawa 4017821895SHidetoshi Shimokawa #include <sys/param.h> 4117821895SHidetoshi Shimokawa #include <sys/systm.h> 4217821895SHidetoshi Shimokawa #include <sys/types.h> 4317821895SHidetoshi Shimokawa #include <sys/mbuf.h> 44c4778b5dSHidetoshi Shimokawa #include <sys/bio.h> 4517821895SHidetoshi Shimokawa 4617821895SHidetoshi Shimokawa #include <sys/kernel.h> 4717821895SHidetoshi Shimokawa #include <sys/malloc.h> 4817821895SHidetoshi Shimokawa #include <sys/conf.h> 4917821895SHidetoshi Shimokawa #include <sys/poll.h> 5017821895SHidetoshi Shimokawa 5117821895SHidetoshi Shimokawa #include <sys/bus.h> 52a160e00eSHidetoshi Shimokawa #include <sys/ctype.h> 5377ee030bSHidetoshi Shimokawa #include <machine/bus.h> 5417821895SHidetoshi Shimokawa 5517821895SHidetoshi Shimokawa #include <sys/ioccom.h> 5617821895SHidetoshi Shimokawa 5717821895SHidetoshi Shimokawa #include <dev/firewire/firewire.h> 5817821895SHidetoshi Shimokawa #include <dev/firewire/firewirereg.h> 5977ee030bSHidetoshi Shimokawa #include <dev/firewire/fwdma.h> 6017821895SHidetoshi Shimokawa #include <dev/firewire/fwmem.h> 616d6f7f28SHidetoshi Shimokawa #include <dev/firewire/iec68113.h> 6217821895SHidetoshi Shimokawa 6317821895SHidetoshi Shimokawa #define FWNODE_INVAL 0xffff 6417821895SHidetoshi Shimokawa 6517821895SHidetoshi Shimokawa static d_open_t fw_open; 6617821895SHidetoshi Shimokawa static d_close_t fw_close; 6717821895SHidetoshi Shimokawa static d_ioctl_t fw_ioctl; 6817821895SHidetoshi Shimokawa static d_poll_t fw_poll; 6917821895SHidetoshi Shimokawa static d_read_t fw_read; /* for Isochronous packet */ 7017821895SHidetoshi Shimokawa static d_write_t fw_write; 7117821895SHidetoshi Shimokawa static d_mmap_t fw_mmap; 72c4778b5dSHidetoshi Shimokawa static d_strategy_t fw_strategy; 7317821895SHidetoshi Shimokawa 74dc08ffecSPoul-Henning Kamp struct cdevsw firewire_cdevsw = { 75dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 767ac40f5fSPoul-Henning Kamp .d_open = fw_open, 777ac40f5fSPoul-Henning Kamp .d_close = fw_close, 787ac40f5fSPoul-Henning Kamp .d_read = fw_read, 797ac40f5fSPoul-Henning Kamp .d_write = fw_write, 807ac40f5fSPoul-Henning Kamp .d_ioctl = fw_ioctl, 817ac40f5fSPoul-Henning Kamp .d_poll = fw_poll, 827ac40f5fSPoul-Henning Kamp .d_mmap = fw_mmap, 83c4778b5dSHidetoshi Shimokawa .d_strategy = fw_strategy, 847ac40f5fSPoul-Henning Kamp .d_name = "fw", 8517821895SHidetoshi Shimokawa }; 8617821895SHidetoshi Shimokawa 876cada79aSHidetoshi Shimokawa struct fw_drv1 { 880892f4c5SHidetoshi Shimokawa struct firewire_comm *fc; 896cada79aSHidetoshi Shimokawa struct fw_xferq *ir; 906cada79aSHidetoshi Shimokawa struct fw_xferq *it; 916cada79aSHidetoshi Shimokawa struct fw_isobufreq bufreq; 920892f4c5SHidetoshi Shimokawa STAILQ_HEAD(, fw_bind) binds; 930892f4c5SHidetoshi Shimokawa STAILQ_HEAD(, fw_xfer) rq; 946cada79aSHidetoshi Shimokawa }; 956cada79aSHidetoshi Shimokawa 966cada79aSHidetoshi Shimokawa static int 976cada79aSHidetoshi Shimokawa fwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q, 986cada79aSHidetoshi Shimokawa struct fw_bufspec *b) 996cada79aSHidetoshi Shimokawa { 1006cada79aSHidetoshi Shimokawa int i; 1016cada79aSHidetoshi Shimokawa 1026cada79aSHidetoshi Shimokawa if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF)) 1036cada79aSHidetoshi Shimokawa return (EBUSY); 1046cada79aSHidetoshi Shimokawa 10523667f08SAlexander Kabaev q->bulkxfer = malloc(sizeof(struct fw_bulkxfer) * b->nchunk, 1066cada79aSHidetoshi Shimokawa M_FW, M_WAITOK); 1076cada79aSHidetoshi Shimokawa 10803161bbcSDoug Rabson b->psize = roundup2(b->psize, sizeof(uint32_t)); 10903161bbcSDoug Rabson q->buf = fwdma_malloc_multiseg(fc, sizeof(uint32_t), 1106cada79aSHidetoshi Shimokawa b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK); 1116cada79aSHidetoshi Shimokawa 1126cada79aSHidetoshi Shimokawa if (q->buf == NULL) { 1136cada79aSHidetoshi Shimokawa free(q->bulkxfer, M_FW); 1146cada79aSHidetoshi Shimokawa q->bulkxfer = NULL; 1156cada79aSHidetoshi Shimokawa return (ENOMEM); 1166cada79aSHidetoshi Shimokawa } 1176cada79aSHidetoshi Shimokawa q->bnchunk = b->nchunk; 1186cada79aSHidetoshi Shimokawa q->bnpacket = b->npacket; 1196cada79aSHidetoshi Shimokawa q->psize = (b->psize + 3) & ~3; 1206cada79aSHidetoshi Shimokawa q->queued = 0; 1216cada79aSHidetoshi Shimokawa 1226cada79aSHidetoshi Shimokawa STAILQ_INIT(&q->stvalid); 1236cada79aSHidetoshi Shimokawa STAILQ_INIT(&q->stfree); 1246cada79aSHidetoshi Shimokawa STAILQ_INIT(&q->stdma); 1256cada79aSHidetoshi Shimokawa q->stproc = NULL; 1266cada79aSHidetoshi Shimokawa 1276cada79aSHidetoshi Shimokawa for (i = 0; i < q->bnchunk; i++) { 1286cada79aSHidetoshi Shimokawa q->bulkxfer[i].poffset = i * q->bnpacket; 1296cada79aSHidetoshi Shimokawa q->bulkxfer[i].mbuf = NULL; 1306cada79aSHidetoshi Shimokawa STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link); 1316cada79aSHidetoshi Shimokawa } 1326cada79aSHidetoshi Shimokawa 1336cada79aSHidetoshi Shimokawa q->flag &= ~FWXFERQ_MODEMASK; 1346cada79aSHidetoshi Shimokawa q->flag |= FWXFERQ_STREAM; 1356cada79aSHidetoshi Shimokawa q->flag |= FWXFERQ_EXTBUF; 1366cada79aSHidetoshi Shimokawa 1376cada79aSHidetoshi Shimokawa return (0); 1386cada79aSHidetoshi Shimokawa } 1396cada79aSHidetoshi Shimokawa 1406cada79aSHidetoshi Shimokawa static int 1416cada79aSHidetoshi Shimokawa fwdev_freebuf(struct fw_xferq *q) 1426cada79aSHidetoshi Shimokawa { 1436cada79aSHidetoshi Shimokawa if (q->flag & FWXFERQ_EXTBUF) { 1446cada79aSHidetoshi Shimokawa if (q->buf != NULL) 1456cada79aSHidetoshi Shimokawa fwdma_free_multiseg(q->buf); 1466cada79aSHidetoshi Shimokawa q->buf = NULL; 1476cada79aSHidetoshi Shimokawa free(q->bulkxfer, M_FW); 1486cada79aSHidetoshi Shimokawa q->bulkxfer = NULL; 1496cada79aSHidetoshi Shimokawa q->flag &= ~FWXFERQ_EXTBUF; 1506cada79aSHidetoshi Shimokawa q->psize = 0; 1516cada79aSHidetoshi Shimokawa q->maxq = FWMAXQUEUE; 1526cada79aSHidetoshi Shimokawa } 1536cada79aSHidetoshi Shimokawa return (0); 1546cada79aSHidetoshi Shimokawa } 1556cada79aSHidetoshi Shimokawa 1566cada79aSHidetoshi Shimokawa 15717821895SHidetoshi Shimokawa static int 15889c9c53dSPoul-Henning Kamp fw_open(struct cdev *dev, int flags, int fmt, fw_proc *td) 15917821895SHidetoshi Shimokawa { 16017821895SHidetoshi Shimokawa int err = 0; 1610892f4c5SHidetoshi Shimokawa int unit = DEV2UNIT(dev); 1620892f4c5SHidetoshi Shimokawa struct fw_drv1 *d; 1630892f4c5SHidetoshi Shimokawa struct firewire_softc *sc; 16417821895SHidetoshi Shimokawa 16517821895SHidetoshi Shimokawa if (DEV_FWMEM(dev)) 16617821895SHidetoshi Shimokawa return fwmem_open(dev, flags, fmt, td); 16717821895SHidetoshi Shimokawa 1689950b741SHidetoshi Shimokawa sc = devclass_get_softc(firewire_devclass, unit); 1699950b741SHidetoshi Shimokawa if (sc == NULL) 1709950b741SHidetoshi Shimokawa return (ENXIO); 1719950b741SHidetoshi Shimokawa 1729950b741SHidetoshi Shimokawa FW_GLOCK(sc->fc); 1739950b741SHidetoshi Shimokawa if (dev->si_drv1 != NULL) { 1749950b741SHidetoshi Shimokawa FW_GUNLOCK(sc->fc); 1753a927c87SHidetoshi Shimokawa return (EBUSY); 1769950b741SHidetoshi Shimokawa } 1779950b741SHidetoshi Shimokawa /* set dummy value for allocation */ 1789950b741SHidetoshi Shimokawa dev->si_drv1 = (void *)-1; 1799950b741SHidetoshi Shimokawa FW_GUNLOCK(sc->fc); 1809950b741SHidetoshi Shimokawa 1819950b741SHidetoshi Shimokawa dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); 1823a927c87SHidetoshi Shimokawa 183a160e00eSHidetoshi Shimokawa if ((dev->si_flags & SI_NAMED) == 0) { 184a160e00eSHidetoshi Shimokawa int unit = DEV2UNIT(dev); 185a160e00eSHidetoshi Shimokawa int sub = DEV2SUB(dev); 186a160e00eSHidetoshi Shimokawa 1876bfa9a2dSEd Schouten make_dev(&firewire_cdevsw, dev2unit(dev), 18823667f08SAlexander Kabaev UID_ROOT, GID_OPERATOR, 0660, "fw%d.%d", unit, sub); 189a160e00eSHidetoshi Shimokawa } 19023667f08SAlexander Kabaev 19123667f08SAlexander Kabaev d = dev->si_drv1; 1920892f4c5SHidetoshi Shimokawa d->fc = sc->fc; 1930892f4c5SHidetoshi Shimokawa STAILQ_INIT(&d->binds); 1940892f4c5SHidetoshi Shimokawa STAILQ_INIT(&d->rq); 1956cada79aSHidetoshi Shimokawa 19617821895SHidetoshi Shimokawa return err; 19717821895SHidetoshi Shimokawa } 19817821895SHidetoshi Shimokawa 19917821895SHidetoshi Shimokawa static int 20089c9c53dSPoul-Henning Kamp fw_close(struct cdev *dev, int flags, int fmt, fw_proc *td) 20117821895SHidetoshi Shimokawa { 2026cada79aSHidetoshi Shimokawa struct firewire_comm *fc; 2036cada79aSHidetoshi Shimokawa struct fw_drv1 *d; 20417821895SHidetoshi Shimokawa struct fw_xfer *xfer; 20517821895SHidetoshi Shimokawa struct fw_bind *fwb; 20617821895SHidetoshi Shimokawa int err = 0; 20717821895SHidetoshi Shimokawa 20817821895SHidetoshi Shimokawa if (DEV_FWMEM(dev)) 20917821895SHidetoshi Shimokawa return fwmem_close(dev, flags, fmt, td); 21017821895SHidetoshi Shimokawa 21123667f08SAlexander Kabaev d = dev->si_drv1; 2120892f4c5SHidetoshi Shimokawa fc = d->fc; 21317821895SHidetoshi Shimokawa 2140892f4c5SHidetoshi Shimokawa /* remove binding */ 2150892f4c5SHidetoshi Shimokawa for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL; 2160892f4c5SHidetoshi Shimokawa fwb = STAILQ_FIRST(&d->binds)) { 2170892f4c5SHidetoshi Shimokawa fw_bindremove(fc, fwb); 2180892f4c5SHidetoshi Shimokawa STAILQ_REMOVE_HEAD(&d->binds, chlist); 2190892f4c5SHidetoshi Shimokawa fw_xferlist_remove(&fwb->xferlist); 2200892f4c5SHidetoshi Shimokawa free(fwb, M_FW); 2210892f4c5SHidetoshi Shimokawa } 2226cada79aSHidetoshi Shimokawa if (d->ir != NULL) { 2236cada79aSHidetoshi Shimokawa struct fw_xferq *ir = d->ir; 2246cada79aSHidetoshi Shimokawa 2256cada79aSHidetoshi Shimokawa if ((ir->flag & FWXFERQ_OPEN) == 0) 2266cada79aSHidetoshi Shimokawa return (EINVAL); 2276cada79aSHidetoshi Shimokawa if (ir->flag & FWXFERQ_RUNNING) { 2286cada79aSHidetoshi Shimokawa ir->flag &= ~FWXFERQ_RUNNING; 2296cada79aSHidetoshi Shimokawa fc->irx_disable(fc, ir->dmach); 23017821895SHidetoshi Shimokawa } 2316cada79aSHidetoshi Shimokawa /* free extbuf */ 2326cada79aSHidetoshi Shimokawa fwdev_freebuf(ir); 2336cada79aSHidetoshi Shimokawa /* drain receiving buffer */ 2346cada79aSHidetoshi Shimokawa for (xfer = STAILQ_FIRST(&ir->q); 2356cada79aSHidetoshi Shimokawa xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) { 2366cada79aSHidetoshi Shimokawa ir->queued--; 2376cada79aSHidetoshi Shimokawa STAILQ_REMOVE_HEAD(&ir->q, link); 23817821895SHidetoshi Shimokawa 23917821895SHidetoshi Shimokawa xfer->resp = 0; 24017821895SHidetoshi Shimokawa fw_xfer_done(xfer); 24117821895SHidetoshi Shimokawa } 24223667f08SAlexander Kabaev ir->flag &= ~(FWXFERQ_OPEN | FWXFERQ_MODEMASK | 24323667f08SAlexander Kabaev FWXFERQ_CHTAGMASK); 2446cada79aSHidetoshi Shimokawa d->ir = NULL; 2456cada79aSHidetoshi Shimokawa 2466cada79aSHidetoshi Shimokawa } 2476cada79aSHidetoshi Shimokawa if (d->it != NULL) { 2486cada79aSHidetoshi Shimokawa struct fw_xferq *it = d->it; 2496cada79aSHidetoshi Shimokawa 2506cada79aSHidetoshi Shimokawa if ((it->flag & FWXFERQ_OPEN) == 0) 2516cada79aSHidetoshi Shimokawa return (EINVAL); 2526cada79aSHidetoshi Shimokawa if (it->flag & FWXFERQ_RUNNING) { 2536cada79aSHidetoshi Shimokawa it->flag &= ~FWXFERQ_RUNNING; 2546cada79aSHidetoshi Shimokawa fc->itx_disable(fc, it->dmach); 2556cada79aSHidetoshi Shimokawa } 2566cada79aSHidetoshi Shimokawa /* free extbuf */ 2576cada79aSHidetoshi Shimokawa fwdev_freebuf(it); 2586cada79aSHidetoshi Shimokawa it->flag &= ~(FWXFERQ_OPEN | 2596cada79aSHidetoshi Shimokawa FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 2606cada79aSHidetoshi Shimokawa d->it = NULL; 2616cada79aSHidetoshi Shimokawa } 2626cada79aSHidetoshi Shimokawa free(dev->si_drv1, M_FW); 2636cada79aSHidetoshi Shimokawa dev->si_drv1 = NULL; 2646cada79aSHidetoshi Shimokawa 26517821895SHidetoshi Shimokawa return err; 26617821895SHidetoshi Shimokawa } 26717821895SHidetoshi Shimokawa 2680892f4c5SHidetoshi Shimokawa static int 2690892f4c5SHidetoshi Shimokawa fw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 2700892f4c5SHidetoshi Shimokawa { 2710892f4c5SHidetoshi Shimokawa int err = 0, s; 2720892f4c5SHidetoshi Shimokawa struct fw_xfer *xfer; 2730892f4c5SHidetoshi Shimokawa struct fw_bind *fwb; 2740892f4c5SHidetoshi Shimokawa struct fw_pkt *fp; 2750892f4c5SHidetoshi Shimokawa struct tcode_info *tinfo; 2760892f4c5SHidetoshi Shimokawa 2779950b741SHidetoshi Shimokawa FW_GLOCK(d->fc); 2780892f4c5SHidetoshi Shimokawa while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == 0) 2799950b741SHidetoshi Shimokawa err = msleep(&d->rq, FW_GMTX(d->fc), FWPRI, "fwra", 0); 2800892f4c5SHidetoshi Shimokawa 2819950b741SHidetoshi Shimokawa if (err != 0) { 2829950b741SHidetoshi Shimokawa FW_GUNLOCK(d->fc); 2830892f4c5SHidetoshi Shimokawa return (err); 2849950b741SHidetoshi Shimokawa } 2850892f4c5SHidetoshi Shimokawa 2860892f4c5SHidetoshi Shimokawa s = splfw(); 2870892f4c5SHidetoshi Shimokawa STAILQ_REMOVE_HEAD(&d->rq, link); 2889950b741SHidetoshi Shimokawa FW_GUNLOCK(xfer->fc); 2890892f4c5SHidetoshi Shimokawa splx(s); 2900892f4c5SHidetoshi Shimokawa fp = &xfer->recv.hdr; 2910892f4c5SHidetoshi Shimokawa #if 0 /* for GASP ?? */ 2920892f4c5SHidetoshi Shimokawa if (fc->irx_post != NULL) 2930892f4c5SHidetoshi Shimokawa fc->irx_post(fc, fp->mode.ld); 2940892f4c5SHidetoshi Shimokawa #endif 2950892f4c5SHidetoshi Shimokawa tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode]; 29623667f08SAlexander Kabaev err = uiomove(fp, tinfo->hdr_len, uio); 2970892f4c5SHidetoshi Shimokawa if (err) 2980892f4c5SHidetoshi Shimokawa goto out; 29923667f08SAlexander Kabaev err = uiomove(xfer->recv.payload, xfer->recv.pay_len, uio); 3000892f4c5SHidetoshi Shimokawa 3010892f4c5SHidetoshi Shimokawa out: 3020892f4c5SHidetoshi Shimokawa /* recycle this xfer */ 3030892f4c5SHidetoshi Shimokawa fwb = (struct fw_bind *)xfer->sc; 3040892f4c5SHidetoshi Shimokawa fw_xfer_unload(xfer); 3050892f4c5SHidetoshi Shimokawa xfer->recv.pay_len = PAGE_SIZE; 3069950b741SHidetoshi Shimokawa FW_GLOCK(xfer->fc); 3070892f4c5SHidetoshi Shimokawa STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 3089950b741SHidetoshi Shimokawa FW_GUNLOCK(xfer->fc); 3090892f4c5SHidetoshi Shimokawa return (err); 3100892f4c5SHidetoshi Shimokawa } 3110892f4c5SHidetoshi Shimokawa 31217821895SHidetoshi Shimokawa /* 31317821895SHidetoshi Shimokawa * read request. 31417821895SHidetoshi Shimokawa */ 31517821895SHidetoshi Shimokawa static int 31689c9c53dSPoul-Henning Kamp fw_read(struct cdev *dev, struct uio *uio, int ioflag) 31717821895SHidetoshi Shimokawa { 3180892f4c5SHidetoshi Shimokawa struct fw_drv1 *d; 31917821895SHidetoshi Shimokawa struct fw_xferq *ir; 3200892f4c5SHidetoshi Shimokawa struct firewire_comm *fc; 32117821895SHidetoshi Shimokawa int err = 0, s, slept = 0; 32217821895SHidetoshi Shimokawa struct fw_pkt *fp; 32317821895SHidetoshi Shimokawa 32417821895SHidetoshi Shimokawa if (DEV_FWMEM(dev)) 3259950b741SHidetoshi Shimokawa return (physio(dev, uio, ioflag)); 32617821895SHidetoshi Shimokawa 32723667f08SAlexander Kabaev d = dev->si_drv1; 3280892f4c5SHidetoshi Shimokawa fc = d->fc; 3290892f4c5SHidetoshi Shimokawa ir = d->ir; 3300892f4c5SHidetoshi Shimokawa 3310892f4c5SHidetoshi Shimokawa if (ir == NULL) 3320892f4c5SHidetoshi Shimokawa return (fw_read_async(d, uio, ioflag)); 3330892f4c5SHidetoshi Shimokawa 3340892f4c5SHidetoshi Shimokawa if (ir->buf == NULL) 3356cada79aSHidetoshi Shimokawa return (EIO); 33617821895SHidetoshi Shimokawa 3379950b741SHidetoshi Shimokawa FW_GLOCK(fc); 33817821895SHidetoshi Shimokawa readloop: 33977ee030bSHidetoshi Shimokawa if (ir->stproc == NULL) { 340c3e9e255SHidetoshi Shimokawa /* iso bulkxfer */ 34117821895SHidetoshi Shimokawa ir->stproc = STAILQ_FIRST(&ir->stvalid); 34217821895SHidetoshi Shimokawa if (ir->stproc != NULL) { 34317821895SHidetoshi Shimokawa s = splfw(); 34417821895SHidetoshi Shimokawa STAILQ_REMOVE_HEAD(&ir->stvalid, link); 34517821895SHidetoshi Shimokawa splx(s); 34617821895SHidetoshi Shimokawa ir->queued = 0; 34717821895SHidetoshi Shimokawa } 34817821895SHidetoshi Shimokawa } 3490892f4c5SHidetoshi Shimokawa if (ir->stproc == NULL) { 350453130d9SPedro F. Giffuni /* no data available */ 35117821895SHidetoshi Shimokawa if (slept == 0) { 35217821895SHidetoshi Shimokawa slept = 1; 35317821895SHidetoshi Shimokawa ir->flag |= FWXFERQ_WAKEUP; 3549950b741SHidetoshi Shimokawa err = msleep(ir, FW_GMTX(fc), FWPRI, "fw_read", hz); 35517821895SHidetoshi Shimokawa ir->flag &= ~FWXFERQ_WAKEUP; 356c3e9e255SHidetoshi Shimokawa if (err == 0) 35717821895SHidetoshi Shimokawa goto readloop; 358c3e9e255SHidetoshi Shimokawa } else if (slept == 1) 35917821895SHidetoshi Shimokawa err = EIO; 3609950b741SHidetoshi Shimokawa FW_GUNLOCK(fc); 36117821895SHidetoshi Shimokawa return err; 36217821895SHidetoshi Shimokawa } else if (ir->stproc != NULL) { 363c3e9e255SHidetoshi Shimokawa /* iso bulkxfer */ 3649950b741SHidetoshi Shimokawa FW_GUNLOCK(fc); 36577ee030bSHidetoshi Shimokawa fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 36677ee030bSHidetoshi Shimokawa ir->stproc->poffset + ir->queued); 3670892f4c5SHidetoshi Shimokawa if (fc->irx_post != NULL) 3680892f4c5SHidetoshi Shimokawa fc->irx_post(fc, fp->mode.ld); 36977ee030bSHidetoshi Shimokawa if (fp->mode.stream.len == 0) { 37017821895SHidetoshi Shimokawa err = EIO; 37117821895SHidetoshi Shimokawa return err; 37217821895SHidetoshi Shimokawa } 373c3e9e255SHidetoshi Shimokawa err = uiomove((caddr_t)fp, 37403161bbcSDoug Rabson fp->mode.stream.len + sizeof(uint32_t), uio); 37517821895SHidetoshi Shimokawa ir->queued++; 37617821895SHidetoshi Shimokawa if (ir->queued >= ir->bnpacket) { 37717821895SHidetoshi Shimokawa s = splfw(); 37817821895SHidetoshi Shimokawa STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 37917821895SHidetoshi Shimokawa splx(s); 3800892f4c5SHidetoshi Shimokawa fc->irx_enable(fc, ir->dmach); 38117821895SHidetoshi Shimokawa ir->stproc = NULL; 38217821895SHidetoshi Shimokawa } 383c3e9e255SHidetoshi Shimokawa if (uio->uio_resid >= ir->psize) { 384c3e9e255SHidetoshi Shimokawa slept = -1; 3859950b741SHidetoshi Shimokawa FW_GLOCK(fc); 386c3e9e255SHidetoshi Shimokawa goto readloop; 387c3e9e255SHidetoshi Shimokawa } 38817821895SHidetoshi Shimokawa } 38917821895SHidetoshi Shimokawa return err; 39017821895SHidetoshi Shimokawa } 39117821895SHidetoshi Shimokawa 39217821895SHidetoshi Shimokawa static int 3930892f4c5SHidetoshi Shimokawa fw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 3940892f4c5SHidetoshi Shimokawa { 3950892f4c5SHidetoshi Shimokawa struct fw_xfer *xfer; 3960892f4c5SHidetoshi Shimokawa struct fw_pkt pkt; 3970892f4c5SHidetoshi Shimokawa struct tcode_info *tinfo; 3980892f4c5SHidetoshi Shimokawa int err; 3990892f4c5SHidetoshi Shimokawa 4000892f4c5SHidetoshi Shimokawa bzero(&pkt, sizeof(struct fw_pkt)); 4010892f4c5SHidetoshi Shimokawa if ((err = uiomove((caddr_t)&pkt, sizeof(uint32_t), uio))) 4020892f4c5SHidetoshi Shimokawa return (err); 4030892f4c5SHidetoshi Shimokawa tinfo = &d->fc->tcode[pkt.mode.hdr.tcode]; 4040892f4c5SHidetoshi Shimokawa if ((err = uiomove((caddr_t)&pkt + sizeof(uint32_t), 4050892f4c5SHidetoshi Shimokawa tinfo->hdr_len - sizeof(uint32_t), uio))) 4060892f4c5SHidetoshi Shimokawa return (err); 4070892f4c5SHidetoshi Shimokawa 4080892f4c5SHidetoshi Shimokawa if ((xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid, 4090892f4c5SHidetoshi Shimokawa PAGE_SIZE/*XXX*/)) == NULL) 4100892f4c5SHidetoshi Shimokawa return (ENOMEM); 4110892f4c5SHidetoshi Shimokawa 4120892f4c5SHidetoshi Shimokawa bcopy(&pkt, &xfer->send.hdr, sizeof(struct fw_pkt)); 4130892f4c5SHidetoshi Shimokawa xfer->send.pay_len = uio->uio_resid; 4140892f4c5SHidetoshi Shimokawa if (uio->uio_resid > 0) { 4150892f4c5SHidetoshi Shimokawa if ((err = uiomove((caddr_t)&xfer->send.payload[0], 41603cd51dfSRoman Divacky uio->uio_resid, uio))) 4170892f4c5SHidetoshi Shimokawa goto out; 4180892f4c5SHidetoshi Shimokawa } 4190892f4c5SHidetoshi Shimokawa 4200892f4c5SHidetoshi Shimokawa xfer->fc = d->fc; 4210892f4c5SHidetoshi Shimokawa xfer->sc = NULL; 4229950b741SHidetoshi Shimokawa xfer->hand = fw_xferwake; 4230892f4c5SHidetoshi Shimokawa xfer->send.spd = 2 /* XXX */; 4240892f4c5SHidetoshi Shimokawa 4250892f4c5SHidetoshi Shimokawa if ((err = fw_asyreq(xfer->fc, -1, xfer))) 4260892f4c5SHidetoshi Shimokawa goto out; 4270892f4c5SHidetoshi Shimokawa 4289950b741SHidetoshi Shimokawa if ((err = fw_xferwait(xfer))) 4290892f4c5SHidetoshi Shimokawa goto out; 4300892f4c5SHidetoshi Shimokawa 4310892f4c5SHidetoshi Shimokawa if (xfer->resp != 0) { 4320892f4c5SHidetoshi Shimokawa err = xfer->resp; 4330892f4c5SHidetoshi Shimokawa goto out; 4340892f4c5SHidetoshi Shimokawa } 4350892f4c5SHidetoshi Shimokawa 4369950b741SHidetoshi Shimokawa if (xfer->flag & FWXF_RCVD) { 4379950b741SHidetoshi Shimokawa FW_GLOCK(xfer->fc); 4380892f4c5SHidetoshi Shimokawa STAILQ_INSERT_TAIL(&d->rq, xfer, link); 4399950b741SHidetoshi Shimokawa FW_GUNLOCK(xfer->fc); 4400892f4c5SHidetoshi Shimokawa return (0); 4410892f4c5SHidetoshi Shimokawa } 4420892f4c5SHidetoshi Shimokawa 4430892f4c5SHidetoshi Shimokawa out: 4440892f4c5SHidetoshi Shimokawa fw_xfer_free(xfer); 4450892f4c5SHidetoshi Shimokawa return (err); 4460892f4c5SHidetoshi Shimokawa } 4470892f4c5SHidetoshi Shimokawa 4480892f4c5SHidetoshi Shimokawa static int 44989c9c53dSPoul-Henning Kamp fw_write(struct cdev *dev, struct uio *uio, int ioflag) 45017821895SHidetoshi Shimokawa { 45117821895SHidetoshi Shimokawa int err = 0; 45217821895SHidetoshi Shimokawa int s, slept = 0; 4530892f4c5SHidetoshi Shimokawa struct fw_drv1 *d; 45417821895SHidetoshi Shimokawa struct fw_pkt *fp; 45517821895SHidetoshi Shimokawa struct firewire_comm *fc; 45617821895SHidetoshi Shimokawa struct fw_xferq *it; 45717821895SHidetoshi Shimokawa 45817821895SHidetoshi Shimokawa if (DEV_FWMEM(dev)) 4599950b741SHidetoshi Shimokawa return (physio(dev, uio, ioflag)); 46017821895SHidetoshi Shimokawa 46123667f08SAlexander Kabaev d = dev->si_drv1; 4620892f4c5SHidetoshi Shimokawa fc = d->fc; 4630892f4c5SHidetoshi Shimokawa it = d->it; 4640892f4c5SHidetoshi Shimokawa 4650892f4c5SHidetoshi Shimokawa if (it == NULL) 4660892f4c5SHidetoshi Shimokawa return (fw_write_async(d, uio, ioflag)); 4670892f4c5SHidetoshi Shimokawa 4680892f4c5SHidetoshi Shimokawa if (it->buf == NULL) 4696cada79aSHidetoshi Shimokawa return (EIO); 4709950b741SHidetoshi Shimokawa 4719950b741SHidetoshi Shimokawa FW_GLOCK(fc); 47217821895SHidetoshi Shimokawa isoloop: 47317821895SHidetoshi Shimokawa if (it->stproc == NULL) { 47417821895SHidetoshi Shimokawa it->stproc = STAILQ_FIRST(&it->stfree); 47517821895SHidetoshi Shimokawa if (it->stproc != NULL) { 47617821895SHidetoshi Shimokawa s = splfw(); 47717821895SHidetoshi Shimokawa STAILQ_REMOVE_HEAD(&it->stfree, link); 47817821895SHidetoshi Shimokawa splx(s); 47917821895SHidetoshi Shimokawa it->queued = 0; 48017821895SHidetoshi Shimokawa } else if (slept == 0) { 48117821895SHidetoshi Shimokawa slept = 1; 4829950b741SHidetoshi Shimokawa #if 0 /* XXX to avoid lock recursion */ 4830892f4c5SHidetoshi Shimokawa err = fc->itx_enable(fc, it->dmach); 484c3e9e255SHidetoshi Shimokawa if (err) 4859950b741SHidetoshi Shimokawa goto out; 4869950b741SHidetoshi Shimokawa #endif 4879950b741SHidetoshi Shimokawa err = msleep(it, FW_GMTX(fc), FWPRI, "fw_write", hz); 488c3e9e255SHidetoshi Shimokawa if (err) 4899950b741SHidetoshi Shimokawa goto out; 49017821895SHidetoshi Shimokawa goto isoloop; 49117821895SHidetoshi Shimokawa } else { 49217821895SHidetoshi Shimokawa err = EIO; 4939950b741SHidetoshi Shimokawa goto out; 49417821895SHidetoshi Shimokawa } 49517821895SHidetoshi Shimokawa } 4969950b741SHidetoshi Shimokawa FW_GUNLOCK(fc); 49777ee030bSHidetoshi Shimokawa fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 49877ee030bSHidetoshi Shimokawa it->stproc->poffset + it->queued); 499c3e9e255SHidetoshi Shimokawa err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 500c3e9e255SHidetoshi Shimokawa err = uiomove((caddr_t)fp->mode.stream.payload, 50177ee030bSHidetoshi Shimokawa fp->mode.stream.len, uio); 50217821895SHidetoshi Shimokawa it->queued++; 503c3e9e255SHidetoshi Shimokawa if (it->queued >= it->bnpacket) { 50417821895SHidetoshi Shimokawa s = splfw(); 50517821895SHidetoshi Shimokawa STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 50617821895SHidetoshi Shimokawa splx(s); 50717821895SHidetoshi Shimokawa it->stproc = NULL; 5080892f4c5SHidetoshi Shimokawa err = fc->itx_enable(fc, it->dmach); 50917821895SHidetoshi Shimokawa } 510c3e9e255SHidetoshi Shimokawa if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 511c3e9e255SHidetoshi Shimokawa slept = 0; 5129950b741SHidetoshi Shimokawa FW_GLOCK(fc); 513c3e9e255SHidetoshi Shimokawa goto isoloop; 514c3e9e255SHidetoshi Shimokawa } 51517821895SHidetoshi Shimokawa return err; 5169950b741SHidetoshi Shimokawa 5179950b741SHidetoshi Shimokawa out: 5189950b741SHidetoshi Shimokawa FW_GUNLOCK(fc); 5199950b741SHidetoshi Shimokawa return err; 5209190691bSHidetoshi Shimokawa } 5210892f4c5SHidetoshi Shimokawa 5220892f4c5SHidetoshi Shimokawa static void 5230892f4c5SHidetoshi Shimokawa fw_hand(struct fw_xfer *xfer) 5240892f4c5SHidetoshi Shimokawa { 5250892f4c5SHidetoshi Shimokawa struct fw_bind *fwb; 5260892f4c5SHidetoshi Shimokawa struct fw_drv1 *d; 5270892f4c5SHidetoshi Shimokawa 5280892f4c5SHidetoshi Shimokawa fwb = (struct fw_bind *)xfer->sc; 52923667f08SAlexander Kabaev d = fwb->sc; 5309950b741SHidetoshi Shimokawa FW_GLOCK(xfer->fc); 5310892f4c5SHidetoshi Shimokawa STAILQ_INSERT_TAIL(&d->rq, xfer, link); 5329950b741SHidetoshi Shimokawa FW_GUNLOCK(xfer->fc); 5330892f4c5SHidetoshi Shimokawa wakeup(&d->rq); 5340892f4c5SHidetoshi Shimokawa } 5350892f4c5SHidetoshi Shimokawa 53617821895SHidetoshi Shimokawa /* 53717821895SHidetoshi Shimokawa * ioctl support. 53817821895SHidetoshi Shimokawa */ 53917821895SHidetoshi Shimokawa int 54089c9c53dSPoul-Henning Kamp fw_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 54117821895SHidetoshi Shimokawa { 5426cada79aSHidetoshi Shimokawa struct firewire_comm *fc; 5436cada79aSHidetoshi Shimokawa struct fw_drv1 *d; 5440892f4c5SHidetoshi Shimokawa int i, len, err = 0; 54517821895SHidetoshi Shimokawa struct fw_device *fwdev; 54617821895SHidetoshi Shimokawa struct fw_bind *fwb; 54717821895SHidetoshi Shimokawa struct fw_xferq *ir, *it; 54817821895SHidetoshi Shimokawa struct fw_xfer *xfer; 54917821895SHidetoshi Shimokawa struct fw_pkt *fp; 550c547b896SHidetoshi Shimokawa struct fw_devinfo *devinfo; 551d7e486b4SHidetoshi Shimokawa void *ptr; 55217821895SHidetoshi Shimokawa 55317821895SHidetoshi Shimokawa struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 55417821895SHidetoshi Shimokawa struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 55517821895SHidetoshi Shimokawa struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 55617821895SHidetoshi Shimokawa struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 55717821895SHidetoshi Shimokawa struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 55817821895SHidetoshi Shimokawa struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 55917821895SHidetoshi Shimokawa 56017821895SHidetoshi Shimokawa if (DEV_FWMEM(dev)) 56117821895SHidetoshi Shimokawa return fwmem_ioctl(dev, cmd, data, flag, td); 56217821895SHidetoshi Shimokawa 56317821895SHidetoshi Shimokawa if (!data) 56417821895SHidetoshi Shimokawa return (EINVAL); 56517821895SHidetoshi Shimokawa 56623667f08SAlexander Kabaev d = dev->si_drv1; 5670892f4c5SHidetoshi Shimokawa fc = d->fc; 5686cada79aSHidetoshi Shimokawa ir = d->ir; 5696cada79aSHidetoshi Shimokawa it = d->it; 5706cada79aSHidetoshi Shimokawa 57117821895SHidetoshi Shimokawa switch (cmd) { 57217821895SHidetoshi Shimokawa case FW_STSTREAM: 5736cada79aSHidetoshi Shimokawa if (it == NULL) { 5749950b741SHidetoshi Shimokawa i = fw_open_isodma(fc, /* tx */1); 5759950b741SHidetoshi Shimokawa if (i < 0) { 5766cada79aSHidetoshi Shimokawa err = EBUSY; 5776cada79aSHidetoshi Shimokawa break; 5786cada79aSHidetoshi Shimokawa } 5799950b741SHidetoshi Shimokawa it = fc->it[i]; 5806cada79aSHidetoshi Shimokawa err = fwdev_allocbuf(fc, it, &d->bufreq.tx); 5819950b741SHidetoshi Shimokawa if (err) { 5829950b741SHidetoshi Shimokawa it->flag &= ~FWXFERQ_OPEN; 5836cada79aSHidetoshi Shimokawa break; 5849950b741SHidetoshi Shimokawa } 5856cada79aSHidetoshi Shimokawa } 5866cada79aSHidetoshi Shimokawa it->flag &= ~0xff; 5876cada79aSHidetoshi Shimokawa it->flag |= (0x3f & ichreq->ch); 5886cada79aSHidetoshi Shimokawa it->flag |= ((0x3 & ichreq->tag) << 6); 5896cada79aSHidetoshi Shimokawa d->it = it; 59017821895SHidetoshi Shimokawa break; 59117821895SHidetoshi Shimokawa case FW_GTSTREAM: 5926cada79aSHidetoshi Shimokawa if (it != NULL) { 5936cada79aSHidetoshi Shimokawa ichreq->ch = it->flag & 0x3f; 5946cada79aSHidetoshi Shimokawa ichreq->tag = it->flag >> 2 & 0x3; 5956cada79aSHidetoshi Shimokawa } else 5966cada79aSHidetoshi Shimokawa err = EINVAL; 59717821895SHidetoshi Shimokawa break; 59817821895SHidetoshi Shimokawa case FW_SRSTREAM: 5996cada79aSHidetoshi Shimokawa if (ir == NULL) { 6009950b741SHidetoshi Shimokawa i = fw_open_isodma(fc, /* tx */0); 6019950b741SHidetoshi Shimokawa if (i < 0) { 6026cada79aSHidetoshi Shimokawa err = EBUSY; 6036cada79aSHidetoshi Shimokawa break; 6046cada79aSHidetoshi Shimokawa } 6059950b741SHidetoshi Shimokawa ir = fc->ir[i]; 6066cada79aSHidetoshi Shimokawa err = fwdev_allocbuf(fc, ir, &d->bufreq.rx); 6079950b741SHidetoshi Shimokawa if (err) { 6089950b741SHidetoshi Shimokawa ir->flag &= ~FWXFERQ_OPEN; 6096cada79aSHidetoshi Shimokawa break; 6109950b741SHidetoshi Shimokawa } 6116cada79aSHidetoshi Shimokawa } 6126cada79aSHidetoshi Shimokawa ir->flag &= ~0xff; 6136cada79aSHidetoshi Shimokawa ir->flag |= (0x3f & ichreq->ch); 6146cada79aSHidetoshi Shimokawa ir->flag |= ((0x3 & ichreq->tag) << 6); 6156cada79aSHidetoshi Shimokawa d->ir = ir; 6166cada79aSHidetoshi Shimokawa err = fc->irx_enable(fc, ir->dmach); 61717821895SHidetoshi Shimokawa break; 61817821895SHidetoshi Shimokawa case FW_GRSTREAM: 6196cada79aSHidetoshi Shimokawa if (d->ir != NULL) { 6206cada79aSHidetoshi Shimokawa ichreq->ch = ir->flag & 0x3f; 6216cada79aSHidetoshi Shimokawa ichreq->tag = ir->flag >> 2 & 0x3; 6226cada79aSHidetoshi Shimokawa } else 6236cada79aSHidetoshi Shimokawa err = EINVAL; 62417821895SHidetoshi Shimokawa break; 62517821895SHidetoshi Shimokawa case FW_SSTBUF: 6266cada79aSHidetoshi Shimokawa bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq)); 62717821895SHidetoshi Shimokawa break; 62817821895SHidetoshi Shimokawa case FW_GSTBUF: 6296cada79aSHidetoshi Shimokawa bzero(&ibufreq->rx, sizeof(ibufreq->rx)); 6306cada79aSHidetoshi Shimokawa if (ir != NULL) { 6316cada79aSHidetoshi Shimokawa ibufreq->rx.nchunk = ir->bnchunk; 6326cada79aSHidetoshi Shimokawa ibufreq->rx.npacket = ir->bnpacket; 6336cada79aSHidetoshi Shimokawa ibufreq->rx.psize = ir->psize; 6346cada79aSHidetoshi Shimokawa } 6356cada79aSHidetoshi Shimokawa bzero(&ibufreq->tx, sizeof(ibufreq->tx)); 6366cada79aSHidetoshi Shimokawa if (it != NULL) { 6376cada79aSHidetoshi Shimokawa ibufreq->tx.nchunk = it->bnchunk; 6386cada79aSHidetoshi Shimokawa ibufreq->tx.npacket = it->bnpacket; 6396cada79aSHidetoshi Shimokawa ibufreq->tx.psize = it->psize; 6406cada79aSHidetoshi Shimokawa } 64117821895SHidetoshi Shimokawa break; 64217821895SHidetoshi Shimokawa case FW_ASYREQ: 643c4778b5dSHidetoshi Shimokawa { 644c4778b5dSHidetoshi Shimokawa struct tcode_info *tinfo; 645102ebc1fSHidetoshi Shimokawa int pay_len = 0; 646c4778b5dSHidetoshi Shimokawa 64717821895SHidetoshi Shimokawa fp = &asyreq->pkt; 6480892f4c5SHidetoshi Shimokawa tinfo = &fc->tcode[fp->mode.hdr.tcode]; 649102ebc1fSHidetoshi Shimokawa 650102ebc1fSHidetoshi Shimokawa if ((tinfo->flag & FWTI_BLOCK_ASY) != 0) 651102ebc1fSHidetoshi Shimokawa pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len); 652102ebc1fSHidetoshi Shimokawa 653102ebc1fSHidetoshi Shimokawa xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/); 654102ebc1fSHidetoshi Shimokawa if (xfer == NULL) 655102ebc1fSHidetoshi Shimokawa return (ENOMEM); 656102ebc1fSHidetoshi Shimokawa 65717821895SHidetoshi Shimokawa switch (asyreq->req.type) { 65817821895SHidetoshi Shimokawa case FWASREQNODE: 65917821895SHidetoshi Shimokawa break; 66017821895SHidetoshi Shimokawa case FWASREQEUI: 6610892f4c5SHidetoshi Shimokawa fwdev = fw_noderesolve_eui64(fc, 662233b1b97SHidetoshi Shimokawa &asyreq->req.dst.eui); 66317821895SHidetoshi Shimokawa if (fwdev == NULL) { 6640892f4c5SHidetoshi Shimokawa device_printf(fc->bdev, 66517faeefcSHidetoshi Shimokawa "cannot find node\n"); 66617821895SHidetoshi Shimokawa err = EINVAL; 667102ebc1fSHidetoshi Shimokawa goto out; 66817821895SHidetoshi Shimokawa } 669c4778b5dSHidetoshi Shimokawa fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst; 67017821895SHidetoshi Shimokawa break; 67117821895SHidetoshi Shimokawa case FWASRESTL: 67217821895SHidetoshi Shimokawa /* XXX what's this? */ 67317821895SHidetoshi Shimokawa break; 67417821895SHidetoshi Shimokawa case FWASREQSTREAM: 67517821895SHidetoshi Shimokawa /* nothing to do */ 67617821895SHidetoshi Shimokawa break; 67717821895SHidetoshi Shimokawa } 678102ebc1fSHidetoshi Shimokawa 679c4778b5dSHidetoshi Shimokawa bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len); 680102ebc1fSHidetoshi Shimokawa if (pay_len > 0) 681c4778b5dSHidetoshi Shimokawa bcopy((char *)fp + tinfo->hdr_len, 68223667f08SAlexander Kabaev xfer->send.payload, pay_len); 683102ebc1fSHidetoshi Shimokawa xfer->send.spd = asyreq->req.sped; 6849950b741SHidetoshi Shimokawa xfer->hand = fw_xferwake; 685102ebc1fSHidetoshi Shimokawa 6860892f4c5SHidetoshi Shimokawa if ((err = fw_asyreq(fc, -1, xfer)) != 0) 687102ebc1fSHidetoshi Shimokawa goto out; 6889950b741SHidetoshi Shimokawa if ((err = fw_xferwait(xfer)) != 0) 689102ebc1fSHidetoshi Shimokawa goto out; 690c4778b5dSHidetoshi Shimokawa if (xfer->resp != 0) { 691c4778b5dSHidetoshi Shimokawa err = EIO; 692102ebc1fSHidetoshi Shimokawa goto out; 693c4778b5dSHidetoshi Shimokawa } 694102ebc1fSHidetoshi Shimokawa if ((tinfo->flag & FWTI_TLABEL) == 0) 695102ebc1fSHidetoshi Shimokawa goto out; 696102ebc1fSHidetoshi Shimokawa 697102ebc1fSHidetoshi Shimokawa /* copy response */ 6980892f4c5SHidetoshi Shimokawa tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode]; 6997b1f6286SDoug Rabson if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB || 7007b1f6286SDoug Rabson xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) { 7017b1f6286SDoug Rabson pay_len = xfer->recv.pay_len; 7027b1f6286SDoug Rabson if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) { 7037b1f6286SDoug Rabson asyreq->req.len = xfer->recv.pay_len + 7047b1f6286SDoug Rabson tinfo->hdr_len; 7057b1f6286SDoug Rabson } else { 70617821895SHidetoshi Shimokawa err = EINVAL; 7077b1f6286SDoug Rabson pay_len = 0; 7087b1f6286SDoug Rabson } 7097b1f6286SDoug Rabson } else { 7107b1f6286SDoug Rabson pay_len = 0; 7117b1f6286SDoug Rabson } 712c4778b5dSHidetoshi Shimokawa bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len); 7137b1f6286SDoug Rabson bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, pay_len); 714102ebc1fSHidetoshi Shimokawa out: 715c4778b5dSHidetoshi Shimokawa fw_xfer_free_buf(xfer); 71617821895SHidetoshi Shimokawa break; 717c4778b5dSHidetoshi Shimokawa } 71817821895SHidetoshi Shimokawa case FW_IBUSRST: 7190892f4c5SHidetoshi Shimokawa fc->ibr(fc); 72017821895SHidetoshi Shimokawa break; 72117821895SHidetoshi Shimokawa case FW_CBINDADDR: 7220892f4c5SHidetoshi Shimokawa fwb = fw_bindlookup(fc, 72317821895SHidetoshi Shimokawa bindreq->start.hi, bindreq->start.lo); 72417821895SHidetoshi Shimokawa if (fwb == NULL) { 72517821895SHidetoshi Shimokawa err = EINVAL; 72617821895SHidetoshi Shimokawa break; 72717821895SHidetoshi Shimokawa } 7280892f4c5SHidetoshi Shimokawa fw_bindremove(fc, fwb); 7290892f4c5SHidetoshi Shimokawa STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist); 7300892f4c5SHidetoshi Shimokawa fw_xferlist_remove(&fwb->xferlist); 7315166f1dfSHidetoshi Shimokawa free(fwb, M_FW); 73217821895SHidetoshi Shimokawa break; 73317821895SHidetoshi Shimokawa case FW_SBINDADDR: 73417821895SHidetoshi Shimokawa if (bindreq->len <= 0) { 73517821895SHidetoshi Shimokawa err = EINVAL; 73617821895SHidetoshi Shimokawa break; 73717821895SHidetoshi Shimokawa } 73817821895SHidetoshi Shimokawa if (bindreq->start.hi > 0xffff) { 73917821895SHidetoshi Shimokawa err = EINVAL; 74017821895SHidetoshi Shimokawa break; 74117821895SHidetoshi Shimokawa } 74223667f08SAlexander Kabaev fwb = malloc(sizeof(struct fw_bind), M_FW, M_WAITOK); 743c4778b5dSHidetoshi Shimokawa fwb->start = ((u_int64_t)bindreq->start.hi << 32) | 744c4778b5dSHidetoshi Shimokawa bindreq->start.lo; 745c4778b5dSHidetoshi Shimokawa fwb->end = fwb->start + bindreq->len; 74623667f08SAlexander Kabaev fwb->sc = d; 74777ee030bSHidetoshi Shimokawa STAILQ_INIT(&fwb->xferlist); 7480892f4c5SHidetoshi Shimokawa err = fw_bindadd(fc, fwb); 7490892f4c5SHidetoshi Shimokawa if (err == 0) { 7500892f4c5SHidetoshi Shimokawa fw_xferlist_add(&fwb->xferlist, M_FWXFER, 7510892f4c5SHidetoshi Shimokawa /* XXX */ 7520892f4c5SHidetoshi Shimokawa PAGE_SIZE, PAGE_SIZE, 5, 75323667f08SAlexander Kabaev fc, fwb, fw_hand); 7540892f4c5SHidetoshi Shimokawa STAILQ_INSERT_TAIL(&d->binds, fwb, chlist); 7550892f4c5SHidetoshi Shimokawa } 75617821895SHidetoshi Shimokawa break; 75717821895SHidetoshi Shimokawa case FW_GDEVLST: 758c547b896SHidetoshi Shimokawa i = len = 1; 759c547b896SHidetoshi Shimokawa /* myself */ 760c547b896SHidetoshi Shimokawa devinfo = &fwdevlst->dev[0]; 7610892f4c5SHidetoshi Shimokawa devinfo->dst = fc->nodeid; 762c547b896SHidetoshi Shimokawa devinfo->status = 0; /* XXX */ 7630892f4c5SHidetoshi Shimokawa devinfo->eui.hi = fc->eui.hi; 7640892f4c5SHidetoshi Shimokawa devinfo->eui.lo = fc->eui.lo; 7650892f4c5SHidetoshi Shimokawa STAILQ_FOREACH(fwdev, &fc->devices, link) { 766c547b896SHidetoshi Shimokawa if (len < FW_MAX_DEVLST) { 767c547b896SHidetoshi Shimokawa devinfo = &fwdevlst->dev[len++]; 768c547b896SHidetoshi Shimokawa devinfo->dst = fwdev->dst; 769c547b896SHidetoshi Shimokawa devinfo->status = 770c547b896SHidetoshi Shimokawa (fwdev->status == FWDEVINVAL) ? 0 : 1; 771c547b896SHidetoshi Shimokawa devinfo->eui.hi = fwdev->eui.hi; 772c547b896SHidetoshi Shimokawa devinfo->eui.lo = fwdev->eui.lo; 77317821895SHidetoshi Shimokawa } 77417821895SHidetoshi Shimokawa i++; 77517821895SHidetoshi Shimokawa } 77617821895SHidetoshi Shimokawa fwdevlst->n = i; 777c547b896SHidetoshi Shimokawa fwdevlst->info_len = len; 77817821895SHidetoshi Shimokawa break; 77917821895SHidetoshi Shimokawa case FW_GTPMAP: 7800892f4c5SHidetoshi Shimokawa bcopy(fc->topology_map, data, 7810892f4c5SHidetoshi Shimokawa (fc->topology_map->crc_len + 1) * 4); 78217821895SHidetoshi Shimokawa break; 78317821895SHidetoshi Shimokawa case FW_GCROM: 7840892f4c5SHidetoshi Shimokawa STAILQ_FOREACH(fwdev, &fc->devices, link) 7850981f5f0SHidetoshi Shimokawa if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 78617821895SHidetoshi Shimokawa break; 78717821895SHidetoshi Shimokawa if (fwdev == NULL) { 7880892f4c5SHidetoshi Shimokawa if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) { 78917821895SHidetoshi Shimokawa err = FWNODE_INVAL; 79017821895SHidetoshi Shimokawa break; 79117821895SHidetoshi Shimokawa } 792d7e486b4SHidetoshi Shimokawa /* myself */ 793d7e486b4SHidetoshi Shimokawa ptr = malloc(CROMSIZE, M_FW, M_WAITOK); 794d7e486b4SHidetoshi Shimokawa len = CROMSIZE; 795d7e486b4SHidetoshi Shimokawa for (i = 0; i < CROMSIZE/4; i++) 79603161bbcSDoug Rabson ((uint32_t *)ptr)[i] 7970892f4c5SHidetoshi Shimokawa = ntohl(fc->config_rom[i]); 798d7e486b4SHidetoshi Shimokawa } else { 799d7e486b4SHidetoshi Shimokawa /* found */ 800d7e486b4SHidetoshi Shimokawa ptr = (void *)&fwdev->csrrom[0]; 80117821895SHidetoshi Shimokawa if (fwdev->rommax < CSRROMOFF) 80217821895SHidetoshi Shimokawa len = 0; 80317821895SHidetoshi Shimokawa else 80417821895SHidetoshi Shimokawa len = fwdev->rommax - CSRROMOFF + 4; 805d7e486b4SHidetoshi Shimokawa } 806e340a7acSHidetoshi Shimokawa if (crom_buf->len < len) 80717821895SHidetoshi Shimokawa len = crom_buf->len; 80817821895SHidetoshi Shimokawa else 80917821895SHidetoshi Shimokawa crom_buf->len = len; 810d7e486b4SHidetoshi Shimokawa err = copyout(ptr, crom_buf->ptr, len); 811d7e486b4SHidetoshi Shimokawa if (fwdev == NULL) 812d7e486b4SHidetoshi Shimokawa /* myself */ 813d7e486b4SHidetoshi Shimokawa free(ptr, M_FW); 81417821895SHidetoshi Shimokawa break; 81517821895SHidetoshi Shimokawa default: 8160892f4c5SHidetoshi Shimokawa fc->ioctl(dev, cmd, data, flag, td); 81717821895SHidetoshi Shimokawa break; 81817821895SHidetoshi Shimokawa } 81917821895SHidetoshi Shimokawa return err; 82017821895SHidetoshi Shimokawa } 82117821895SHidetoshi Shimokawa int 82289c9c53dSPoul-Henning Kamp fw_poll(struct cdev *dev, int events, fw_proc *td) 82317821895SHidetoshi Shimokawa { 8246cada79aSHidetoshi Shimokawa struct fw_xferq *ir; 82517821895SHidetoshi Shimokawa int revents; 82617821895SHidetoshi Shimokawa int tmp; 82717821895SHidetoshi Shimokawa 82817821895SHidetoshi Shimokawa if (DEV_FWMEM(dev)) 82917821895SHidetoshi Shimokawa return fwmem_poll(dev, events, td); 83017821895SHidetoshi Shimokawa 8316cada79aSHidetoshi Shimokawa ir = ((struct fw_drv1 *)dev->si_drv1)->ir; 83217821895SHidetoshi Shimokawa revents = 0; 83317821895SHidetoshi Shimokawa tmp = POLLIN | POLLRDNORM; 83417821895SHidetoshi Shimokawa if (events & tmp) { 8356cada79aSHidetoshi Shimokawa if (STAILQ_FIRST(&ir->q) != NULL) 83617821895SHidetoshi Shimokawa revents |= tmp; 83717821895SHidetoshi Shimokawa else 8386cada79aSHidetoshi Shimokawa selrecord(td, &ir->rsel); 83917821895SHidetoshi Shimokawa } 84017821895SHidetoshi Shimokawa tmp = POLLOUT | POLLWRNORM; 84117821895SHidetoshi Shimokawa if (events & tmp) { 84217821895SHidetoshi Shimokawa /* XXX should be fixed */ 84317821895SHidetoshi Shimokawa revents |= tmp; 84417821895SHidetoshi Shimokawa } 84517821895SHidetoshi Shimokawa 84617821895SHidetoshi Shimokawa return revents; 84717821895SHidetoshi Shimokawa } 84817821895SHidetoshi Shimokawa 84917821895SHidetoshi Shimokawa static int 850cfd7baceSRobert Noland fw_mmap (struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, 851cfd7baceSRobert Noland int nproto, vm_memattr_t *memattr) 85217821895SHidetoshi Shimokawa { 85317821895SHidetoshi Shimokawa 85417821895SHidetoshi Shimokawa if (DEV_FWMEM(dev)) 855cfd7baceSRobert Noland return fwmem_mmap(dev, offset, paddr, nproto, memattr); 85617821895SHidetoshi Shimokawa 85717821895SHidetoshi Shimokawa return EINVAL; 85817821895SHidetoshi Shimokawa } 859a160e00eSHidetoshi Shimokawa 860c4778b5dSHidetoshi Shimokawa static void 861c4778b5dSHidetoshi Shimokawa fw_strategy(struct bio *bp) 862c4778b5dSHidetoshi Shimokawa { 86389c9c53dSPoul-Henning Kamp struct cdev *dev; 864c4778b5dSHidetoshi Shimokawa 865c4778b5dSHidetoshi Shimokawa dev = bp->bio_dev; 866c4778b5dSHidetoshi Shimokawa if (DEV_FWMEM(dev)) { 867c4778b5dSHidetoshi Shimokawa fwmem_strategy(bp); 868c4778b5dSHidetoshi Shimokawa return; 869c4778b5dSHidetoshi Shimokawa } 870c4778b5dSHidetoshi Shimokawa 871c4778b5dSHidetoshi Shimokawa bp->bio_error = EOPNOTSUPP; 872c4778b5dSHidetoshi Shimokawa bp->bio_flags |= BIO_ERROR; 873c4778b5dSHidetoshi Shimokawa bp->bio_resid = bp->bio_bcount; 874c4778b5dSHidetoshi Shimokawa biodone(bp); 875c4778b5dSHidetoshi Shimokawa } 876c4778b5dSHidetoshi Shimokawa 877a160e00eSHidetoshi Shimokawa int 878a160e00eSHidetoshi Shimokawa fwdev_makedev(struct firewire_softc *sc) 879a160e00eSHidetoshi Shimokawa { 880a160e00eSHidetoshi Shimokawa int err = 0; 881a160e00eSHidetoshi Shimokawa 88289c9c53dSPoul-Henning Kamp struct cdev *d; 883a160e00eSHidetoshi Shimokawa int unit; 884a160e00eSHidetoshi Shimokawa 885a160e00eSHidetoshi Shimokawa unit = device_get_unit(sc->fc->bdev); 886a160e00eSHidetoshi Shimokawa sc->dev = make_dev(&firewire_cdevsw, MAKEMINOR(0, unit, 0), 88723667f08SAlexander Kabaev UID_ROOT, GID_OPERATOR, 0660, "fw%d.%d", unit, 0); 88823667f08SAlexander Kabaev d = make_dev(&firewire_cdevsw, MAKEMINOR(FWMEM_FLAG, unit, 0), 88923667f08SAlexander Kabaev UID_ROOT, GID_OPERATOR, 0660, "fwmem%d.%d", unit, 0); 890a160e00eSHidetoshi Shimokawa dev_depends(sc->dev, d); 891a160e00eSHidetoshi Shimokawa make_dev_alias(sc->dev, "fw%d", unit); 892a160e00eSHidetoshi Shimokawa make_dev_alias(d, "fwmem%d", unit); 893a160e00eSHidetoshi Shimokawa 894a160e00eSHidetoshi Shimokawa return (err); 895a160e00eSHidetoshi Shimokawa } 896a160e00eSHidetoshi Shimokawa 897a160e00eSHidetoshi Shimokawa int 898a160e00eSHidetoshi Shimokawa fwdev_destroydev(struct firewire_softc *sc) 899a160e00eSHidetoshi Shimokawa { 900a160e00eSHidetoshi Shimokawa int err = 0; 901a160e00eSHidetoshi Shimokawa 90210d3ed64SHidetoshi Shimokawa destroy_dev(sc->dev); 903a160e00eSHidetoshi Shimokawa return (err); 904a160e00eSHidetoshi Shimokawa } 905a160e00eSHidetoshi Shimokawa 906a160e00eSHidetoshi Shimokawa #define NDEVTYPE 2 907a160e00eSHidetoshi Shimokawa void 9086a113b3dSRobert Watson fwdev_clone(void *arg, struct ucred *cred, char *name, int namelen, 9096a113b3dSRobert Watson struct cdev **dev) 910a160e00eSHidetoshi Shimokawa { 911a160e00eSHidetoshi Shimokawa struct firewire_softc *sc; 912a160e00eSHidetoshi Shimokawa char *devnames[NDEVTYPE] = {"fw", "fwmem"}; 913a160e00eSHidetoshi Shimokawa char *subp = NULL; 914a160e00eSHidetoshi Shimokawa int devflag[NDEVTYPE] = {0, FWMEM_FLAG}; 915a160e00eSHidetoshi Shimokawa int i, unit = 0, sub = 0; 916a160e00eSHidetoshi Shimokawa 917f3732fd1SPoul-Henning Kamp if (*dev != NULL) 918a160e00eSHidetoshi Shimokawa return; 919a160e00eSHidetoshi Shimokawa 920a160e00eSHidetoshi Shimokawa for (i = 0; i < NDEVTYPE; i++) 921c727011aSHidetoshi Shimokawa if (dev_stdclone(name, &subp, devnames[i], &unit) == 2) 922a160e00eSHidetoshi Shimokawa goto found; 923a160e00eSHidetoshi Shimokawa /* not match */ 924a160e00eSHidetoshi Shimokawa return; 925a160e00eSHidetoshi Shimokawa found: 926a160e00eSHidetoshi Shimokawa 927a160e00eSHidetoshi Shimokawa if (subp == NULL || *subp++ != '.') 928a160e00eSHidetoshi Shimokawa return; 929a160e00eSHidetoshi Shimokawa 930a160e00eSHidetoshi Shimokawa /* /dev/fwU.S */ 931a160e00eSHidetoshi Shimokawa while (isdigit(*subp)) { 932a160e00eSHidetoshi Shimokawa sub *= 10; 933a160e00eSHidetoshi Shimokawa sub += *subp++ - '0'; 934a160e00eSHidetoshi Shimokawa } 935a160e00eSHidetoshi Shimokawa if (*subp != '\0') 936a160e00eSHidetoshi Shimokawa return; 937a160e00eSHidetoshi Shimokawa 938a160e00eSHidetoshi Shimokawa sc = devclass_get_softc(firewire_devclass, unit); 939a160e00eSHidetoshi Shimokawa if (sc == NULL) 940a160e00eSHidetoshi Shimokawa return; 941d56b4cd4SDavide Italiano *dev = make_dev_credf(MAKEDEV_REF, &firewire_cdevsw, 942d56b4cd4SDavide Italiano MAKEMINOR(devflag[i], unit, sub), cred, UID_ROOT, GID_OPERATOR, 943d56b4cd4SDavide Italiano 0660, "%s%d.%d", devnames[i], unit, sub); 944a160e00eSHidetoshi Shimokawa dev_depends(sc->dev, *dev); 945a160e00eSHidetoshi Shimokawa return; 946a160e00eSHidetoshi Shimokawa } 947