fwdev.c revision 272214
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. 33272214Skan * 34106813Ssimokawa * $FreeBSD: head/sys/dev/firewire/fwdev.c 272214 2014-09-27 16:50:21Z kan $ 35106813Ssimokawa * 36106813Ssimokawa */ 37106813Ssimokawa 38106813Ssimokawa#include <sys/param.h> 39106813Ssimokawa#include <sys/systm.h> 40106813Ssimokawa#include <sys/types.h> 41106813Ssimokawa#include <sys/mbuf.h> 42120660Ssimokawa#include <sys/bio.h> 43106813Ssimokawa 44106813Ssimokawa#include <sys/kernel.h> 45106813Ssimokawa#include <sys/malloc.h> 46106813Ssimokawa#include <sys/conf.h> 47106813Ssimokawa#include <sys/poll.h> 48106813Ssimokawa 49106813Ssimokawa#include <sys/bus.h> 50118455Ssimokawa#include <sys/ctype.h> 51113584Ssimokawa#include <machine/bus.h> 52106813Ssimokawa 53106813Ssimokawa#include <sys/ioccom.h> 54106813Ssimokawa 55106813Ssimokawa#include <dev/firewire/firewire.h> 56106813Ssimokawa#include <dev/firewire/firewirereg.h> 57113584Ssimokawa#include <dev/firewire/fwdma.h> 58106813Ssimokawa#include <dev/firewire/fwmem.h> 59109282Ssimokawa#include <dev/firewire/iec68113.h> 60106813Ssimokawa 61106813Ssimokawa#define FWNODE_INVAL 0xffff 62106813Ssimokawa 63106813Ssimokawastatic d_open_t fw_open; 64106813Ssimokawastatic d_close_t fw_close; 65106813Ssimokawastatic d_ioctl_t fw_ioctl; 66106813Ssimokawastatic d_poll_t fw_poll; 67106813Ssimokawastatic d_read_t fw_read; /* for Isochronous packet */ 68106813Ssimokawastatic d_write_t fw_write; 69106813Ssimokawastatic d_mmap_t fw_mmap; 70120660Ssimokawastatic d_strategy_t fw_strategy; 71106813Ssimokawa 72126080Sphkstruct cdevsw firewire_cdevsw = { 73126080Sphk .d_version = D_VERSION, 74111815Sphk .d_open = fw_open, 75111815Sphk .d_close = fw_close, 76111815Sphk .d_read = fw_read, 77111815Sphk .d_write = fw_write, 78111815Sphk .d_ioctl = fw_ioctl, 79111815Sphk .d_poll = fw_poll, 80111815Sphk .d_mmap = fw_mmap, 81120660Ssimokawa .d_strategy = fw_strategy, 82111815Sphk .d_name = "fw", 83170374Ssimokawa .d_flags = D_MEM 84106813Ssimokawa}; 85106813Ssimokawa 86118293Ssimokawastruct fw_drv1 { 87169130Ssimokawa struct firewire_comm *fc; 88118293Ssimokawa struct fw_xferq *ir; 89118293Ssimokawa struct fw_xferq *it; 90118293Ssimokawa struct fw_isobufreq bufreq; 91169130Ssimokawa STAILQ_HEAD(, fw_bind) binds; 92169130Ssimokawa STAILQ_HEAD(, fw_xfer) rq; 93118293Ssimokawa}; 94118293Ssimokawa 95106813Ssimokawastatic int 96118293Ssimokawafwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q, 97118293Ssimokawa struct fw_bufspec *b) 98118293Ssimokawa{ 99118293Ssimokawa int i; 100118293Ssimokawa 101118293Ssimokawa if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF)) 102272214Skan return (EBUSY); 103118293Ssimokawa 104272214Skan q->bulkxfer = malloc(sizeof(struct fw_bulkxfer) * b->nchunk, 105272214Skan M_FW, M_WAITOK); 106118293Ssimokawa if (q->bulkxfer == NULL) 107272214Skan return (ENOMEM); 108118293Ssimokawa 109129585Sdfr b->psize = roundup2(b->psize, sizeof(uint32_t)); 110129585Sdfr q->buf = fwdma_malloc_multiseg(fc, sizeof(uint32_t), 111272214Skan b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK); 112118293Ssimokawa 113118293Ssimokawa if (q->buf == NULL) { 114118293Ssimokawa free(q->bulkxfer, M_FW); 115118293Ssimokawa q->bulkxfer = NULL; 116272214Skan return (ENOMEM); 117118293Ssimokawa } 118118293Ssimokawa q->bnchunk = b->nchunk; 119118293Ssimokawa q->bnpacket = b->npacket; 120118293Ssimokawa q->psize = (b->psize + 3) & ~3; 121118293Ssimokawa q->queued = 0; 122118293Ssimokawa 123118293Ssimokawa STAILQ_INIT(&q->stvalid); 124118293Ssimokawa STAILQ_INIT(&q->stfree); 125118293Ssimokawa STAILQ_INIT(&q->stdma); 126118293Ssimokawa q->stproc = NULL; 127118293Ssimokawa 128272214Skan for (i = 0; i < q->bnchunk; i++) { 129118293Ssimokawa q->bulkxfer[i].poffset = i * q->bnpacket; 130118293Ssimokawa q->bulkxfer[i].mbuf = NULL; 131118293Ssimokawa STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link); 132118293Ssimokawa } 133118293Ssimokawa 134118293Ssimokawa q->flag &= ~FWXFERQ_MODEMASK; 135118293Ssimokawa q->flag |= FWXFERQ_STREAM; 136118293Ssimokawa q->flag |= FWXFERQ_EXTBUF; 137118293Ssimokawa 138118293Ssimokawa return (0); 139118293Ssimokawa} 140118293Ssimokawa 141118293Ssimokawastatic int 142118293Ssimokawafwdev_freebuf(struct fw_xferq *q) 143118293Ssimokawa{ 144118293Ssimokawa if (q->flag & FWXFERQ_EXTBUF) { 145118293Ssimokawa if (q->buf != NULL) 146118293Ssimokawa fwdma_free_multiseg(q->buf); 147118293Ssimokawa q->buf = NULL; 148118293Ssimokawa free(q->bulkxfer, M_FW); 149118293Ssimokawa q->bulkxfer = NULL; 150118293Ssimokawa q->flag &= ~FWXFERQ_EXTBUF; 151118293Ssimokawa q->psize = 0; 152118293Ssimokawa q->maxq = FWMAXQUEUE; 153118293Ssimokawa } 154118293Ssimokawa return (0); 155118293Ssimokawa} 156118293Ssimokawa 157118293Ssimokawa 158118293Ssimokawastatic int 159272214Skanfw_open(struct cdev *dev, int flags, int fmt, fw_proc *td) 160106813Ssimokawa{ 161106813Ssimokawa int err = 0; 162169130Ssimokawa int unit = DEV2UNIT(dev); 163169130Ssimokawa struct fw_drv1 *d; 164169130Ssimokawa struct firewire_softc *sc; 165106813Ssimokawa 166122227Ssimokawa if (DEV_FWMEM(dev)) 167122227Ssimokawa return fwmem_open(dev, flags, fmt, td); 168122227Ssimokawa 169170374Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 170170374Ssimokawa if (sc == NULL) 171170374Ssimokawa return (ENXIO); 172170374Ssimokawa 173170374Ssimokawa FW_GLOCK(sc->fc); 174170374Ssimokawa if (dev->si_drv1 != NULL) { 175170374Ssimokawa FW_GUNLOCK(sc->fc); 176118293Ssimokawa return (EBUSY); 177170374Ssimokawa } 178170374Ssimokawa /* set dummy value for allocation */ 179170374Ssimokawa dev->si_drv1 = (void *)-1; 180170374Ssimokawa FW_GUNLOCK(sc->fc); 181118293Ssimokawa 182170374Ssimokawa dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); 183170374Ssimokawa if (dev->si_drv1 == NULL) 184170374Ssimokawa return (ENOMEM); 185170374Ssimokawa 186118455Ssimokawa if ((dev->si_flags & SI_NAMED) == 0) { 187118455Ssimokawa int unit = DEV2UNIT(dev); 188118455Ssimokawa int sub = DEV2SUB(dev); 189118455Ssimokawa 190183397Sed make_dev(&firewire_cdevsw, dev2unit(dev), 191272214Skan UID_ROOT, GID_OPERATOR, 0660, "fw%d.%d", unit, sub); 192118455Ssimokawa } 193272214Skan 194272214Skan d = dev->si_drv1; 195169130Ssimokawa d->fc = sc->fc; 196169130Ssimokawa STAILQ_INIT(&d->binds); 197169130Ssimokawa STAILQ_INIT(&d->rq); 198169130Ssimokawa 199106813Ssimokawa return err; 200106813Ssimokawa} 201106813Ssimokawa 202106813Ssimokawastatic int 203272214Skanfw_close(struct cdev *dev, int flags, int fmt, fw_proc *td) 204106813Ssimokawa{ 205118293Ssimokawa struct firewire_comm *fc; 206118293Ssimokawa struct fw_drv1 *d; 207106813Ssimokawa struct fw_xfer *xfer; 208106813Ssimokawa struct fw_bind *fwb; 209106813Ssimokawa int err = 0; 210106813Ssimokawa 211106813Ssimokawa if (DEV_FWMEM(dev)) 212106813Ssimokawa return fwmem_close(dev, flags, fmt, td); 213106813Ssimokawa 214272214Skan d = dev->si_drv1; 215169130Ssimokawa fc = d->fc; 216118293Ssimokawa 217169130Ssimokawa /* remove binding */ 218169130Ssimokawa for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL; 219272214Skan fwb = STAILQ_FIRST(&d->binds)) { 220169130Ssimokawa fw_bindremove(fc, fwb); 221169130Ssimokawa STAILQ_REMOVE_HEAD(&d->binds, chlist); 222169130Ssimokawa fw_xferlist_remove(&fwb->xferlist); 223169130Ssimokawa free(fwb, M_FW); 224169130Ssimokawa } 225118293Ssimokawa if (d->ir != NULL) { 226118293Ssimokawa struct fw_xferq *ir = d->ir; 227118293Ssimokawa 228118293Ssimokawa if ((ir->flag & FWXFERQ_OPEN) == 0) 229118293Ssimokawa return (EINVAL); 230118293Ssimokawa if (ir->flag & FWXFERQ_RUNNING) { 231118293Ssimokawa ir->flag &= ~FWXFERQ_RUNNING; 232118293Ssimokawa fc->irx_disable(fc, ir->dmach); 233118293Ssimokawa } 234118293Ssimokawa /* free extbuf */ 235118293Ssimokawa fwdev_freebuf(ir); 236118293Ssimokawa /* drain receiving buffer */ 237118293Ssimokawa for (xfer = STAILQ_FIRST(&ir->q); 238272214Skan xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) { 239272214Skan ir->queued--; 240118293Ssimokawa STAILQ_REMOVE_HEAD(&ir->q, link); 241118293Ssimokawa 242118293Ssimokawa xfer->resp = 0; 243118293Ssimokawa fw_xfer_done(xfer); 244118293Ssimokawa } 245272214Skan ir->flag &= ~(FWXFERQ_OPEN | FWXFERQ_MODEMASK | 246272214Skan FWXFERQ_CHTAGMASK); 247118293Ssimokawa d->ir = NULL; 248118293Ssimokawa 249106813Ssimokawa } 250118293Ssimokawa if (d->it != NULL) { 251118293Ssimokawa struct fw_xferq *it = d->it; 252106813Ssimokawa 253118293Ssimokawa if ((it->flag & FWXFERQ_OPEN) == 0) 254118293Ssimokawa return (EINVAL); 255118293Ssimokawa if (it->flag & FWXFERQ_RUNNING) { 256118293Ssimokawa it->flag &= ~FWXFERQ_RUNNING; 257118293Ssimokawa fc->itx_disable(fc, it->dmach); 258118293Ssimokawa } 259118293Ssimokawa /* free extbuf */ 260118293Ssimokawa fwdev_freebuf(it); 261118293Ssimokawa it->flag &= ~(FWXFERQ_OPEN | 262272214Skan FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 263118293Ssimokawa d->it = NULL; 264106813Ssimokawa } 265118293Ssimokawa free(dev->si_drv1, M_FW); 266118293Ssimokawa dev->si_drv1 = NULL; 267106813Ssimokawa 268106813Ssimokawa return err; 269106813Ssimokawa} 270106813Ssimokawa 271169130Ssimokawastatic int 272169130Ssimokawafw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 273169130Ssimokawa{ 274169130Ssimokawa int err = 0, s; 275169130Ssimokawa struct fw_xfer *xfer; 276169130Ssimokawa struct fw_bind *fwb; 277169130Ssimokawa struct fw_pkt *fp; 278169130Ssimokawa struct tcode_info *tinfo; 279169130Ssimokawa 280170374Ssimokawa FW_GLOCK(d->fc); 281169130Ssimokawa while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == 0) 282170374Ssimokawa err = msleep(&d->rq, FW_GMTX(d->fc), FWPRI, "fwra", 0); 283169130Ssimokawa 284170374Ssimokawa if (err != 0) { 285170374Ssimokawa FW_GUNLOCK(d->fc); 286169130Ssimokawa return (err); 287170374Ssimokawa } 288169130Ssimokawa 289169130Ssimokawa s = splfw(); 290169130Ssimokawa STAILQ_REMOVE_HEAD(&d->rq, link); 291170374Ssimokawa FW_GUNLOCK(xfer->fc); 292169130Ssimokawa splx(s); 293169130Ssimokawa fp = &xfer->recv.hdr; 294169130Ssimokawa#if 0 /* for GASP ?? */ 295169130Ssimokawa if (fc->irx_post != NULL) 296169130Ssimokawa fc->irx_post(fc, fp->mode.ld); 297169130Ssimokawa#endif 298169130Ssimokawa tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode]; 299272214Skan err = uiomove(fp, tinfo->hdr_len, uio); 300169130Ssimokawa if (err) 301169130Ssimokawa goto out; 302272214Skan err = uiomove(xfer->recv.payload, xfer->recv.pay_len, uio); 303169130Ssimokawa 304169130Ssimokawaout: 305169130Ssimokawa /* recycle this xfer */ 306169130Ssimokawa fwb = (struct fw_bind *)xfer->sc; 307169130Ssimokawa fw_xfer_unload(xfer); 308169130Ssimokawa xfer->recv.pay_len = PAGE_SIZE; 309170374Ssimokawa FW_GLOCK(xfer->fc); 310169130Ssimokawa STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 311170374Ssimokawa FW_GUNLOCK(xfer->fc); 312169130Ssimokawa return (err); 313169130Ssimokawa} 314169130Ssimokawa 315106813Ssimokawa/* 316106813Ssimokawa * read request. 317106813Ssimokawa */ 318106813Ssimokawastatic int 319272214Skanfw_read(struct cdev *dev, struct uio *uio, int ioflag) 320106813Ssimokawa{ 321169130Ssimokawa struct fw_drv1 *d; 322106813Ssimokawa struct fw_xferq *ir; 323169130Ssimokawa struct firewire_comm *fc; 324106813Ssimokawa int err = 0, s, slept = 0; 325106813Ssimokawa struct fw_pkt *fp; 326106813Ssimokawa 327106813Ssimokawa if (DEV_FWMEM(dev)) 328170374Ssimokawa return (physio(dev, uio, ioflag)); 329106813Ssimokawa 330272214Skan d = dev->si_drv1; 331169130Ssimokawa fc = d->fc; 332169130Ssimokawa ir = d->ir; 333169130Ssimokawa 334169130Ssimokawa if (ir == NULL) 335169130Ssimokawa return (fw_read_async(d, uio, ioflag)); 336169130Ssimokawa 337169130Ssimokawa if (ir->buf == NULL) 338118293Ssimokawa return (EIO); 339106813Ssimokawa 340170374Ssimokawa FW_GLOCK(fc); 341106813Ssimokawareadloop: 342113584Ssimokawa if (ir->stproc == NULL) { 343109988Ssimokawa /* iso bulkxfer */ 344106813Ssimokawa ir->stproc = STAILQ_FIRST(&ir->stvalid); 345109988Ssimokawa if (ir->stproc != NULL) { 346106813Ssimokawa s = splfw(); 347106813Ssimokawa STAILQ_REMOVE_HEAD(&ir->stvalid, link); 348106813Ssimokawa splx(s); 349106813Ssimokawa ir->queued = 0; 350106813Ssimokawa } 351106813Ssimokawa } 352169130Ssimokawa if (ir->stproc == NULL) { 353109988Ssimokawa /* no data avaliable */ 354109988Ssimokawa if (slept == 0) { 355106813Ssimokawa slept = 1; 356106813Ssimokawa ir->flag |= FWXFERQ_WAKEUP; 357170374Ssimokawa err = msleep(ir, FW_GMTX(fc), FWPRI, "fw_read", hz); 358109988Ssimokawa ir->flag &= ~FWXFERQ_WAKEUP; 359109988Ssimokawa if (err == 0) 360109988Ssimokawa goto readloop; 361109988Ssimokawa } else if (slept == 1) 362106813Ssimokawa err = EIO; 363170374Ssimokawa FW_GUNLOCK(fc); 364109988Ssimokawa return err; 365272214Skan } else if (ir->stproc != NULL) { 366109988Ssimokawa /* iso bulkxfer */ 367170374Ssimokawa FW_GUNLOCK(fc); 368272214Skan fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 369272214Skan ir->stproc->poffset + ir->queued); 370272214Skan if (fc->irx_post != NULL) 371169130Ssimokawa fc->irx_post(fc, fp->mode.ld); 372272214Skan if (fp->mode.stream.len == 0) { 373106813Ssimokawa err = EIO; 374106813Ssimokawa return err; 375106813Ssimokawa } 376109988Ssimokawa err = uiomove((caddr_t)fp, 377129585Sdfr fp->mode.stream.len + sizeof(uint32_t), uio); 378272214Skan ir->queued++; 379272214Skan if (ir->queued >= ir->bnpacket) { 380106813Ssimokawa s = splfw(); 381106813Ssimokawa STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 382106813Ssimokawa splx(s); 383169130Ssimokawa fc->irx_enable(fc, ir->dmach); 384106813Ssimokawa ir->stproc = NULL; 385106813Ssimokawa } 386109988Ssimokawa if (uio->uio_resid >= ir->psize) { 387109988Ssimokawa slept = -1; 388170374Ssimokawa FW_GLOCK(fc); 389109988Ssimokawa goto readloop; 390109988Ssimokawa } 391106813Ssimokawa } 392106813Ssimokawa return err; 393106813Ssimokawa} 394106813Ssimokawa 395106813Ssimokawastatic int 396169130Ssimokawafw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 397169130Ssimokawa{ 398169130Ssimokawa struct fw_xfer *xfer; 399169130Ssimokawa struct fw_pkt pkt; 400169130Ssimokawa struct tcode_info *tinfo; 401169130Ssimokawa int err; 402169130Ssimokawa 403169130Ssimokawa bzero(&pkt, sizeof(struct fw_pkt)); 404169130Ssimokawa if ((err = uiomove((caddr_t)&pkt, sizeof(uint32_t), uio))) 405169130Ssimokawa return (err); 406169130Ssimokawa tinfo = &d->fc->tcode[pkt.mode.hdr.tcode]; 407169130Ssimokawa if ((err = uiomove((caddr_t)&pkt + sizeof(uint32_t), 408169130Ssimokawa tinfo->hdr_len - sizeof(uint32_t), uio))) 409169130Ssimokawa return (err); 410169130Ssimokawa 411169130Ssimokawa if ((xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid, 412169130Ssimokawa PAGE_SIZE/*XXX*/)) == NULL) 413169130Ssimokawa return (ENOMEM); 414169130Ssimokawa 415169130Ssimokawa bcopy(&pkt, &xfer->send.hdr, sizeof(struct fw_pkt)); 416169130Ssimokawa xfer->send.pay_len = uio->uio_resid; 417169130Ssimokawa if (uio->uio_resid > 0) { 418169130Ssimokawa if ((err = uiomove((caddr_t)&xfer->send.payload[0], 419194687Srdivacky uio->uio_resid, uio))) 420169130Ssimokawa goto out; 421169130Ssimokawa } 422169130Ssimokawa 423169130Ssimokawa xfer->fc = d->fc; 424169130Ssimokawa xfer->sc = NULL; 425170374Ssimokawa xfer->hand = fw_xferwake; 426169130Ssimokawa xfer->send.spd = 2 /* XXX */; 427169130Ssimokawa 428169130Ssimokawa if ((err = fw_asyreq(xfer->fc, -1, xfer))) 429169130Ssimokawa goto out; 430169130Ssimokawa 431170374Ssimokawa if ((err = fw_xferwait(xfer))) 432169130Ssimokawa goto out; 433169130Ssimokawa 434169130Ssimokawa if (xfer->resp != 0) { 435169130Ssimokawa err = xfer->resp; 436169130Ssimokawa goto out; 437169130Ssimokawa } 438169130Ssimokawa 439170374Ssimokawa if (xfer->flag & FWXF_RCVD) { 440170374Ssimokawa FW_GLOCK(xfer->fc); 441169130Ssimokawa STAILQ_INSERT_TAIL(&d->rq, xfer, link); 442170374Ssimokawa FW_GUNLOCK(xfer->fc); 443169130Ssimokawa return (0); 444169130Ssimokawa } 445169130Ssimokawa 446169130Ssimokawaout: 447169130Ssimokawa fw_xfer_free(xfer); 448169130Ssimokawa return (err); 449169130Ssimokawa} 450169130Ssimokawa 451169130Ssimokawastatic int 452272214Skanfw_write(struct cdev *dev, struct uio *uio, int ioflag) 453106813Ssimokawa{ 454106813Ssimokawa int err = 0; 455106813Ssimokawa int s, slept = 0; 456169130Ssimokawa struct fw_drv1 *d; 457106813Ssimokawa struct fw_pkt *fp; 458106813Ssimokawa struct firewire_comm *fc; 459106813Ssimokawa struct fw_xferq *it; 460106813Ssimokawa 461106813Ssimokawa if (DEV_FWMEM(dev)) 462170374Ssimokawa return (physio(dev, uio, ioflag)); 463106813Ssimokawa 464272214Skan d = dev->si_drv1; 465169130Ssimokawa fc = d->fc; 466169130Ssimokawa it = d->it; 467169130Ssimokawa 468169130Ssimokawa if (it == NULL) 469169130Ssimokawa return (fw_write_async(d, uio, ioflag)); 470169130Ssimokawa 471169130Ssimokawa if (it->buf == NULL) 472118293Ssimokawa return (EIO); 473170374Ssimokawa 474170374Ssimokawa FW_GLOCK(fc); 475106813Ssimokawaisoloop: 476113802Ssimokawa if (it->stproc == NULL) { 477113802Ssimokawa it->stproc = STAILQ_FIRST(&it->stfree); 478113802Ssimokawa if (it->stproc != NULL) { 479106813Ssimokawa s = splfw(); 480113802Ssimokawa STAILQ_REMOVE_HEAD(&it->stfree, link); 481106813Ssimokawa splx(s); 482113802Ssimokawa it->queued = 0; 483113802Ssimokawa } else if (slept == 0) { 484113802Ssimokawa slept = 1; 485170374Ssimokawa#if 0 /* XXX to avoid lock recursion */ 486169130Ssimokawa err = fc->itx_enable(fc, it->dmach); 487113802Ssimokawa if (err) 488170374Ssimokawa goto out; 489170374Ssimokawa#endif 490170374Ssimokawa err = msleep(it, FW_GMTX(fc), FWPRI, "fw_write", hz); 491113802Ssimokawa if (err) 492170374Ssimokawa goto out; 493109988Ssimokawa goto isoloop; 494113802Ssimokawa } else { 495113802Ssimokawa err = EIO; 496170374Ssimokawa goto out; 497106813Ssimokawa } 498106813Ssimokawa } 499170374Ssimokawa FW_GUNLOCK(fc); 500113802Ssimokawa fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 501113802Ssimokawa it->stproc->poffset + it->queued); 502113802Ssimokawa err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 503113802Ssimokawa err = uiomove((caddr_t)fp->mode.stream.payload, 504113802Ssimokawa fp->mode.stream.len, uio); 505272214Skan it->queued++; 506113802Ssimokawa if (it->queued >= it->bnpacket) { 507113802Ssimokawa s = splfw(); 508113802Ssimokawa STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 509113802Ssimokawa splx(s); 510113802Ssimokawa it->stproc = NULL; 511169130Ssimokawa err = fc->itx_enable(fc, it->dmach); 512113802Ssimokawa } 513113802Ssimokawa if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 514113802Ssimokawa slept = 0; 515170374Ssimokawa FW_GLOCK(fc); 516113802Ssimokawa goto isoloop; 517113802Ssimokawa } 518113802Ssimokawa return err; 519170374Ssimokawa 520170374Ssimokawaout: 521170374Ssimokawa FW_GUNLOCK(fc); 522170374Ssimokawa return err; 523106813Ssimokawa} 524169130Ssimokawa 525169130Ssimokawastatic void 526169130Ssimokawafw_hand(struct fw_xfer *xfer) 527169130Ssimokawa{ 528169130Ssimokawa struct fw_bind *fwb; 529169130Ssimokawa struct fw_drv1 *d; 530169130Ssimokawa 531169130Ssimokawa fwb = (struct fw_bind *)xfer->sc; 532272214Skan d = fwb->sc; 533170374Ssimokawa FW_GLOCK(xfer->fc); 534169130Ssimokawa STAILQ_INSERT_TAIL(&d->rq, xfer, link); 535170374Ssimokawa FW_GUNLOCK(xfer->fc); 536169130Ssimokawa wakeup(&d->rq); 537169130Ssimokawa} 538169130Ssimokawa 539106813Ssimokawa/* 540106813Ssimokawa * ioctl support. 541106813Ssimokawa */ 542106813Ssimokawaint 543272214Skanfw_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 544106813Ssimokawa{ 545118293Ssimokawa struct firewire_comm *fc; 546118293Ssimokawa struct fw_drv1 *d; 547169130Ssimokawa int i, len, err = 0; 548106813Ssimokawa struct fw_device *fwdev; 549106813Ssimokawa struct fw_bind *fwb; 550106813Ssimokawa struct fw_xferq *ir, *it; 551106813Ssimokawa struct fw_xfer *xfer; 552106813Ssimokawa struct fw_pkt *fp; 553109814Ssimokawa struct fw_devinfo *devinfo; 554117473Ssimokawa void *ptr; 555106813Ssimokawa 556106813Ssimokawa struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 557106813Ssimokawa struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 558106813Ssimokawa struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 559106813Ssimokawa struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 560106813Ssimokawa struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 561106813Ssimokawa struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 562106813Ssimokawa 563106813Ssimokawa if (DEV_FWMEM(dev)) 564106813Ssimokawa return fwmem_ioctl(dev, cmd, data, flag, td); 565106813Ssimokawa 566106813Ssimokawa if (!data) 567272214Skan return (EINVAL); 568106813Ssimokawa 569272214Skan d = dev->si_drv1; 570169130Ssimokawa fc = d->fc; 571118293Ssimokawa ir = d->ir; 572118293Ssimokawa it = d->it; 573118293Ssimokawa 574106813Ssimokawa switch (cmd) { 575106813Ssimokawa case FW_STSTREAM: 576118293Ssimokawa if (it == NULL) { 577170374Ssimokawa i = fw_open_isodma(fc, /* tx */1); 578170374Ssimokawa if (i < 0) { 579118293Ssimokawa err = EBUSY; 580118293Ssimokawa break; 581118293Ssimokawa } 582170374Ssimokawa it = fc->it[i]; 583118293Ssimokawa err = fwdev_allocbuf(fc, it, &d->bufreq.tx); 584170374Ssimokawa if (err) { 585170374Ssimokawa it->flag &= ~FWXFERQ_OPEN; 586118293Ssimokawa break; 587170374Ssimokawa } 588118293Ssimokawa } 589118293Ssimokawa it->flag &= ~0xff; 590118293Ssimokawa it->flag |= (0x3f & ichreq->ch); 591118293Ssimokawa it->flag |= ((0x3 & ichreq->tag) << 6); 592118293Ssimokawa d->it = it; 593106813Ssimokawa break; 594106813Ssimokawa case FW_GTSTREAM: 595118293Ssimokawa if (it != NULL) { 596118293Ssimokawa ichreq->ch = it->flag & 0x3f; 597118293Ssimokawa ichreq->tag = it->flag >> 2 & 0x3; 598118293Ssimokawa } else 599118293Ssimokawa err = EINVAL; 600106813Ssimokawa break; 601106813Ssimokawa case FW_SRSTREAM: 602118293Ssimokawa if (ir == NULL) { 603170374Ssimokawa i = fw_open_isodma(fc, /* tx */0); 604170374Ssimokawa if (i < 0) { 605118293Ssimokawa err = EBUSY; 606118293Ssimokawa break; 607118293Ssimokawa } 608170374Ssimokawa ir = fc->ir[i]; 609118293Ssimokawa err = fwdev_allocbuf(fc, ir, &d->bufreq.rx); 610170374Ssimokawa if (err) { 611170374Ssimokawa ir->flag &= ~FWXFERQ_OPEN; 612118293Ssimokawa break; 613170374Ssimokawa } 614118293Ssimokawa } 615118293Ssimokawa ir->flag &= ~0xff; 616118293Ssimokawa ir->flag |= (0x3f & ichreq->ch); 617118293Ssimokawa ir->flag |= ((0x3 & ichreq->tag) << 6); 618118293Ssimokawa d->ir = ir; 619118293Ssimokawa err = fc->irx_enable(fc, ir->dmach); 620106813Ssimokawa break; 621106813Ssimokawa case FW_GRSTREAM: 622118293Ssimokawa if (d->ir != NULL) { 623118293Ssimokawa ichreq->ch = ir->flag & 0x3f; 624118293Ssimokawa ichreq->tag = ir->flag >> 2 & 0x3; 625118293Ssimokawa } else 626118293Ssimokawa err = EINVAL; 627106813Ssimokawa break; 628106813Ssimokawa case FW_SSTBUF: 629118293Ssimokawa bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq)); 630106813Ssimokawa break; 631106813Ssimokawa case FW_GSTBUF: 632118293Ssimokawa bzero(&ibufreq->rx, sizeof(ibufreq->rx)); 633118293Ssimokawa if (ir != NULL) { 634118293Ssimokawa ibufreq->rx.nchunk = ir->bnchunk; 635118293Ssimokawa ibufreq->rx.npacket = ir->bnpacket; 636118293Ssimokawa ibufreq->rx.psize = ir->psize; 637118293Ssimokawa } 638118293Ssimokawa bzero(&ibufreq->tx, sizeof(ibufreq->tx)); 639118293Ssimokawa if (it != NULL) { 640118293Ssimokawa ibufreq->tx.nchunk = it->bnchunk; 641118293Ssimokawa ibufreq->tx.npacket = it->bnpacket; 642118293Ssimokawa ibufreq->tx.psize = it->psize; 643118293Ssimokawa } 644106813Ssimokawa break; 645106813Ssimokawa case FW_ASYREQ: 646120660Ssimokawa { 647120660Ssimokawa struct tcode_info *tinfo; 648121466Ssimokawa int pay_len = 0; 649120660Ssimokawa 650106813Ssimokawa fp = &asyreq->pkt; 651169130Ssimokawa tinfo = &fc->tcode[fp->mode.hdr.tcode]; 652121466Ssimokawa 653121466Ssimokawa if ((tinfo->flag & FWTI_BLOCK_ASY) != 0) 654121466Ssimokawa pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len); 655121466Ssimokawa 656121466Ssimokawa xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/); 657121466Ssimokawa if (xfer == NULL) 658121466Ssimokawa return (ENOMEM); 659121466Ssimokawa 660106813Ssimokawa switch (asyreq->req.type) { 661106813Ssimokawa case FWASREQNODE: 662106813Ssimokawa break; 663106813Ssimokawa case FWASREQEUI: 664169130Ssimokawa fwdev = fw_noderesolve_eui64(fc, 665110582Ssimokawa &asyreq->req.dst.eui); 666106813Ssimokawa if (fwdev == NULL) { 667169130Ssimokawa device_printf(fc->bdev, 668108782Ssimokawa "cannot find node\n"); 669106813Ssimokawa err = EINVAL; 670121466Ssimokawa goto out; 671106813Ssimokawa } 672120660Ssimokawa fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst; 673106813Ssimokawa break; 674106813Ssimokawa case FWASRESTL: 675106813Ssimokawa /* XXX what's this? */ 676106813Ssimokawa break; 677106813Ssimokawa case FWASREQSTREAM: 678106813Ssimokawa /* nothing to do */ 679106813Ssimokawa break; 680106813Ssimokawa } 681121466Ssimokawa 682120660Ssimokawa bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len); 683121466Ssimokawa if (pay_len > 0) 684120660Ssimokawa bcopy((char *)fp + tinfo->hdr_len, 685272214Skan xfer->send.payload, pay_len); 686121466Ssimokawa xfer->send.spd = asyreq->req.sped; 687170374Ssimokawa xfer->hand = fw_xferwake; 688121466Ssimokawa 689169130Ssimokawa if ((err = fw_asyreq(fc, -1, xfer)) != 0) 690121466Ssimokawa goto out; 691170374Ssimokawa if ((err = fw_xferwait(xfer)) != 0) 692121466Ssimokawa goto out; 693121466Ssimokawa if (xfer->resp != 0) { 694121466Ssimokawa err = EIO; 695121466Ssimokawa goto out; 696106813Ssimokawa } 697121466Ssimokawa if ((tinfo->flag & FWTI_TLABEL) == 0) 698121466Ssimokawa goto out; 699121466Ssimokawa 700121466Ssimokawa /* copy response */ 701169130Ssimokawa tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode]; 702129628Sdfr if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB || 703129628Sdfr xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) { 704129628Sdfr pay_len = xfer->recv.pay_len; 705129628Sdfr if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) { 706129628Sdfr asyreq->req.len = xfer->recv.pay_len + 707272214Skan tinfo->hdr_len; 708129628Sdfr } else { 709129628Sdfr err = EINVAL; 710129628Sdfr pay_len = 0; 711129628Sdfr } 712129628Sdfr } else { 713129628Sdfr pay_len = 0; 714129628Sdfr } 715121466Ssimokawa bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len); 716129628Sdfr bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, pay_len); 717121466Ssimokawaout: 718120660Ssimokawa fw_xfer_free_buf(xfer); 719106813Ssimokawa break; 720120660Ssimokawa } 721106813Ssimokawa case FW_IBUSRST: 722169130Ssimokawa fc->ibr(fc); 723106813Ssimokawa break; 724106813Ssimokawa case FW_CBINDADDR: 725169130Ssimokawa fwb = fw_bindlookup(fc, 726106813Ssimokawa bindreq->start.hi, bindreq->start.lo); 727272214Skan if (fwb == NULL) { 728106813Ssimokawa err = EINVAL; 729106813Ssimokawa break; 730106813Ssimokawa } 731169130Ssimokawa fw_bindremove(fc, fwb); 732169130Ssimokawa STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist); 733169130Ssimokawa fw_xferlist_remove(&fwb->xferlist); 734110195Ssimokawa free(fwb, M_FW); 735106813Ssimokawa break; 736106813Ssimokawa case FW_SBINDADDR: 737272214Skan if (bindreq->len <= 0) { 738106813Ssimokawa err = EINVAL; 739106813Ssimokawa break; 740106813Ssimokawa } 741272214Skan if (bindreq->start.hi > 0xffff) { 742106813Ssimokawa err = EINVAL; 743106813Ssimokawa break; 744106813Ssimokawa } 745272214Skan fwb = malloc(sizeof(struct fw_bind), M_FW, M_WAITOK); 746272214Skan if (fwb == NULL) { 747106813Ssimokawa err = ENOMEM; 748106813Ssimokawa break; 749106813Ssimokawa } 750120660Ssimokawa fwb->start = ((u_int64_t)bindreq->start.hi << 32) | 751120660Ssimokawa bindreq->start.lo; 752120660Ssimokawa fwb->end = fwb->start + bindreq->len; 753272214Skan fwb->sc = d; 754169130Ssimokawa STAILQ_INIT(&fwb->xferlist); 755169130Ssimokawa err = fw_bindadd(fc, fwb); 756169130Ssimokawa if (err == 0) { 757169130Ssimokawa fw_xferlist_add(&fwb->xferlist, M_FWXFER, 758169130Ssimokawa /* XXX */ 759169130Ssimokawa PAGE_SIZE, PAGE_SIZE, 5, 760272214Skan fc, fwb, fw_hand); 761169130Ssimokawa STAILQ_INSERT_TAIL(&d->binds, fwb, chlist); 762106813Ssimokawa } 763106813Ssimokawa break; 764106813Ssimokawa case FW_GDEVLST: 765109814Ssimokawa i = len = 1; 766109814Ssimokawa /* myself */ 767109814Ssimokawa devinfo = &fwdevlst->dev[0]; 768169130Ssimokawa devinfo->dst = fc->nodeid; 769109814Ssimokawa devinfo->status = 0; /* XXX */ 770169130Ssimokawa devinfo->eui.hi = fc->eui.hi; 771169130Ssimokawa devinfo->eui.lo = fc->eui.lo; 772169130Ssimokawa STAILQ_FOREACH(fwdev, &fc->devices, link) { 773272214Skan if (len < FW_MAX_DEVLST) { 774109814Ssimokawa devinfo = &fwdevlst->dev[len++]; 775109814Ssimokawa devinfo->dst = fwdev->dst; 776272214Skan devinfo->status = 777272214Skan (fwdev->status == FWDEVINVAL) ? 0 : 1; 778109814Ssimokawa devinfo->eui.hi = fwdev->eui.hi; 779109814Ssimokawa devinfo->eui.lo = fwdev->eui.lo; 780106813Ssimokawa } 781106813Ssimokawa i++; 782106813Ssimokawa } 783106813Ssimokawa fwdevlst->n = i; 784109814Ssimokawa fwdevlst->info_len = len; 785106813Ssimokawa break; 786106813Ssimokawa case FW_GTPMAP: 787169130Ssimokawa bcopy(fc->topology_map, data, 788272214Skan (fc->topology_map->crc_len + 1) * 4); 789106813Ssimokawa break; 790106813Ssimokawa case FW_GCROM: 791169130Ssimokawa STAILQ_FOREACH(fwdev, &fc->devices, link) 792110193Ssimokawa if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 793106813Ssimokawa break; 794106813Ssimokawa if (fwdev == NULL) { 795169130Ssimokawa if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) { 796117473Ssimokawa err = FWNODE_INVAL; 797117473Ssimokawa break; 798117473Ssimokawa } 799117473Ssimokawa /* myself */ 800117473Ssimokawa ptr = malloc(CROMSIZE, M_FW, M_WAITOK); 801117473Ssimokawa len = CROMSIZE; 802117473Ssimokawa for (i = 0; i < CROMSIZE/4; i++) 803129585Sdfr ((uint32_t *)ptr)[i] 804169130Ssimokawa = ntohl(fc->config_rom[i]); 805117473Ssimokawa } else { 806117473Ssimokawa /* found */ 807117473Ssimokawa ptr = (void *)&fwdev->csrrom[0]; 808117473Ssimokawa if (fwdev->rommax < CSRROMOFF) 809117473Ssimokawa len = 0; 810117473Ssimokawa else 811117473Ssimokawa len = fwdev->rommax - CSRROMOFF + 4; 812106813Ssimokawa } 813169019Ssimokawa if (crom_buf->len < len) 814106813Ssimokawa len = crom_buf->len; 815106813Ssimokawa else 816106813Ssimokawa crom_buf->len = len; 817117473Ssimokawa err = copyout(ptr, crom_buf->ptr, len); 818117473Ssimokawa if (fwdev == NULL) 819117473Ssimokawa /* myself */ 820117473Ssimokawa free(ptr, M_FW); 821106813Ssimokawa break; 822106813Ssimokawa default: 823272214Skan fc->ioctl(dev, cmd, data, flag, td); 824106813Ssimokawa break; 825106813Ssimokawa } 826106813Ssimokawa return err; 827106813Ssimokawa} 828106813Ssimokawaint 829130585Sphkfw_poll(struct cdev *dev, int events, fw_proc *td) 830106813Ssimokawa{ 831118293Ssimokawa struct fw_xferq *ir; 832106813Ssimokawa int revents; 833106813Ssimokawa int tmp; 834106813Ssimokawa 835106813Ssimokawa if (DEV_FWMEM(dev)) 836106813Ssimokawa return fwmem_poll(dev, events, td); 837106813Ssimokawa 838118293Ssimokawa ir = ((struct fw_drv1 *)dev->si_drv1)->ir; 839106813Ssimokawa revents = 0; 840106813Ssimokawa tmp = POLLIN | POLLRDNORM; 841106813Ssimokawa if (events & tmp) { 842118293Ssimokawa if (STAILQ_FIRST(&ir->q) != NULL) 843106813Ssimokawa revents |= tmp; 844106813Ssimokawa else 845118293Ssimokawa selrecord(td, &ir->rsel); 846106813Ssimokawa } 847106813Ssimokawa tmp = POLLOUT | POLLWRNORM; 848106813Ssimokawa if (events & tmp) { 849272214Skan /* XXX should be fixed */ 850106813Ssimokawa revents |= tmp; 851106813Ssimokawa } 852106813Ssimokawa 853106813Ssimokawa return revents; 854106813Ssimokawa} 855106813Ssimokawa 856106813Ssimokawastatic int 857201223Srnolandfw_mmap (struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, 858201223Srnoland int nproto, vm_memattr_t *memattr) 859272214Skan{ 860106813Ssimokawa 861106813Ssimokawa if (DEV_FWMEM(dev)) 862201223Srnoland return fwmem_mmap(dev, offset, paddr, nproto, memattr); 863106813Ssimokawa 864106813Ssimokawa return EINVAL; 865106813Ssimokawa} 866118455Ssimokawa 867120660Ssimokawastatic void 868120660Ssimokawafw_strategy(struct bio *bp) 869120660Ssimokawa{ 870130585Sphk struct cdev *dev; 871120660Ssimokawa 872120660Ssimokawa dev = bp->bio_dev; 873120660Ssimokawa if (DEV_FWMEM(dev)) { 874120660Ssimokawa fwmem_strategy(bp); 875120660Ssimokawa return; 876120660Ssimokawa } 877120660Ssimokawa 878120660Ssimokawa bp->bio_error = EOPNOTSUPP; 879120660Ssimokawa bp->bio_flags |= BIO_ERROR; 880120660Ssimokawa bp->bio_resid = bp->bio_bcount; 881120660Ssimokawa biodone(bp); 882120660Ssimokawa} 883120660Ssimokawa 884118455Ssimokawaint 885118455Ssimokawafwdev_makedev(struct firewire_softc *sc) 886118455Ssimokawa{ 887118455Ssimokawa int err = 0; 888118455Ssimokawa 889130585Sphk struct cdev *d; 890118455Ssimokawa int unit; 891118455Ssimokawa 892118455Ssimokawa unit = device_get_unit(sc->fc->bdev); 893118455Ssimokawa sc->dev = make_dev(&firewire_cdevsw, MAKEMINOR(0, unit, 0), 894272214Skan UID_ROOT, GID_OPERATOR, 0660, "fw%d.%d", unit, 0); 895272214Skan d = make_dev(&firewire_cdevsw, MAKEMINOR(FWMEM_FLAG, unit, 0), 896272214Skan UID_ROOT, GID_OPERATOR, 0660, "fwmem%d.%d", unit, 0); 897118455Ssimokawa dev_depends(sc->dev, d); 898118455Ssimokawa make_dev_alias(sc->dev, "fw%d", unit); 899118455Ssimokawa make_dev_alias(d, "fwmem%d", unit); 900118455Ssimokawa 901118455Ssimokawa return (err); 902118455Ssimokawa} 903118455Ssimokawa 904118455Ssimokawaint 905118455Ssimokawafwdev_destroydev(struct firewire_softc *sc) 906118455Ssimokawa{ 907118455Ssimokawa int err = 0; 908118455Ssimokawa 909118455Ssimokawa destroy_dev(sc->dev); 910118455Ssimokawa return (err); 911118455Ssimokawa} 912118455Ssimokawa 913118455Ssimokawa#define NDEVTYPE 2 914118455Ssimokawavoid 915148868Srwatsonfwdev_clone(void *arg, struct ucred *cred, char *name, int namelen, 916148868Srwatson struct cdev **dev) 917118455Ssimokawa{ 918118455Ssimokawa struct firewire_softc *sc; 919118455Ssimokawa char *devnames[NDEVTYPE] = {"fw", "fwmem"}; 920118455Ssimokawa char *subp = NULL; 921118455Ssimokawa int devflag[NDEVTYPE] = {0, FWMEM_FLAG}; 922118455Ssimokawa int i, unit = 0, sub = 0; 923118455Ssimokawa 924130640Sphk if (*dev != NULL) 925118455Ssimokawa return; 926118455Ssimokawa 927118455Ssimokawa for (i = 0; i < NDEVTYPE; i++) 928120624Ssimokawa if (dev_stdclone(name, &subp, devnames[i], &unit) == 2) 929118455Ssimokawa goto found; 930118455Ssimokawa /* not match */ 931118455Ssimokawa return; 932118455Ssimokawafound: 933118455Ssimokawa 934118455Ssimokawa if (subp == NULL || *subp++ != '.') 935118455Ssimokawa return; 936118455Ssimokawa 937118455Ssimokawa /* /dev/fwU.S */ 938118455Ssimokawa while (isdigit(*subp)) { 939118455Ssimokawa sub *= 10; 940118455Ssimokawa sub += *subp++ - '0'; 941118455Ssimokawa } 942118455Ssimokawa if (*subp != '\0') 943118455Ssimokawa return; 944118455Ssimokawa 945118455Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 946118455Ssimokawa if (sc == NULL) 947118455Ssimokawa return; 948255359Sdavide *dev = make_dev_credf(MAKEDEV_REF, &firewire_cdevsw, 949255359Sdavide MAKEMINOR(devflag[i], unit, sub), cred, UID_ROOT, GID_OPERATOR, 950255359Sdavide 0660, "%s%d.%d", devnames[i], unit, sub); 951118455Ssimokawa dev_depends(sc->dev, *dev); 952118455Ssimokawa return; 953118455Ssimokawa} 954