fwdev.c revision 255359
1139749Simp/*- 2113584Ssimokawa * Copyright (c) 2003 Hidetoshi Shimokawa 3106813Ssimokawa * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 4106813Ssimokawa * All rights reserved. 5106813Ssimokawa * 6106813Ssimokawa * Redistribution and use in source and binary forms, with or without 7106813Ssimokawa * modification, are permitted provided that the following conditions 8106813Ssimokawa * are met: 9106813Ssimokawa * 1. Redistributions of source code must retain the above copyright 10106813Ssimokawa * notice, this list of conditions and the following disclaimer. 11106813Ssimokawa * 2. Redistributions in binary form must reproduce the above copyright 12106813Ssimokawa * notice, this list of conditions and the following disclaimer in the 13106813Ssimokawa * documentation and/or other materials provided with the distribution. 14106813Ssimokawa * 3. All advertising materials mentioning features or use of this software 15106813Ssimokawa * must display the acknowledgement as bellow: 16106813Ssimokawa * 17106813Ssimokawa * This product includes software developed by K. Kobayashi and H. Shimokawa 18106813Ssimokawa * 19106813Ssimokawa * 4. The name of the author may not be used to endorse or promote products 20106813Ssimokawa * derived from this software without specific prior written permission. 21106813Ssimokawa * 22106813Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23106813Ssimokawa * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24106813Ssimokawa * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25106813Ssimokawa * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 26106813Ssimokawa * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27106813Ssimokawa * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28106813Ssimokawa * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29106813Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 30106813Ssimokawa * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31106813Ssimokawa * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32106813Ssimokawa * POSSIBILITY OF SUCH DAMAGE. 33106813Ssimokawa * 34106813Ssimokawa * $FreeBSD: head/sys/dev/firewire/fwdev.c 255359 2013-09-07 13:45:44Z davide $ 35106813Ssimokawa * 36106813Ssimokawa */ 37106813Ssimokawa 38106813Ssimokawa#include <sys/param.h> 39106813Ssimokawa#include <sys/systm.h> 40106813Ssimokawa#include <sys/types.h> 41106813Ssimokawa#include <sys/mbuf.h> 42127468Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500000 43120660Ssimokawa#include <sys/buf.h> 44120660Ssimokawa#else 45120660Ssimokawa#include <sys/bio.h> 46120660Ssimokawa#endif 47106813Ssimokawa 48106813Ssimokawa#include <sys/kernel.h> 49106813Ssimokawa#include <sys/malloc.h> 50106813Ssimokawa#include <sys/conf.h> 51106813Ssimokawa#include <sys/poll.h> 52106813Ssimokawa 53106813Ssimokawa#include <sys/bus.h> 54118455Ssimokawa#include <sys/ctype.h> 55113584Ssimokawa#include <machine/bus.h> 56106813Ssimokawa 57106813Ssimokawa#include <sys/ioccom.h> 58106813Ssimokawa 59127468Ssimokawa#ifdef __DragonFly__ 60127468Ssimokawa#include "firewire.h" 61127468Ssimokawa#include "firewirereg.h" 62127468Ssimokawa#include "fwdma.h" 63127468Ssimokawa#include "fwmem.h" 64127468Ssimokawa#include "iec68113.h" 65127468Ssimokawa#else 66106813Ssimokawa#include <dev/firewire/firewire.h> 67106813Ssimokawa#include <dev/firewire/firewirereg.h> 68113584Ssimokawa#include <dev/firewire/fwdma.h> 69106813Ssimokawa#include <dev/firewire/fwmem.h> 70109282Ssimokawa#include <dev/firewire/iec68113.h> 71127468Ssimokawa#endif 72106813Ssimokawa 73106813Ssimokawa#define FWNODE_INVAL 0xffff 74106813Ssimokawa 75106813Ssimokawastatic d_open_t fw_open; 76106813Ssimokawastatic d_close_t fw_close; 77106813Ssimokawastatic d_ioctl_t fw_ioctl; 78106813Ssimokawastatic d_poll_t fw_poll; 79106813Ssimokawastatic d_read_t fw_read; /* for Isochronous packet */ 80106813Ssimokawastatic d_write_t fw_write; 81106813Ssimokawastatic d_mmap_t fw_mmap; 82120660Ssimokawastatic d_strategy_t fw_strategy; 83106813Ssimokawa 84126080Sphkstruct cdevsw firewire_cdevsw = { 85127468Ssimokawa#ifdef __DragonFly__ 86127468Ssimokawa#define CDEV_MAJOR 127 87127468Ssimokawa "fw", CDEV_MAJOR, D_MEM, NULL, 0, 88127468Ssimokawa fw_open, fw_close, fw_read, fw_write, fw_ioctl, 89127468Ssimokawa fw_poll, fw_mmap, fw_strategy, nodump, nopsize, 90127468Ssimokawa#elif __FreeBSD_version >= 500104 91126080Sphk .d_version = D_VERSION, 92111815Sphk .d_open = fw_open, 93111815Sphk .d_close = fw_close, 94111815Sphk .d_read = fw_read, 95111815Sphk .d_write = fw_write, 96111815Sphk .d_ioctl = fw_ioctl, 97111815Sphk .d_poll = fw_poll, 98111815Sphk .d_mmap = fw_mmap, 99120660Ssimokawa .d_strategy = fw_strategy, 100111815Sphk .d_name = "fw", 101170374Ssimokawa .d_flags = D_MEM 102111942Ssimokawa#else 103127468Ssimokawa#define CDEV_MAJOR 127 104111942Ssimokawa fw_open, fw_close, fw_read, fw_write, fw_ioctl, 105120660Ssimokawa fw_poll, fw_mmap, fw_strategy, "fw", CDEV_MAJOR, 106118455Ssimokawa nodump, nopsize, D_MEM, -1 107111942Ssimokawa#endif 108106813Ssimokawa}; 109106813Ssimokawa 110118293Ssimokawastruct fw_drv1 { 111169130Ssimokawa struct firewire_comm *fc; 112118293Ssimokawa struct fw_xferq *ir; 113118293Ssimokawa struct fw_xferq *it; 114118293Ssimokawa struct fw_isobufreq bufreq; 115169130Ssimokawa STAILQ_HEAD(, fw_bind) binds; 116169130Ssimokawa STAILQ_HEAD(, fw_xfer) rq; 117118293Ssimokawa}; 118118293Ssimokawa 119106813Ssimokawastatic int 120118293Ssimokawafwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q, 121118293Ssimokawa struct fw_bufspec *b) 122118293Ssimokawa{ 123118293Ssimokawa int i; 124118293Ssimokawa 125118293Ssimokawa if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF)) 126118293Ssimokawa return(EBUSY); 127118293Ssimokawa 128118293Ssimokawa q->bulkxfer = (struct fw_bulkxfer *) malloc( 129118293Ssimokawa sizeof(struct fw_bulkxfer) * b->nchunk, 130118293Ssimokawa M_FW, M_WAITOK); 131118293Ssimokawa if (q->bulkxfer == NULL) 132118293Ssimokawa return(ENOMEM); 133118293Ssimokawa 134129585Sdfr b->psize = roundup2(b->psize, sizeof(uint32_t)); 135129585Sdfr q->buf = fwdma_malloc_multiseg(fc, sizeof(uint32_t), 136118293Ssimokawa b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK); 137118293Ssimokawa 138118293Ssimokawa if (q->buf == NULL) { 139118293Ssimokawa free(q->bulkxfer, M_FW); 140118293Ssimokawa q->bulkxfer = NULL; 141118293Ssimokawa return(ENOMEM); 142118293Ssimokawa } 143118293Ssimokawa q->bnchunk = b->nchunk; 144118293Ssimokawa q->bnpacket = b->npacket; 145118293Ssimokawa q->psize = (b->psize + 3) & ~3; 146118293Ssimokawa q->queued = 0; 147118293Ssimokawa 148118293Ssimokawa STAILQ_INIT(&q->stvalid); 149118293Ssimokawa STAILQ_INIT(&q->stfree); 150118293Ssimokawa STAILQ_INIT(&q->stdma); 151118293Ssimokawa q->stproc = NULL; 152118293Ssimokawa 153118293Ssimokawa for(i = 0 ; i < q->bnchunk; i++){ 154118293Ssimokawa q->bulkxfer[i].poffset = i * q->bnpacket; 155118293Ssimokawa q->bulkxfer[i].mbuf = NULL; 156118293Ssimokawa STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link); 157118293Ssimokawa } 158118293Ssimokawa 159118293Ssimokawa q->flag &= ~FWXFERQ_MODEMASK; 160118293Ssimokawa q->flag |= FWXFERQ_STREAM; 161118293Ssimokawa q->flag |= FWXFERQ_EXTBUF; 162118293Ssimokawa 163118293Ssimokawa return (0); 164118293Ssimokawa} 165118293Ssimokawa 166118293Ssimokawastatic int 167118293Ssimokawafwdev_freebuf(struct fw_xferq *q) 168118293Ssimokawa{ 169118293Ssimokawa if (q->flag & FWXFERQ_EXTBUF) { 170118293Ssimokawa if (q->buf != NULL) 171118293Ssimokawa fwdma_free_multiseg(q->buf); 172118293Ssimokawa q->buf = NULL; 173118293Ssimokawa free(q->bulkxfer, M_FW); 174118293Ssimokawa q->bulkxfer = NULL; 175118293Ssimokawa q->flag &= ~FWXFERQ_EXTBUF; 176118293Ssimokawa q->psize = 0; 177118293Ssimokawa q->maxq = FWMAXQUEUE; 178118293Ssimokawa } 179118293Ssimokawa return (0); 180118293Ssimokawa} 181118293Ssimokawa 182118293Ssimokawa 183118293Ssimokawastatic int 184130585Sphkfw_open (struct cdev *dev, int flags, int fmt, fw_proc *td) 185106813Ssimokawa{ 186106813Ssimokawa int err = 0; 187169130Ssimokawa int unit = DEV2UNIT(dev); 188169130Ssimokawa struct fw_drv1 *d; 189169130Ssimokawa struct firewire_softc *sc; 190106813Ssimokawa 191122227Ssimokawa if (DEV_FWMEM(dev)) 192122227Ssimokawa return fwmem_open(dev, flags, fmt, td); 193122227Ssimokawa 194170374Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 195170374Ssimokawa if (sc == NULL) 196170374Ssimokawa return (ENXIO); 197170374Ssimokawa 198170374Ssimokawa FW_GLOCK(sc->fc); 199170374Ssimokawa if (dev->si_drv1 != NULL) { 200170374Ssimokawa FW_GUNLOCK(sc->fc); 201118293Ssimokawa return (EBUSY); 202170374Ssimokawa } 203170374Ssimokawa /* set dummy value for allocation */ 204170374Ssimokawa dev->si_drv1 = (void *)-1; 205170374Ssimokawa FW_GUNLOCK(sc->fc); 206118293Ssimokawa 207170374Ssimokawa dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); 208170374Ssimokawa if (dev->si_drv1 == NULL) 209170374Ssimokawa return (ENOMEM); 210170374Ssimokawa 211127468Ssimokawa#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 212118455Ssimokawa if ((dev->si_flags & SI_NAMED) == 0) { 213118455Ssimokawa int unit = DEV2UNIT(dev); 214118455Ssimokawa int sub = DEV2SUB(dev); 215118455Ssimokawa 216183397Sed make_dev(&firewire_cdevsw, dev2unit(dev), 217118293Ssimokawa UID_ROOT, GID_OPERATOR, 0660, 218118293Ssimokawa "fw%d.%d", unit, sub); 219118455Ssimokawa } 220118455Ssimokawa#endif 221169130Ssimokawa d = (struct fw_drv1 *)dev->si_drv1; 222169130Ssimokawa d->fc = sc->fc; 223169130Ssimokawa STAILQ_INIT(&d->binds); 224169130Ssimokawa STAILQ_INIT(&d->rq); 225169130Ssimokawa 226106813Ssimokawa return err; 227106813Ssimokawa} 228106813Ssimokawa 229106813Ssimokawastatic int 230130585Sphkfw_close (struct cdev *dev, int flags, int fmt, fw_proc *td) 231106813Ssimokawa{ 232118293Ssimokawa struct firewire_comm *fc; 233118293Ssimokawa struct fw_drv1 *d; 234106813Ssimokawa struct fw_xfer *xfer; 235106813Ssimokawa struct fw_bind *fwb; 236106813Ssimokawa int err = 0; 237106813Ssimokawa 238106813Ssimokawa if (DEV_FWMEM(dev)) 239106813Ssimokawa return fwmem_close(dev, flags, fmt, td); 240106813Ssimokawa 241118293Ssimokawa d = (struct fw_drv1 *)dev->si_drv1; 242169130Ssimokawa fc = d->fc; 243118293Ssimokawa 244169130Ssimokawa /* remove binding */ 245169130Ssimokawa for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL; 246169130Ssimokawa fwb = STAILQ_FIRST(&d->binds)) { 247169130Ssimokawa fw_bindremove(fc, fwb); 248169130Ssimokawa STAILQ_REMOVE_HEAD(&d->binds, chlist); 249169130Ssimokawa fw_xferlist_remove(&fwb->xferlist); 250169130Ssimokawa free(fwb, M_FW); 251169130Ssimokawa } 252118293Ssimokawa if (d->ir != NULL) { 253118293Ssimokawa struct fw_xferq *ir = d->ir; 254118293Ssimokawa 255118293Ssimokawa if ((ir->flag & FWXFERQ_OPEN) == 0) 256118293Ssimokawa return (EINVAL); 257118293Ssimokawa if (ir->flag & FWXFERQ_RUNNING) { 258118293Ssimokawa ir->flag &= ~FWXFERQ_RUNNING; 259118293Ssimokawa fc->irx_disable(fc, ir->dmach); 260118293Ssimokawa } 261118293Ssimokawa /* free extbuf */ 262118293Ssimokawa fwdev_freebuf(ir); 263118293Ssimokawa /* drain receiving buffer */ 264118293Ssimokawa for (xfer = STAILQ_FIRST(&ir->q); 265118293Ssimokawa xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) { 266118293Ssimokawa ir->queued --; 267118293Ssimokawa STAILQ_REMOVE_HEAD(&ir->q, link); 268118293Ssimokawa 269118293Ssimokawa xfer->resp = 0; 270118293Ssimokawa fw_xfer_done(xfer); 271118293Ssimokawa } 272118293Ssimokawa ir->flag &= ~(FWXFERQ_OPEN | 273118293Ssimokawa FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 274118293Ssimokawa d->ir = NULL; 275118293Ssimokawa 276106813Ssimokawa } 277118293Ssimokawa if (d->it != NULL) { 278118293Ssimokawa struct fw_xferq *it = d->it; 279106813Ssimokawa 280118293Ssimokawa if ((it->flag & FWXFERQ_OPEN) == 0) 281118293Ssimokawa return (EINVAL); 282118293Ssimokawa if (it->flag & FWXFERQ_RUNNING) { 283118293Ssimokawa it->flag &= ~FWXFERQ_RUNNING; 284118293Ssimokawa fc->itx_disable(fc, it->dmach); 285118293Ssimokawa } 286118293Ssimokawa /* free extbuf */ 287118293Ssimokawa fwdev_freebuf(it); 288118293Ssimokawa it->flag &= ~(FWXFERQ_OPEN | 289118293Ssimokawa FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 290118293Ssimokawa d->it = NULL; 291106813Ssimokawa } 292118293Ssimokawa free(dev->si_drv1, M_FW); 293118293Ssimokawa dev->si_drv1 = NULL; 294106813Ssimokawa 295106813Ssimokawa return err; 296106813Ssimokawa} 297106813Ssimokawa 298169130Ssimokawastatic int 299169130Ssimokawafw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 300169130Ssimokawa{ 301169130Ssimokawa int err = 0, s; 302169130Ssimokawa struct fw_xfer *xfer; 303169130Ssimokawa struct fw_bind *fwb; 304169130Ssimokawa struct fw_pkt *fp; 305169130Ssimokawa struct tcode_info *tinfo; 306169130Ssimokawa 307170374Ssimokawa FW_GLOCK(d->fc); 308169130Ssimokawa while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == 0) 309170374Ssimokawa err = msleep(&d->rq, FW_GMTX(d->fc), FWPRI, "fwra", 0); 310169130Ssimokawa 311170374Ssimokawa if (err != 0) { 312170374Ssimokawa FW_GUNLOCK(d->fc); 313169130Ssimokawa return (err); 314170374Ssimokawa } 315169130Ssimokawa 316169130Ssimokawa s = splfw(); 317169130Ssimokawa STAILQ_REMOVE_HEAD(&d->rq, link); 318170374Ssimokawa FW_GUNLOCK(xfer->fc); 319169130Ssimokawa splx(s); 320169130Ssimokawa fp = &xfer->recv.hdr; 321169130Ssimokawa#if 0 /* for GASP ?? */ 322169130Ssimokawa if (fc->irx_post != NULL) 323169130Ssimokawa fc->irx_post(fc, fp->mode.ld); 324169130Ssimokawa#endif 325169130Ssimokawa tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode]; 326169130Ssimokawa err = uiomove((void *)fp, tinfo->hdr_len, uio); 327169130Ssimokawa if (err) 328169130Ssimokawa goto out; 329169130Ssimokawa err = uiomove((void *)xfer->recv.payload, xfer->recv.pay_len, uio); 330169130Ssimokawa 331169130Ssimokawaout: 332169130Ssimokawa /* recycle this xfer */ 333169130Ssimokawa fwb = (struct fw_bind *)xfer->sc; 334169130Ssimokawa fw_xfer_unload(xfer); 335169130Ssimokawa xfer->recv.pay_len = PAGE_SIZE; 336170374Ssimokawa FW_GLOCK(xfer->fc); 337169130Ssimokawa STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 338170374Ssimokawa FW_GUNLOCK(xfer->fc); 339169130Ssimokawa return (err); 340169130Ssimokawa} 341169130Ssimokawa 342106813Ssimokawa/* 343106813Ssimokawa * read request. 344106813Ssimokawa */ 345106813Ssimokawastatic int 346130585Sphkfw_read (struct cdev *dev, struct uio *uio, int ioflag) 347106813Ssimokawa{ 348169130Ssimokawa struct fw_drv1 *d; 349106813Ssimokawa struct fw_xferq *ir; 350169130Ssimokawa struct firewire_comm *fc; 351106813Ssimokawa int err = 0, s, slept = 0; 352106813Ssimokawa struct fw_pkt *fp; 353106813Ssimokawa 354106813Ssimokawa if (DEV_FWMEM(dev)) 355170374Ssimokawa return (physio(dev, uio, ioflag)); 356106813Ssimokawa 357169130Ssimokawa d = (struct fw_drv1 *)dev->si_drv1; 358169130Ssimokawa fc = d->fc; 359169130Ssimokawa ir = d->ir; 360169130Ssimokawa 361169130Ssimokawa if (ir == NULL) 362169130Ssimokawa return (fw_read_async(d, uio, ioflag)); 363169130Ssimokawa 364169130Ssimokawa if (ir->buf == NULL) 365118293Ssimokawa return (EIO); 366106813Ssimokawa 367170374Ssimokawa FW_GLOCK(fc); 368106813Ssimokawareadloop: 369113584Ssimokawa if (ir->stproc == NULL) { 370109988Ssimokawa /* iso bulkxfer */ 371106813Ssimokawa ir->stproc = STAILQ_FIRST(&ir->stvalid); 372109988Ssimokawa if (ir->stproc != NULL) { 373106813Ssimokawa s = splfw(); 374106813Ssimokawa STAILQ_REMOVE_HEAD(&ir->stvalid, link); 375106813Ssimokawa splx(s); 376106813Ssimokawa ir->queued = 0; 377106813Ssimokawa } 378106813Ssimokawa } 379169130Ssimokawa if (ir->stproc == NULL) { 380109988Ssimokawa /* no data avaliable */ 381109988Ssimokawa if (slept == 0) { 382106813Ssimokawa slept = 1; 383106813Ssimokawa ir->flag |= FWXFERQ_WAKEUP; 384170374Ssimokawa err = msleep(ir, FW_GMTX(fc), FWPRI, "fw_read", hz); 385109988Ssimokawa ir->flag &= ~FWXFERQ_WAKEUP; 386109988Ssimokawa if (err == 0) 387109988Ssimokawa goto readloop; 388109988Ssimokawa } else if (slept == 1) 389106813Ssimokawa err = EIO; 390170374Ssimokawa FW_GUNLOCK(fc); 391109988Ssimokawa return err; 392109988Ssimokawa } else if(ir->stproc != NULL) { 393109988Ssimokawa /* iso bulkxfer */ 394170374Ssimokawa FW_GUNLOCK(fc); 395113584Ssimokawa fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 396113584Ssimokawa ir->stproc->poffset + ir->queued); 397169130Ssimokawa if(fc->irx_post != NULL) 398169130Ssimokawa fc->irx_post(fc, fp->mode.ld); 399113584Ssimokawa if(fp->mode.stream.len == 0){ 400106813Ssimokawa err = EIO; 401106813Ssimokawa return err; 402106813Ssimokawa } 403109988Ssimokawa err = uiomove((caddr_t)fp, 404129585Sdfr fp->mode.stream.len + sizeof(uint32_t), uio); 405106813Ssimokawa ir->queued ++; 406106813Ssimokawa if(ir->queued >= ir->bnpacket){ 407106813Ssimokawa s = splfw(); 408106813Ssimokawa STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 409106813Ssimokawa splx(s); 410169130Ssimokawa fc->irx_enable(fc, ir->dmach); 411106813Ssimokawa ir->stproc = NULL; 412106813Ssimokawa } 413109988Ssimokawa if (uio->uio_resid >= ir->psize) { 414109988Ssimokawa slept = -1; 415170374Ssimokawa FW_GLOCK(fc); 416109988Ssimokawa goto readloop; 417109988Ssimokawa } 418106813Ssimokawa } 419106813Ssimokawa return err; 420106813Ssimokawa} 421106813Ssimokawa 422106813Ssimokawastatic int 423169130Ssimokawafw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 424169130Ssimokawa{ 425169130Ssimokawa struct fw_xfer *xfer; 426169130Ssimokawa struct fw_pkt pkt; 427169130Ssimokawa struct tcode_info *tinfo; 428169130Ssimokawa int err; 429169130Ssimokawa 430169130Ssimokawa bzero(&pkt, sizeof(struct fw_pkt)); 431169130Ssimokawa if ((err = uiomove((caddr_t)&pkt, sizeof(uint32_t), uio))) 432169130Ssimokawa return (err); 433169130Ssimokawa tinfo = &d->fc->tcode[pkt.mode.hdr.tcode]; 434169130Ssimokawa if ((err = uiomove((caddr_t)&pkt + sizeof(uint32_t), 435169130Ssimokawa tinfo->hdr_len - sizeof(uint32_t), uio))) 436169130Ssimokawa return (err); 437169130Ssimokawa 438169130Ssimokawa if ((xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid, 439169130Ssimokawa PAGE_SIZE/*XXX*/)) == NULL) 440169130Ssimokawa return (ENOMEM); 441169130Ssimokawa 442169130Ssimokawa bcopy(&pkt, &xfer->send.hdr, sizeof(struct fw_pkt)); 443169130Ssimokawa xfer->send.pay_len = uio->uio_resid; 444169130Ssimokawa if (uio->uio_resid > 0) { 445169130Ssimokawa if ((err = uiomove((caddr_t)&xfer->send.payload[0], 446194687Srdivacky uio->uio_resid, uio))) 447169130Ssimokawa goto out; 448169130Ssimokawa } 449169130Ssimokawa 450169130Ssimokawa xfer->fc = d->fc; 451169130Ssimokawa xfer->sc = NULL; 452170374Ssimokawa xfer->hand = fw_xferwake; 453169130Ssimokawa xfer->send.spd = 2 /* XXX */; 454169130Ssimokawa 455169130Ssimokawa if ((err = fw_asyreq(xfer->fc, -1, xfer))) 456169130Ssimokawa goto out; 457169130Ssimokawa 458170374Ssimokawa if ((err = fw_xferwait(xfer))) 459169130Ssimokawa goto out; 460169130Ssimokawa 461169130Ssimokawa if (xfer->resp != 0) { 462169130Ssimokawa err = xfer->resp; 463169130Ssimokawa goto out; 464169130Ssimokawa } 465169130Ssimokawa 466170374Ssimokawa if (xfer->flag & FWXF_RCVD) { 467170374Ssimokawa FW_GLOCK(xfer->fc); 468169130Ssimokawa STAILQ_INSERT_TAIL(&d->rq, xfer, link); 469170374Ssimokawa FW_GUNLOCK(xfer->fc); 470169130Ssimokawa return (0); 471169130Ssimokawa } 472169130Ssimokawa 473169130Ssimokawaout: 474169130Ssimokawa fw_xfer_free(xfer); 475169130Ssimokawa return (err); 476169130Ssimokawa} 477169130Ssimokawa 478169130Ssimokawastatic int 479130585Sphkfw_write (struct cdev *dev, struct uio *uio, int ioflag) 480106813Ssimokawa{ 481106813Ssimokawa int err = 0; 482106813Ssimokawa int s, slept = 0; 483169130Ssimokawa struct fw_drv1 *d; 484106813Ssimokawa struct fw_pkt *fp; 485106813Ssimokawa struct firewire_comm *fc; 486106813Ssimokawa struct fw_xferq *it; 487106813Ssimokawa 488106813Ssimokawa if (DEV_FWMEM(dev)) 489170374Ssimokawa return (physio(dev, uio, ioflag)); 490106813Ssimokawa 491169130Ssimokawa d = (struct fw_drv1 *)dev->si_drv1; 492169130Ssimokawa fc = d->fc; 493169130Ssimokawa it = d->it; 494169130Ssimokawa 495169130Ssimokawa if (it == NULL) 496169130Ssimokawa return (fw_write_async(d, uio, ioflag)); 497169130Ssimokawa 498169130Ssimokawa if (it->buf == NULL) 499118293Ssimokawa return (EIO); 500170374Ssimokawa 501170374Ssimokawa FW_GLOCK(fc); 502106813Ssimokawaisoloop: 503113802Ssimokawa if (it->stproc == NULL) { 504113802Ssimokawa it->stproc = STAILQ_FIRST(&it->stfree); 505113802Ssimokawa if (it->stproc != NULL) { 506106813Ssimokawa s = splfw(); 507113802Ssimokawa STAILQ_REMOVE_HEAD(&it->stfree, link); 508106813Ssimokawa splx(s); 509113802Ssimokawa it->queued = 0; 510113802Ssimokawa } else if (slept == 0) { 511113802Ssimokawa slept = 1; 512170374Ssimokawa#if 0 /* XXX to avoid lock recursion */ 513169130Ssimokawa err = fc->itx_enable(fc, it->dmach); 514113802Ssimokawa if (err) 515170374Ssimokawa goto out; 516170374Ssimokawa#endif 517170374Ssimokawa err = msleep(it, FW_GMTX(fc), FWPRI, "fw_write", hz); 518113802Ssimokawa if (err) 519170374Ssimokawa goto out; 520109988Ssimokawa goto isoloop; 521113802Ssimokawa } else { 522113802Ssimokawa err = EIO; 523170374Ssimokawa goto out; 524106813Ssimokawa } 525106813Ssimokawa } 526170374Ssimokawa FW_GUNLOCK(fc); 527113802Ssimokawa fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 528113802Ssimokawa it->stproc->poffset + it->queued); 529113802Ssimokawa err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 530113802Ssimokawa err = uiomove((caddr_t)fp->mode.stream.payload, 531113802Ssimokawa fp->mode.stream.len, uio); 532113802Ssimokawa it->queued ++; 533113802Ssimokawa if (it->queued >= it->bnpacket) { 534113802Ssimokawa s = splfw(); 535113802Ssimokawa STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 536113802Ssimokawa splx(s); 537113802Ssimokawa it->stproc = NULL; 538169130Ssimokawa err = fc->itx_enable(fc, it->dmach); 539113802Ssimokawa } 540113802Ssimokawa if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 541113802Ssimokawa slept = 0; 542170374Ssimokawa FW_GLOCK(fc); 543113802Ssimokawa goto isoloop; 544113802Ssimokawa } 545113802Ssimokawa return err; 546170374Ssimokawa 547170374Ssimokawaout: 548170374Ssimokawa FW_GUNLOCK(fc); 549170374Ssimokawa return err; 550106813Ssimokawa} 551169130Ssimokawa 552169130Ssimokawastatic void 553169130Ssimokawafw_hand(struct fw_xfer *xfer) 554169130Ssimokawa{ 555169130Ssimokawa struct fw_bind *fwb; 556169130Ssimokawa struct fw_drv1 *d; 557169130Ssimokawa 558169130Ssimokawa fwb = (struct fw_bind *)xfer->sc; 559169130Ssimokawa d = (struct fw_drv1 *)fwb->sc; 560170374Ssimokawa FW_GLOCK(xfer->fc); 561169130Ssimokawa STAILQ_INSERT_TAIL(&d->rq, xfer, link); 562170374Ssimokawa FW_GUNLOCK(xfer->fc); 563169130Ssimokawa wakeup(&d->rq); 564169130Ssimokawa} 565169130Ssimokawa 566106813Ssimokawa/* 567106813Ssimokawa * ioctl support. 568106813Ssimokawa */ 569106813Ssimokawaint 570130585Sphkfw_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 571106813Ssimokawa{ 572118293Ssimokawa struct firewire_comm *fc; 573118293Ssimokawa struct fw_drv1 *d; 574169130Ssimokawa int i, len, err = 0; 575106813Ssimokawa struct fw_device *fwdev; 576106813Ssimokawa struct fw_bind *fwb; 577106813Ssimokawa struct fw_xferq *ir, *it; 578106813Ssimokawa struct fw_xfer *xfer; 579106813Ssimokawa struct fw_pkt *fp; 580109814Ssimokawa struct fw_devinfo *devinfo; 581117473Ssimokawa void *ptr; 582106813Ssimokawa 583106813Ssimokawa struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 584106813Ssimokawa struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 585106813Ssimokawa struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 586106813Ssimokawa struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 587106813Ssimokawa struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 588106813Ssimokawa struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 589106813Ssimokawa 590106813Ssimokawa if (DEV_FWMEM(dev)) 591106813Ssimokawa return fwmem_ioctl(dev, cmd, data, flag, td); 592106813Ssimokawa 593106813Ssimokawa if (!data) 594106813Ssimokawa return(EINVAL); 595106813Ssimokawa 596118293Ssimokawa d = (struct fw_drv1 *)dev->si_drv1; 597169130Ssimokawa fc = d->fc; 598118293Ssimokawa ir = d->ir; 599118293Ssimokawa it = d->it; 600118293Ssimokawa 601106813Ssimokawa switch (cmd) { 602106813Ssimokawa case FW_STSTREAM: 603118293Ssimokawa if (it == NULL) { 604170374Ssimokawa i = fw_open_isodma(fc, /* tx */1); 605170374Ssimokawa if (i < 0) { 606118293Ssimokawa err = EBUSY; 607118293Ssimokawa break; 608118293Ssimokawa } 609170374Ssimokawa it = fc->it[i]; 610118293Ssimokawa err = fwdev_allocbuf(fc, it, &d->bufreq.tx); 611170374Ssimokawa if (err) { 612170374Ssimokawa it->flag &= ~FWXFERQ_OPEN; 613118293Ssimokawa break; 614170374Ssimokawa } 615118293Ssimokawa } 616118293Ssimokawa it->flag &= ~0xff; 617118293Ssimokawa it->flag |= (0x3f & ichreq->ch); 618118293Ssimokawa it->flag |= ((0x3 & ichreq->tag) << 6); 619118293Ssimokawa d->it = it; 620106813Ssimokawa break; 621106813Ssimokawa case FW_GTSTREAM: 622118293Ssimokawa if (it != NULL) { 623118293Ssimokawa ichreq->ch = it->flag & 0x3f; 624118293Ssimokawa ichreq->tag = it->flag >> 2 & 0x3; 625118293Ssimokawa } else 626118293Ssimokawa err = EINVAL; 627106813Ssimokawa break; 628106813Ssimokawa case FW_SRSTREAM: 629118293Ssimokawa if (ir == NULL) { 630170374Ssimokawa i = fw_open_isodma(fc, /* tx */0); 631170374Ssimokawa if (i < 0) { 632118293Ssimokawa err = EBUSY; 633118293Ssimokawa break; 634118293Ssimokawa } 635170374Ssimokawa ir = fc->ir[i]; 636118293Ssimokawa err = fwdev_allocbuf(fc, ir, &d->bufreq.rx); 637170374Ssimokawa if (err) { 638170374Ssimokawa ir->flag &= ~FWXFERQ_OPEN; 639118293Ssimokawa break; 640170374Ssimokawa } 641118293Ssimokawa } 642118293Ssimokawa ir->flag &= ~0xff; 643118293Ssimokawa ir->flag |= (0x3f & ichreq->ch); 644118293Ssimokawa ir->flag |= ((0x3 & ichreq->tag) << 6); 645118293Ssimokawa d->ir = ir; 646118293Ssimokawa err = fc->irx_enable(fc, ir->dmach); 647106813Ssimokawa break; 648106813Ssimokawa case FW_GRSTREAM: 649118293Ssimokawa if (d->ir != NULL) { 650118293Ssimokawa ichreq->ch = ir->flag & 0x3f; 651118293Ssimokawa ichreq->tag = ir->flag >> 2 & 0x3; 652118293Ssimokawa } else 653118293Ssimokawa err = EINVAL; 654106813Ssimokawa break; 655106813Ssimokawa case FW_SSTBUF: 656118293Ssimokawa bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq)); 657106813Ssimokawa break; 658106813Ssimokawa case FW_GSTBUF: 659118293Ssimokawa bzero(&ibufreq->rx, sizeof(ibufreq->rx)); 660118293Ssimokawa if (ir != NULL) { 661118293Ssimokawa ibufreq->rx.nchunk = ir->bnchunk; 662118293Ssimokawa ibufreq->rx.npacket = ir->bnpacket; 663118293Ssimokawa ibufreq->rx.psize = ir->psize; 664118293Ssimokawa } 665118293Ssimokawa bzero(&ibufreq->tx, sizeof(ibufreq->tx)); 666118293Ssimokawa if (it != NULL) { 667118293Ssimokawa ibufreq->tx.nchunk = it->bnchunk; 668118293Ssimokawa ibufreq->tx.npacket = it->bnpacket; 669118293Ssimokawa ibufreq->tx.psize = it->psize; 670118293Ssimokawa } 671106813Ssimokawa break; 672106813Ssimokawa case FW_ASYREQ: 673120660Ssimokawa { 674120660Ssimokawa struct tcode_info *tinfo; 675121466Ssimokawa int pay_len = 0; 676120660Ssimokawa 677106813Ssimokawa fp = &asyreq->pkt; 678169130Ssimokawa tinfo = &fc->tcode[fp->mode.hdr.tcode]; 679121466Ssimokawa 680121466Ssimokawa if ((tinfo->flag & FWTI_BLOCK_ASY) != 0) 681121466Ssimokawa pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len); 682121466Ssimokawa 683121466Ssimokawa xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/); 684121466Ssimokawa if (xfer == NULL) 685121466Ssimokawa return (ENOMEM); 686121466Ssimokawa 687106813Ssimokawa switch (asyreq->req.type) { 688106813Ssimokawa case FWASREQNODE: 689106813Ssimokawa break; 690106813Ssimokawa case FWASREQEUI: 691169130Ssimokawa fwdev = fw_noderesolve_eui64(fc, 692110582Ssimokawa &asyreq->req.dst.eui); 693106813Ssimokawa if (fwdev == NULL) { 694169130Ssimokawa device_printf(fc->bdev, 695108782Ssimokawa "cannot find node\n"); 696106813Ssimokawa err = EINVAL; 697121466Ssimokawa goto out; 698106813Ssimokawa } 699120660Ssimokawa fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst; 700106813Ssimokawa break; 701106813Ssimokawa case FWASRESTL: 702106813Ssimokawa /* XXX what's this? */ 703106813Ssimokawa break; 704106813Ssimokawa case FWASREQSTREAM: 705106813Ssimokawa /* nothing to do */ 706106813Ssimokawa break; 707106813Ssimokawa } 708121466Ssimokawa 709120660Ssimokawa bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len); 710121466Ssimokawa if (pay_len > 0) 711120660Ssimokawa bcopy((char *)fp + tinfo->hdr_len, 712127347Ssimokawa (void *)xfer->send.payload, pay_len); 713121466Ssimokawa xfer->send.spd = asyreq->req.sped; 714170374Ssimokawa xfer->hand = fw_xferwake; 715121466Ssimokawa 716169130Ssimokawa if ((err = fw_asyreq(fc, -1, xfer)) != 0) 717121466Ssimokawa goto out; 718170374Ssimokawa if ((err = fw_xferwait(xfer)) != 0) 719121466Ssimokawa goto out; 720121466Ssimokawa if (xfer->resp != 0) { 721121466Ssimokawa err = EIO; 722121466Ssimokawa goto out; 723106813Ssimokawa } 724121466Ssimokawa if ((tinfo->flag & FWTI_TLABEL) == 0) 725121466Ssimokawa goto out; 726121466Ssimokawa 727121466Ssimokawa /* copy response */ 728169130Ssimokawa tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode]; 729129628Sdfr if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB || 730129628Sdfr xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) { 731129628Sdfr pay_len = xfer->recv.pay_len; 732129628Sdfr if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) { 733129628Sdfr asyreq->req.len = xfer->recv.pay_len + 734129628Sdfr tinfo->hdr_len; 735129628Sdfr } else { 736129628Sdfr err = EINVAL; 737129628Sdfr pay_len = 0; 738129628Sdfr } 739129628Sdfr } else { 740129628Sdfr pay_len = 0; 741129628Sdfr } 742121466Ssimokawa bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len); 743129628Sdfr bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, pay_len); 744121466Ssimokawaout: 745120660Ssimokawa fw_xfer_free_buf(xfer); 746106813Ssimokawa break; 747120660Ssimokawa } 748106813Ssimokawa case FW_IBUSRST: 749169130Ssimokawa fc->ibr(fc); 750106813Ssimokawa break; 751106813Ssimokawa case FW_CBINDADDR: 752169130Ssimokawa fwb = fw_bindlookup(fc, 753106813Ssimokawa bindreq->start.hi, bindreq->start.lo); 754106813Ssimokawa if(fwb == NULL){ 755106813Ssimokawa err = EINVAL; 756106813Ssimokawa break; 757106813Ssimokawa } 758169130Ssimokawa fw_bindremove(fc, fwb); 759169130Ssimokawa STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist); 760169130Ssimokawa fw_xferlist_remove(&fwb->xferlist); 761110195Ssimokawa free(fwb, M_FW); 762106813Ssimokawa break; 763106813Ssimokawa case FW_SBINDADDR: 764106813Ssimokawa if(bindreq->len <= 0 ){ 765106813Ssimokawa err = EINVAL; 766106813Ssimokawa break; 767106813Ssimokawa } 768106813Ssimokawa if(bindreq->start.hi > 0xffff ){ 769106813Ssimokawa err = EINVAL; 770106813Ssimokawa break; 771106813Ssimokawa } 772170374Ssimokawa fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_WAITOK); 773106813Ssimokawa if(fwb == NULL){ 774106813Ssimokawa err = ENOMEM; 775106813Ssimokawa break; 776106813Ssimokawa } 777120660Ssimokawa fwb->start = ((u_int64_t)bindreq->start.hi << 32) | 778120660Ssimokawa bindreq->start.lo; 779120660Ssimokawa fwb->end = fwb->start + bindreq->len; 780169130Ssimokawa fwb->sc = (void *)d; 781169130Ssimokawa STAILQ_INIT(&fwb->xferlist); 782169130Ssimokawa err = fw_bindadd(fc, fwb); 783169130Ssimokawa if (err == 0) { 784169130Ssimokawa fw_xferlist_add(&fwb->xferlist, M_FWXFER, 785169130Ssimokawa /* XXX */ 786169130Ssimokawa PAGE_SIZE, PAGE_SIZE, 5, 787169130Ssimokawa fc, (void *)fwb, fw_hand); 788169130Ssimokawa STAILQ_INSERT_TAIL(&d->binds, fwb, chlist); 789106813Ssimokawa } 790106813Ssimokawa break; 791106813Ssimokawa case FW_GDEVLST: 792109814Ssimokawa i = len = 1; 793109814Ssimokawa /* myself */ 794109814Ssimokawa devinfo = &fwdevlst->dev[0]; 795169130Ssimokawa devinfo->dst = fc->nodeid; 796109814Ssimokawa devinfo->status = 0; /* XXX */ 797169130Ssimokawa devinfo->eui.hi = fc->eui.hi; 798169130Ssimokawa devinfo->eui.lo = fc->eui.lo; 799169130Ssimokawa STAILQ_FOREACH(fwdev, &fc->devices, link) { 800109814Ssimokawa if(len < FW_MAX_DEVLST){ 801109814Ssimokawa devinfo = &fwdevlst->dev[len++]; 802109814Ssimokawa devinfo->dst = fwdev->dst; 803109814Ssimokawa devinfo->status = 804109814Ssimokawa (fwdev->status == FWDEVINVAL)?0:1; 805109814Ssimokawa devinfo->eui.hi = fwdev->eui.hi; 806109814Ssimokawa devinfo->eui.lo = fwdev->eui.lo; 807106813Ssimokawa } 808106813Ssimokawa i++; 809106813Ssimokawa } 810106813Ssimokawa fwdevlst->n = i; 811109814Ssimokawa fwdevlst->info_len = len; 812106813Ssimokawa break; 813106813Ssimokawa case FW_GTPMAP: 814169130Ssimokawa bcopy(fc->topology_map, data, 815169130Ssimokawa (fc->topology_map->crc_len + 1) * 4); 816106813Ssimokawa break; 817106813Ssimokawa case FW_GCROM: 818169130Ssimokawa STAILQ_FOREACH(fwdev, &fc->devices, link) 819110193Ssimokawa if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 820106813Ssimokawa break; 821106813Ssimokawa if (fwdev == NULL) { 822169130Ssimokawa if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) { 823117473Ssimokawa err = FWNODE_INVAL; 824117473Ssimokawa break; 825117473Ssimokawa } 826117473Ssimokawa /* myself */ 827117473Ssimokawa ptr = malloc(CROMSIZE, M_FW, M_WAITOK); 828117473Ssimokawa len = CROMSIZE; 829117473Ssimokawa for (i = 0; i < CROMSIZE/4; i++) 830129585Sdfr ((uint32_t *)ptr)[i] 831169130Ssimokawa = ntohl(fc->config_rom[i]); 832117473Ssimokawa } else { 833117473Ssimokawa /* found */ 834117473Ssimokawa ptr = (void *)&fwdev->csrrom[0]; 835117473Ssimokawa if (fwdev->rommax < CSRROMOFF) 836117473Ssimokawa len = 0; 837117473Ssimokawa else 838117473Ssimokawa len = fwdev->rommax - CSRROMOFF + 4; 839106813Ssimokawa } 840169019Ssimokawa if (crom_buf->len < len) 841106813Ssimokawa len = crom_buf->len; 842106813Ssimokawa else 843106813Ssimokawa crom_buf->len = len; 844117473Ssimokawa err = copyout(ptr, crom_buf->ptr, len); 845117473Ssimokawa if (fwdev == NULL) 846117473Ssimokawa /* myself */ 847117473Ssimokawa free(ptr, M_FW); 848106813Ssimokawa break; 849106813Ssimokawa default: 850169130Ssimokawa fc->ioctl (dev, cmd, data, flag, td); 851106813Ssimokawa break; 852106813Ssimokawa } 853106813Ssimokawa return err; 854106813Ssimokawa} 855106813Ssimokawaint 856130585Sphkfw_poll(struct cdev *dev, int events, fw_proc *td) 857106813Ssimokawa{ 858118293Ssimokawa struct fw_xferq *ir; 859106813Ssimokawa int revents; 860106813Ssimokawa int tmp; 861106813Ssimokawa 862106813Ssimokawa if (DEV_FWMEM(dev)) 863106813Ssimokawa return fwmem_poll(dev, events, td); 864106813Ssimokawa 865118293Ssimokawa ir = ((struct fw_drv1 *)dev->si_drv1)->ir; 866106813Ssimokawa revents = 0; 867106813Ssimokawa tmp = POLLIN | POLLRDNORM; 868106813Ssimokawa if (events & tmp) { 869118293Ssimokawa if (STAILQ_FIRST(&ir->q) != NULL) 870106813Ssimokawa revents |= tmp; 871106813Ssimokawa else 872118293Ssimokawa selrecord(td, &ir->rsel); 873106813Ssimokawa } 874106813Ssimokawa tmp = POLLOUT | POLLWRNORM; 875106813Ssimokawa if (events & tmp) { 876106813Ssimokawa /* XXX should be fixed */ 877106813Ssimokawa revents |= tmp; 878106813Ssimokawa } 879106813Ssimokawa 880106813Ssimokawa return revents; 881106813Ssimokawa} 882106813Ssimokawa 883106813Ssimokawastatic int 884127468Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500102 885130585Sphkfw_mmap (struct cdev *dev, vm_offset_t offset, int nproto) 886111615Ssimokawa#else 887201223Srnolandfw_mmap (struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, 888201223Srnoland int nproto, vm_memattr_t *memattr) 889111615Ssimokawa#endif 890106813Ssimokawa{ 891106813Ssimokawa 892106813Ssimokawa if (DEV_FWMEM(dev)) 893127468Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500102 894111615Ssimokawa return fwmem_mmap(dev, offset, nproto); 895111615Ssimokawa#else 896201223Srnoland return fwmem_mmap(dev, offset, paddr, nproto, memattr); 897111615Ssimokawa#endif 898106813Ssimokawa 899106813Ssimokawa return EINVAL; 900106813Ssimokawa} 901118455Ssimokawa 902120660Ssimokawastatic void 903120660Ssimokawafw_strategy(struct bio *bp) 904120660Ssimokawa{ 905130585Sphk struct cdev *dev; 906120660Ssimokawa 907120660Ssimokawa dev = bp->bio_dev; 908120660Ssimokawa if (DEV_FWMEM(dev)) { 909120660Ssimokawa fwmem_strategy(bp); 910120660Ssimokawa return; 911120660Ssimokawa } 912120660Ssimokawa 913120660Ssimokawa bp->bio_error = EOPNOTSUPP; 914120660Ssimokawa bp->bio_flags |= BIO_ERROR; 915120660Ssimokawa bp->bio_resid = bp->bio_bcount; 916120660Ssimokawa biodone(bp); 917120660Ssimokawa} 918120660Ssimokawa 919118455Ssimokawaint 920118455Ssimokawafwdev_makedev(struct firewire_softc *sc) 921118455Ssimokawa{ 922118455Ssimokawa int err = 0; 923118455Ssimokawa 924127468Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500000 925127468Ssimokawa cdevsw_add(&firewire_cdevsw); 926127468Ssimokawa#else 927130585Sphk struct cdev *d; 928118455Ssimokawa int unit; 929118455Ssimokawa 930118455Ssimokawa unit = device_get_unit(sc->fc->bdev); 931118455Ssimokawa sc->dev = make_dev(&firewire_cdevsw, MAKEMINOR(0, unit, 0), 932118455Ssimokawa UID_ROOT, GID_OPERATOR, 0660, 933118455Ssimokawa "fw%d.%d", unit, 0); 934118455Ssimokawa d = make_dev(&firewire_cdevsw, 935118455Ssimokawa MAKEMINOR(FWMEM_FLAG, unit, 0), 936118455Ssimokawa UID_ROOT, GID_OPERATOR, 0660, 937118455Ssimokawa "fwmem%d.%d", unit, 0); 938118455Ssimokawa dev_depends(sc->dev, d); 939118455Ssimokawa make_dev_alias(sc->dev, "fw%d", unit); 940118455Ssimokawa make_dev_alias(d, "fwmem%d", unit); 941118455Ssimokawa#endif 942118455Ssimokawa 943118455Ssimokawa return (err); 944118455Ssimokawa} 945118455Ssimokawa 946118455Ssimokawaint 947118455Ssimokawafwdev_destroydev(struct firewire_softc *sc) 948118455Ssimokawa{ 949118455Ssimokawa int err = 0; 950118455Ssimokawa 951127468Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500000 952127468Ssimokawa cdevsw_remove(&firewire_cdevsw); 953127468Ssimokawa#else 954118455Ssimokawa destroy_dev(sc->dev); 955118455Ssimokawa#endif 956118455Ssimokawa return (err); 957118455Ssimokawa} 958118455Ssimokawa 959127468Ssimokawa#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 960118455Ssimokawa#define NDEVTYPE 2 961118455Ssimokawavoid 962148868Srwatsonfwdev_clone(void *arg, struct ucred *cred, char *name, int namelen, 963148868Srwatson struct cdev **dev) 964118455Ssimokawa{ 965118455Ssimokawa struct firewire_softc *sc; 966118455Ssimokawa char *devnames[NDEVTYPE] = {"fw", "fwmem"}; 967118455Ssimokawa char *subp = NULL; 968118455Ssimokawa int devflag[NDEVTYPE] = {0, FWMEM_FLAG}; 969118455Ssimokawa int i, unit = 0, sub = 0; 970118455Ssimokawa 971130640Sphk if (*dev != NULL) 972118455Ssimokawa return; 973118455Ssimokawa 974118455Ssimokawa for (i = 0; i < NDEVTYPE; i++) 975120624Ssimokawa if (dev_stdclone(name, &subp, devnames[i], &unit) == 2) 976118455Ssimokawa goto found; 977118455Ssimokawa /* not match */ 978118455Ssimokawa return; 979118455Ssimokawafound: 980118455Ssimokawa 981118455Ssimokawa if (subp == NULL || *subp++ != '.') 982118455Ssimokawa return; 983118455Ssimokawa 984118455Ssimokawa /* /dev/fwU.S */ 985118455Ssimokawa while (isdigit(*subp)) { 986118455Ssimokawa sub *= 10; 987118455Ssimokawa sub += *subp++ - '0'; 988118455Ssimokawa } 989118455Ssimokawa if (*subp != '\0') 990118455Ssimokawa return; 991118455Ssimokawa 992118455Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 993118455Ssimokawa if (sc == NULL) 994118455Ssimokawa return; 995255359Sdavide *dev = make_dev_credf(MAKEDEV_REF, &firewire_cdevsw, 996255359Sdavide MAKEMINOR(devflag[i], unit, sub), cred, UID_ROOT, GID_OPERATOR, 997255359Sdavide 0660, "%s%d.%d", devnames[i], unit, sub); 998118455Ssimokawa dev_depends(sc->dev, *dev); 999118455Ssimokawa return; 1000118455Ssimokawa} 1001118455Ssimokawa#endif 1002