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$ 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", 83106813Ssimokawa}; 84106813Ssimokawa 85118293Ssimokawastruct fw_drv1 { 86169130Ssimokawa struct firewire_comm *fc; 87118293Ssimokawa struct fw_xferq *ir; 88118293Ssimokawa struct fw_xferq *it; 89118293Ssimokawa struct fw_isobufreq bufreq; 90169130Ssimokawa STAILQ_HEAD(, fw_bind) binds; 91169130Ssimokawa STAILQ_HEAD(, fw_xfer) rq; 92118293Ssimokawa}; 93118293Ssimokawa 94106813Ssimokawastatic int 95118293Ssimokawafwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q, 96118293Ssimokawa struct fw_bufspec *b) 97118293Ssimokawa{ 98118293Ssimokawa int i; 99118293Ssimokawa 100118293Ssimokawa if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF)) 101272214Skan return (EBUSY); 102118293Ssimokawa 103272214Skan q->bulkxfer = malloc(sizeof(struct fw_bulkxfer) * b->nchunk, 104272214Skan M_FW, M_WAITOK); 105118293Ssimokawa 106129585Sdfr b->psize = roundup2(b->psize, sizeof(uint32_t)); 107129585Sdfr q->buf = fwdma_malloc_multiseg(fc, sizeof(uint32_t), 108272214Skan b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK); 109118293Ssimokawa 110118293Ssimokawa if (q->buf == NULL) { 111118293Ssimokawa free(q->bulkxfer, M_FW); 112118293Ssimokawa q->bulkxfer = NULL; 113272214Skan return (ENOMEM); 114118293Ssimokawa } 115118293Ssimokawa q->bnchunk = b->nchunk; 116118293Ssimokawa q->bnpacket = b->npacket; 117118293Ssimokawa q->psize = (b->psize + 3) & ~3; 118118293Ssimokawa q->queued = 0; 119118293Ssimokawa 120118293Ssimokawa STAILQ_INIT(&q->stvalid); 121118293Ssimokawa STAILQ_INIT(&q->stfree); 122118293Ssimokawa STAILQ_INIT(&q->stdma); 123118293Ssimokawa q->stproc = NULL; 124118293Ssimokawa 125272214Skan for (i = 0; i < q->bnchunk; i++) { 126118293Ssimokawa q->bulkxfer[i].poffset = i * q->bnpacket; 127118293Ssimokawa q->bulkxfer[i].mbuf = NULL; 128118293Ssimokawa STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link); 129118293Ssimokawa } 130118293Ssimokawa 131118293Ssimokawa q->flag &= ~FWXFERQ_MODEMASK; 132118293Ssimokawa q->flag |= FWXFERQ_STREAM; 133118293Ssimokawa q->flag |= FWXFERQ_EXTBUF; 134118293Ssimokawa 135118293Ssimokawa return (0); 136118293Ssimokawa} 137118293Ssimokawa 138118293Ssimokawastatic int 139118293Ssimokawafwdev_freebuf(struct fw_xferq *q) 140118293Ssimokawa{ 141118293Ssimokawa if (q->flag & FWXFERQ_EXTBUF) { 142118293Ssimokawa if (q->buf != NULL) 143118293Ssimokawa fwdma_free_multiseg(q->buf); 144118293Ssimokawa q->buf = NULL; 145118293Ssimokawa free(q->bulkxfer, M_FW); 146118293Ssimokawa q->bulkxfer = NULL; 147118293Ssimokawa q->flag &= ~FWXFERQ_EXTBUF; 148118293Ssimokawa q->psize = 0; 149118293Ssimokawa q->maxq = FWMAXQUEUE; 150118293Ssimokawa } 151118293Ssimokawa return (0); 152118293Ssimokawa} 153118293Ssimokawa 154118293Ssimokawa 155118293Ssimokawastatic int 156272214Skanfw_open(struct cdev *dev, int flags, int fmt, fw_proc *td) 157106813Ssimokawa{ 158106813Ssimokawa int err = 0; 159169130Ssimokawa int unit = DEV2UNIT(dev); 160169130Ssimokawa struct fw_drv1 *d; 161169130Ssimokawa struct firewire_softc *sc; 162106813Ssimokawa 163122227Ssimokawa if (DEV_FWMEM(dev)) 164122227Ssimokawa return fwmem_open(dev, flags, fmt, td); 165122227Ssimokawa 166170374Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 167170374Ssimokawa if (sc == NULL) 168170374Ssimokawa return (ENXIO); 169170374Ssimokawa 170170374Ssimokawa FW_GLOCK(sc->fc); 171170374Ssimokawa if (dev->si_drv1 != NULL) { 172170374Ssimokawa FW_GUNLOCK(sc->fc); 173118293Ssimokawa return (EBUSY); 174170374Ssimokawa } 175170374Ssimokawa /* set dummy value for allocation */ 176170374Ssimokawa dev->si_drv1 = (void *)-1; 177170374Ssimokawa FW_GUNLOCK(sc->fc); 178118293Ssimokawa 179170374Ssimokawa dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); 180170374Ssimokawa 181118455Ssimokawa if ((dev->si_flags & SI_NAMED) == 0) { 182118455Ssimokawa int unit = DEV2UNIT(dev); 183118455Ssimokawa int sub = DEV2SUB(dev); 184118455Ssimokawa 185183397Sed make_dev(&firewire_cdevsw, dev2unit(dev), 186272214Skan UID_ROOT, GID_OPERATOR, 0660, "fw%d.%d", unit, sub); 187118455Ssimokawa } 188272214Skan 189272214Skan d = dev->si_drv1; 190169130Ssimokawa d->fc = sc->fc; 191169130Ssimokawa STAILQ_INIT(&d->binds); 192169130Ssimokawa STAILQ_INIT(&d->rq); 193169130Ssimokawa 194106813Ssimokawa return err; 195106813Ssimokawa} 196106813Ssimokawa 197106813Ssimokawastatic int 198272214Skanfw_close(struct cdev *dev, int flags, int fmt, fw_proc *td) 199106813Ssimokawa{ 200118293Ssimokawa struct firewire_comm *fc; 201118293Ssimokawa struct fw_drv1 *d; 202106813Ssimokawa struct fw_xfer *xfer; 203106813Ssimokawa struct fw_bind *fwb; 204106813Ssimokawa int err = 0; 205106813Ssimokawa 206106813Ssimokawa if (DEV_FWMEM(dev)) 207106813Ssimokawa return fwmem_close(dev, flags, fmt, td); 208106813Ssimokawa 209272214Skan d = dev->si_drv1; 210169130Ssimokawa fc = d->fc; 211118293Ssimokawa 212169130Ssimokawa /* remove binding */ 213169130Ssimokawa for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL; 214272214Skan fwb = STAILQ_FIRST(&d->binds)) { 215169130Ssimokawa fw_bindremove(fc, fwb); 216169130Ssimokawa STAILQ_REMOVE_HEAD(&d->binds, chlist); 217169130Ssimokawa fw_xferlist_remove(&fwb->xferlist); 218169130Ssimokawa free(fwb, M_FW); 219169130Ssimokawa } 220118293Ssimokawa if (d->ir != NULL) { 221118293Ssimokawa struct fw_xferq *ir = d->ir; 222118293Ssimokawa 223118293Ssimokawa if ((ir->flag & FWXFERQ_OPEN) == 0) 224118293Ssimokawa return (EINVAL); 225118293Ssimokawa if (ir->flag & FWXFERQ_RUNNING) { 226118293Ssimokawa ir->flag &= ~FWXFERQ_RUNNING; 227118293Ssimokawa fc->irx_disable(fc, ir->dmach); 228118293Ssimokawa } 229118293Ssimokawa /* free extbuf */ 230118293Ssimokawa fwdev_freebuf(ir); 231118293Ssimokawa /* drain receiving buffer */ 232118293Ssimokawa for (xfer = STAILQ_FIRST(&ir->q); 233272214Skan xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) { 234272214Skan ir->queued--; 235118293Ssimokawa STAILQ_REMOVE_HEAD(&ir->q, link); 236118293Ssimokawa 237118293Ssimokawa xfer->resp = 0; 238118293Ssimokawa fw_xfer_done(xfer); 239118293Ssimokawa } 240272214Skan ir->flag &= ~(FWXFERQ_OPEN | FWXFERQ_MODEMASK | 241272214Skan FWXFERQ_CHTAGMASK); 242118293Ssimokawa d->ir = NULL; 243118293Ssimokawa 244106813Ssimokawa } 245118293Ssimokawa if (d->it != NULL) { 246118293Ssimokawa struct fw_xferq *it = d->it; 247106813Ssimokawa 248118293Ssimokawa if ((it->flag & FWXFERQ_OPEN) == 0) 249118293Ssimokawa return (EINVAL); 250118293Ssimokawa if (it->flag & FWXFERQ_RUNNING) { 251118293Ssimokawa it->flag &= ~FWXFERQ_RUNNING; 252118293Ssimokawa fc->itx_disable(fc, it->dmach); 253118293Ssimokawa } 254118293Ssimokawa /* free extbuf */ 255118293Ssimokawa fwdev_freebuf(it); 256118293Ssimokawa it->flag &= ~(FWXFERQ_OPEN | 257272214Skan FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 258118293Ssimokawa d->it = NULL; 259106813Ssimokawa } 260118293Ssimokawa free(dev->si_drv1, M_FW); 261118293Ssimokawa dev->si_drv1 = NULL; 262106813Ssimokawa 263106813Ssimokawa return err; 264106813Ssimokawa} 265106813Ssimokawa 266169130Ssimokawastatic int 267169130Ssimokawafw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 268169130Ssimokawa{ 269169130Ssimokawa int err = 0, s; 270169130Ssimokawa struct fw_xfer *xfer; 271169130Ssimokawa struct fw_bind *fwb; 272169130Ssimokawa struct fw_pkt *fp; 273169130Ssimokawa struct tcode_info *tinfo; 274169130Ssimokawa 275170374Ssimokawa FW_GLOCK(d->fc); 276169130Ssimokawa while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == 0) 277170374Ssimokawa err = msleep(&d->rq, FW_GMTX(d->fc), FWPRI, "fwra", 0); 278169130Ssimokawa 279170374Ssimokawa if (err != 0) { 280170374Ssimokawa FW_GUNLOCK(d->fc); 281169130Ssimokawa return (err); 282170374Ssimokawa } 283169130Ssimokawa 284169130Ssimokawa s = splfw(); 285169130Ssimokawa STAILQ_REMOVE_HEAD(&d->rq, link); 286170374Ssimokawa FW_GUNLOCK(xfer->fc); 287169130Ssimokawa splx(s); 288169130Ssimokawa fp = &xfer->recv.hdr; 289169130Ssimokawa#if 0 /* for GASP ?? */ 290169130Ssimokawa if (fc->irx_post != NULL) 291169130Ssimokawa fc->irx_post(fc, fp->mode.ld); 292169130Ssimokawa#endif 293169130Ssimokawa tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode]; 294272214Skan err = uiomove(fp, tinfo->hdr_len, uio); 295169130Ssimokawa if (err) 296169130Ssimokawa goto out; 297272214Skan err = uiomove(xfer->recv.payload, xfer->recv.pay_len, uio); 298169130Ssimokawa 299169130Ssimokawaout: 300169130Ssimokawa /* recycle this xfer */ 301169130Ssimokawa fwb = (struct fw_bind *)xfer->sc; 302169130Ssimokawa fw_xfer_unload(xfer); 303169130Ssimokawa xfer->recv.pay_len = PAGE_SIZE; 304170374Ssimokawa FW_GLOCK(xfer->fc); 305169130Ssimokawa STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 306170374Ssimokawa FW_GUNLOCK(xfer->fc); 307169130Ssimokawa return (err); 308169130Ssimokawa} 309169130Ssimokawa 310106813Ssimokawa/* 311106813Ssimokawa * read request. 312106813Ssimokawa */ 313106813Ssimokawastatic int 314272214Skanfw_read(struct cdev *dev, struct uio *uio, int ioflag) 315106813Ssimokawa{ 316169130Ssimokawa struct fw_drv1 *d; 317106813Ssimokawa struct fw_xferq *ir; 318169130Ssimokawa struct firewire_comm *fc; 319106813Ssimokawa int err = 0, s, slept = 0; 320106813Ssimokawa struct fw_pkt *fp; 321106813Ssimokawa 322106813Ssimokawa if (DEV_FWMEM(dev)) 323170374Ssimokawa return (physio(dev, uio, ioflag)); 324106813Ssimokawa 325272214Skan d = dev->si_drv1; 326169130Ssimokawa fc = d->fc; 327169130Ssimokawa ir = d->ir; 328169130Ssimokawa 329169130Ssimokawa if (ir == NULL) 330169130Ssimokawa return (fw_read_async(d, uio, ioflag)); 331169130Ssimokawa 332169130Ssimokawa if (ir->buf == NULL) 333118293Ssimokawa return (EIO); 334106813Ssimokawa 335170374Ssimokawa FW_GLOCK(fc); 336106813Ssimokawareadloop: 337113584Ssimokawa if (ir->stproc == NULL) { 338109988Ssimokawa /* iso bulkxfer */ 339106813Ssimokawa ir->stproc = STAILQ_FIRST(&ir->stvalid); 340109988Ssimokawa if (ir->stproc != NULL) { 341106813Ssimokawa s = splfw(); 342106813Ssimokawa STAILQ_REMOVE_HEAD(&ir->stvalid, link); 343106813Ssimokawa splx(s); 344106813Ssimokawa ir->queued = 0; 345106813Ssimokawa } 346106813Ssimokawa } 347169130Ssimokawa if (ir->stproc == NULL) { 348298955Spfg /* no data available */ 349109988Ssimokawa if (slept == 0) { 350106813Ssimokawa slept = 1; 351106813Ssimokawa ir->flag |= FWXFERQ_WAKEUP; 352170374Ssimokawa err = msleep(ir, FW_GMTX(fc), FWPRI, "fw_read", hz); 353109988Ssimokawa ir->flag &= ~FWXFERQ_WAKEUP; 354109988Ssimokawa if (err == 0) 355109988Ssimokawa goto readloop; 356109988Ssimokawa } else if (slept == 1) 357106813Ssimokawa err = EIO; 358170374Ssimokawa FW_GUNLOCK(fc); 359109988Ssimokawa return err; 360272214Skan } else if (ir->stproc != NULL) { 361109988Ssimokawa /* iso bulkxfer */ 362170374Ssimokawa FW_GUNLOCK(fc); 363272214Skan fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 364272214Skan ir->stproc->poffset + ir->queued); 365272214Skan if (fc->irx_post != NULL) 366169130Ssimokawa fc->irx_post(fc, fp->mode.ld); 367272214Skan if (fp->mode.stream.len == 0) { 368106813Ssimokawa err = EIO; 369106813Ssimokawa return err; 370106813Ssimokawa } 371109988Ssimokawa err = uiomove((caddr_t)fp, 372129585Sdfr fp->mode.stream.len + sizeof(uint32_t), uio); 373272214Skan ir->queued++; 374272214Skan if (ir->queued >= ir->bnpacket) { 375106813Ssimokawa s = splfw(); 376106813Ssimokawa STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 377106813Ssimokawa splx(s); 378169130Ssimokawa fc->irx_enable(fc, ir->dmach); 379106813Ssimokawa ir->stproc = NULL; 380106813Ssimokawa } 381109988Ssimokawa if (uio->uio_resid >= ir->psize) { 382109988Ssimokawa slept = -1; 383170374Ssimokawa FW_GLOCK(fc); 384109988Ssimokawa goto readloop; 385109988Ssimokawa } 386106813Ssimokawa } 387106813Ssimokawa return err; 388106813Ssimokawa} 389106813Ssimokawa 390106813Ssimokawastatic int 391169130Ssimokawafw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 392169130Ssimokawa{ 393169130Ssimokawa struct fw_xfer *xfer; 394169130Ssimokawa struct fw_pkt pkt; 395169130Ssimokawa struct tcode_info *tinfo; 396169130Ssimokawa int err; 397169130Ssimokawa 398169130Ssimokawa bzero(&pkt, sizeof(struct fw_pkt)); 399169130Ssimokawa if ((err = uiomove((caddr_t)&pkt, sizeof(uint32_t), uio))) 400169130Ssimokawa return (err); 401169130Ssimokawa tinfo = &d->fc->tcode[pkt.mode.hdr.tcode]; 402169130Ssimokawa if ((err = uiomove((caddr_t)&pkt + sizeof(uint32_t), 403169130Ssimokawa tinfo->hdr_len - sizeof(uint32_t), uio))) 404169130Ssimokawa return (err); 405169130Ssimokawa 406169130Ssimokawa if ((xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid, 407169130Ssimokawa PAGE_SIZE/*XXX*/)) == NULL) 408169130Ssimokawa return (ENOMEM); 409169130Ssimokawa 410169130Ssimokawa bcopy(&pkt, &xfer->send.hdr, sizeof(struct fw_pkt)); 411169130Ssimokawa xfer->send.pay_len = uio->uio_resid; 412169130Ssimokawa if (uio->uio_resid > 0) { 413169130Ssimokawa if ((err = uiomove((caddr_t)&xfer->send.payload[0], 414194687Srdivacky uio->uio_resid, uio))) 415169130Ssimokawa goto out; 416169130Ssimokawa } 417169130Ssimokawa 418169130Ssimokawa xfer->fc = d->fc; 419169130Ssimokawa xfer->sc = NULL; 420170374Ssimokawa xfer->hand = fw_xferwake; 421169130Ssimokawa xfer->send.spd = 2 /* XXX */; 422169130Ssimokawa 423169130Ssimokawa if ((err = fw_asyreq(xfer->fc, -1, xfer))) 424169130Ssimokawa goto out; 425169130Ssimokawa 426170374Ssimokawa if ((err = fw_xferwait(xfer))) 427169130Ssimokawa goto out; 428169130Ssimokawa 429169130Ssimokawa if (xfer->resp != 0) { 430169130Ssimokawa err = xfer->resp; 431169130Ssimokawa goto out; 432169130Ssimokawa } 433169130Ssimokawa 434170374Ssimokawa if (xfer->flag & FWXF_RCVD) { 435170374Ssimokawa FW_GLOCK(xfer->fc); 436169130Ssimokawa STAILQ_INSERT_TAIL(&d->rq, xfer, link); 437170374Ssimokawa FW_GUNLOCK(xfer->fc); 438169130Ssimokawa return (0); 439169130Ssimokawa } 440169130Ssimokawa 441169130Ssimokawaout: 442169130Ssimokawa fw_xfer_free(xfer); 443169130Ssimokawa return (err); 444169130Ssimokawa} 445169130Ssimokawa 446169130Ssimokawastatic int 447272214Skanfw_write(struct cdev *dev, struct uio *uio, int ioflag) 448106813Ssimokawa{ 449106813Ssimokawa int err = 0; 450106813Ssimokawa int s, slept = 0; 451169130Ssimokawa struct fw_drv1 *d; 452106813Ssimokawa struct fw_pkt *fp; 453106813Ssimokawa struct firewire_comm *fc; 454106813Ssimokawa struct fw_xferq *it; 455106813Ssimokawa 456106813Ssimokawa if (DEV_FWMEM(dev)) 457170374Ssimokawa return (physio(dev, uio, ioflag)); 458106813Ssimokawa 459272214Skan d = dev->si_drv1; 460169130Ssimokawa fc = d->fc; 461169130Ssimokawa it = d->it; 462169130Ssimokawa 463169130Ssimokawa if (it == NULL) 464169130Ssimokawa return (fw_write_async(d, uio, ioflag)); 465169130Ssimokawa 466169130Ssimokawa if (it->buf == NULL) 467118293Ssimokawa return (EIO); 468170374Ssimokawa 469170374Ssimokawa FW_GLOCK(fc); 470106813Ssimokawaisoloop: 471113802Ssimokawa if (it->stproc == NULL) { 472113802Ssimokawa it->stproc = STAILQ_FIRST(&it->stfree); 473113802Ssimokawa if (it->stproc != NULL) { 474106813Ssimokawa s = splfw(); 475113802Ssimokawa STAILQ_REMOVE_HEAD(&it->stfree, link); 476106813Ssimokawa splx(s); 477113802Ssimokawa it->queued = 0; 478113802Ssimokawa } else if (slept == 0) { 479113802Ssimokawa slept = 1; 480170374Ssimokawa#if 0 /* XXX to avoid lock recursion */ 481169130Ssimokawa err = fc->itx_enable(fc, it->dmach); 482113802Ssimokawa if (err) 483170374Ssimokawa goto out; 484170374Ssimokawa#endif 485170374Ssimokawa err = msleep(it, FW_GMTX(fc), FWPRI, "fw_write", hz); 486113802Ssimokawa if (err) 487170374Ssimokawa goto out; 488109988Ssimokawa goto isoloop; 489113802Ssimokawa } else { 490113802Ssimokawa err = EIO; 491170374Ssimokawa goto out; 492106813Ssimokawa } 493106813Ssimokawa } 494170374Ssimokawa FW_GUNLOCK(fc); 495113802Ssimokawa fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 496113802Ssimokawa it->stproc->poffset + it->queued); 497113802Ssimokawa err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 498113802Ssimokawa err = uiomove((caddr_t)fp->mode.stream.payload, 499113802Ssimokawa fp->mode.stream.len, uio); 500272214Skan it->queued++; 501113802Ssimokawa if (it->queued >= it->bnpacket) { 502113802Ssimokawa s = splfw(); 503113802Ssimokawa STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 504113802Ssimokawa splx(s); 505113802Ssimokawa it->stproc = NULL; 506169130Ssimokawa err = fc->itx_enable(fc, it->dmach); 507113802Ssimokawa } 508113802Ssimokawa if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 509113802Ssimokawa slept = 0; 510170374Ssimokawa FW_GLOCK(fc); 511113802Ssimokawa goto isoloop; 512113802Ssimokawa } 513113802Ssimokawa return err; 514170374Ssimokawa 515170374Ssimokawaout: 516170374Ssimokawa FW_GUNLOCK(fc); 517170374Ssimokawa return err; 518106813Ssimokawa} 519169130Ssimokawa 520169130Ssimokawastatic void 521169130Ssimokawafw_hand(struct fw_xfer *xfer) 522169130Ssimokawa{ 523169130Ssimokawa struct fw_bind *fwb; 524169130Ssimokawa struct fw_drv1 *d; 525169130Ssimokawa 526169130Ssimokawa fwb = (struct fw_bind *)xfer->sc; 527272214Skan d = fwb->sc; 528170374Ssimokawa FW_GLOCK(xfer->fc); 529169130Ssimokawa STAILQ_INSERT_TAIL(&d->rq, xfer, link); 530170374Ssimokawa FW_GUNLOCK(xfer->fc); 531169130Ssimokawa wakeup(&d->rq); 532169130Ssimokawa} 533169130Ssimokawa 534106813Ssimokawa/* 535106813Ssimokawa * ioctl support. 536106813Ssimokawa */ 537106813Ssimokawaint 538272214Skanfw_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 539106813Ssimokawa{ 540118293Ssimokawa struct firewire_comm *fc; 541118293Ssimokawa struct fw_drv1 *d; 542169130Ssimokawa int i, len, err = 0; 543106813Ssimokawa struct fw_device *fwdev; 544106813Ssimokawa struct fw_bind *fwb; 545106813Ssimokawa struct fw_xferq *ir, *it; 546106813Ssimokawa struct fw_xfer *xfer; 547106813Ssimokawa struct fw_pkt *fp; 548109814Ssimokawa struct fw_devinfo *devinfo; 549117473Ssimokawa void *ptr; 550106813Ssimokawa 551106813Ssimokawa struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 552106813Ssimokawa struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 553106813Ssimokawa struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 554106813Ssimokawa struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 555106813Ssimokawa struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 556106813Ssimokawa struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 557106813Ssimokawa 558106813Ssimokawa if (DEV_FWMEM(dev)) 559106813Ssimokawa return fwmem_ioctl(dev, cmd, data, flag, td); 560106813Ssimokawa 561106813Ssimokawa if (!data) 562272214Skan return (EINVAL); 563106813Ssimokawa 564272214Skan d = dev->si_drv1; 565169130Ssimokawa fc = d->fc; 566118293Ssimokawa ir = d->ir; 567118293Ssimokawa it = d->it; 568118293Ssimokawa 569106813Ssimokawa switch (cmd) { 570106813Ssimokawa case FW_STSTREAM: 571118293Ssimokawa if (it == NULL) { 572170374Ssimokawa i = fw_open_isodma(fc, /* tx */1); 573170374Ssimokawa if (i < 0) { 574118293Ssimokawa err = EBUSY; 575118293Ssimokawa break; 576118293Ssimokawa } 577170374Ssimokawa it = fc->it[i]; 578118293Ssimokawa err = fwdev_allocbuf(fc, it, &d->bufreq.tx); 579170374Ssimokawa if (err) { 580170374Ssimokawa it->flag &= ~FWXFERQ_OPEN; 581118293Ssimokawa break; 582170374Ssimokawa } 583118293Ssimokawa } 584118293Ssimokawa it->flag &= ~0xff; 585118293Ssimokawa it->flag |= (0x3f & ichreq->ch); 586118293Ssimokawa it->flag |= ((0x3 & ichreq->tag) << 6); 587118293Ssimokawa d->it = it; 588106813Ssimokawa break; 589106813Ssimokawa case FW_GTSTREAM: 590118293Ssimokawa if (it != NULL) { 591118293Ssimokawa ichreq->ch = it->flag & 0x3f; 592118293Ssimokawa ichreq->tag = it->flag >> 2 & 0x3; 593118293Ssimokawa } else 594118293Ssimokawa err = EINVAL; 595106813Ssimokawa break; 596106813Ssimokawa case FW_SRSTREAM: 597118293Ssimokawa if (ir == NULL) { 598170374Ssimokawa i = fw_open_isodma(fc, /* tx */0); 599170374Ssimokawa if (i < 0) { 600118293Ssimokawa err = EBUSY; 601118293Ssimokawa break; 602118293Ssimokawa } 603170374Ssimokawa ir = fc->ir[i]; 604118293Ssimokawa err = fwdev_allocbuf(fc, ir, &d->bufreq.rx); 605170374Ssimokawa if (err) { 606170374Ssimokawa ir->flag &= ~FWXFERQ_OPEN; 607118293Ssimokawa break; 608170374Ssimokawa } 609118293Ssimokawa } 610118293Ssimokawa ir->flag &= ~0xff; 611118293Ssimokawa ir->flag |= (0x3f & ichreq->ch); 612118293Ssimokawa ir->flag |= ((0x3 & ichreq->tag) << 6); 613118293Ssimokawa d->ir = ir; 614118293Ssimokawa err = fc->irx_enable(fc, ir->dmach); 615106813Ssimokawa break; 616106813Ssimokawa case FW_GRSTREAM: 617118293Ssimokawa if (d->ir != NULL) { 618118293Ssimokawa ichreq->ch = ir->flag & 0x3f; 619118293Ssimokawa ichreq->tag = ir->flag >> 2 & 0x3; 620118293Ssimokawa } else 621118293Ssimokawa err = EINVAL; 622106813Ssimokawa break; 623106813Ssimokawa case FW_SSTBUF: 624118293Ssimokawa bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq)); 625106813Ssimokawa break; 626106813Ssimokawa case FW_GSTBUF: 627118293Ssimokawa bzero(&ibufreq->rx, sizeof(ibufreq->rx)); 628118293Ssimokawa if (ir != NULL) { 629118293Ssimokawa ibufreq->rx.nchunk = ir->bnchunk; 630118293Ssimokawa ibufreq->rx.npacket = ir->bnpacket; 631118293Ssimokawa ibufreq->rx.psize = ir->psize; 632118293Ssimokawa } 633118293Ssimokawa bzero(&ibufreq->tx, sizeof(ibufreq->tx)); 634118293Ssimokawa if (it != NULL) { 635118293Ssimokawa ibufreq->tx.nchunk = it->bnchunk; 636118293Ssimokawa ibufreq->tx.npacket = it->bnpacket; 637118293Ssimokawa ibufreq->tx.psize = it->psize; 638118293Ssimokawa } 639106813Ssimokawa break; 640106813Ssimokawa case FW_ASYREQ: 641120660Ssimokawa { 642120660Ssimokawa struct tcode_info *tinfo; 643121466Ssimokawa int pay_len = 0; 644120660Ssimokawa 645106813Ssimokawa fp = &asyreq->pkt; 646169130Ssimokawa tinfo = &fc->tcode[fp->mode.hdr.tcode]; 647121466Ssimokawa 648121466Ssimokawa if ((tinfo->flag & FWTI_BLOCK_ASY) != 0) 649121466Ssimokawa pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len); 650121466Ssimokawa 651121466Ssimokawa xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/); 652121466Ssimokawa if (xfer == NULL) 653121466Ssimokawa return (ENOMEM); 654121466Ssimokawa 655106813Ssimokawa switch (asyreq->req.type) { 656106813Ssimokawa case FWASREQNODE: 657106813Ssimokawa break; 658106813Ssimokawa case FWASREQEUI: 659169130Ssimokawa fwdev = fw_noderesolve_eui64(fc, 660110582Ssimokawa &asyreq->req.dst.eui); 661106813Ssimokawa if (fwdev == NULL) { 662169130Ssimokawa device_printf(fc->bdev, 663108782Ssimokawa "cannot find node\n"); 664106813Ssimokawa err = EINVAL; 665121466Ssimokawa goto out; 666106813Ssimokawa } 667120660Ssimokawa fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst; 668106813Ssimokawa break; 669106813Ssimokawa case FWASRESTL: 670106813Ssimokawa /* XXX what's this? */ 671106813Ssimokawa break; 672106813Ssimokawa case FWASREQSTREAM: 673106813Ssimokawa /* nothing to do */ 674106813Ssimokawa break; 675106813Ssimokawa } 676121466Ssimokawa 677120660Ssimokawa bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len); 678121466Ssimokawa if (pay_len > 0) 679120660Ssimokawa bcopy((char *)fp + tinfo->hdr_len, 680272214Skan xfer->send.payload, pay_len); 681121466Ssimokawa xfer->send.spd = asyreq->req.sped; 682170374Ssimokawa xfer->hand = fw_xferwake; 683121466Ssimokawa 684169130Ssimokawa if ((err = fw_asyreq(fc, -1, xfer)) != 0) 685121466Ssimokawa goto out; 686170374Ssimokawa if ((err = fw_xferwait(xfer)) != 0) 687121466Ssimokawa goto out; 688121466Ssimokawa if (xfer->resp != 0) { 689121466Ssimokawa err = EIO; 690121466Ssimokawa goto out; 691106813Ssimokawa } 692121466Ssimokawa if ((tinfo->flag & FWTI_TLABEL) == 0) 693121466Ssimokawa goto out; 694121466Ssimokawa 695121466Ssimokawa /* copy response */ 696169130Ssimokawa tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode]; 697129628Sdfr if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB || 698129628Sdfr xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) { 699129628Sdfr pay_len = xfer->recv.pay_len; 700129628Sdfr if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) { 701129628Sdfr asyreq->req.len = xfer->recv.pay_len + 702272214Skan tinfo->hdr_len; 703129628Sdfr } else { 704129628Sdfr err = EINVAL; 705129628Sdfr pay_len = 0; 706129628Sdfr } 707129628Sdfr } else { 708129628Sdfr pay_len = 0; 709129628Sdfr } 710121466Ssimokawa bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len); 711129628Sdfr bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, pay_len); 712121466Ssimokawaout: 713120660Ssimokawa fw_xfer_free_buf(xfer); 714106813Ssimokawa break; 715120660Ssimokawa } 716106813Ssimokawa case FW_IBUSRST: 717169130Ssimokawa fc->ibr(fc); 718106813Ssimokawa break; 719106813Ssimokawa case FW_CBINDADDR: 720169130Ssimokawa fwb = fw_bindlookup(fc, 721106813Ssimokawa bindreq->start.hi, bindreq->start.lo); 722272214Skan if (fwb == NULL) { 723106813Ssimokawa err = EINVAL; 724106813Ssimokawa break; 725106813Ssimokawa } 726169130Ssimokawa fw_bindremove(fc, fwb); 727169130Ssimokawa STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist); 728169130Ssimokawa fw_xferlist_remove(&fwb->xferlist); 729110195Ssimokawa free(fwb, M_FW); 730106813Ssimokawa break; 731106813Ssimokawa case FW_SBINDADDR: 732272214Skan if (bindreq->len <= 0) { 733106813Ssimokawa err = EINVAL; 734106813Ssimokawa break; 735106813Ssimokawa } 736272214Skan if (bindreq->start.hi > 0xffff) { 737106813Ssimokawa err = EINVAL; 738106813Ssimokawa break; 739106813Ssimokawa } 740272214Skan fwb = malloc(sizeof(struct fw_bind), M_FW, M_WAITOK); 741120660Ssimokawa fwb->start = ((u_int64_t)bindreq->start.hi << 32) | 742120660Ssimokawa bindreq->start.lo; 743120660Ssimokawa fwb->end = fwb->start + bindreq->len; 744272214Skan fwb->sc = d; 745169130Ssimokawa STAILQ_INIT(&fwb->xferlist); 746169130Ssimokawa err = fw_bindadd(fc, fwb); 747169130Ssimokawa if (err == 0) { 748169130Ssimokawa fw_xferlist_add(&fwb->xferlist, M_FWXFER, 749169130Ssimokawa /* XXX */ 750169130Ssimokawa PAGE_SIZE, PAGE_SIZE, 5, 751272214Skan fc, fwb, fw_hand); 752169130Ssimokawa STAILQ_INSERT_TAIL(&d->binds, fwb, chlist); 753106813Ssimokawa } 754106813Ssimokawa break; 755106813Ssimokawa case FW_GDEVLST: 756109814Ssimokawa i = len = 1; 757109814Ssimokawa /* myself */ 758109814Ssimokawa devinfo = &fwdevlst->dev[0]; 759169130Ssimokawa devinfo->dst = fc->nodeid; 760109814Ssimokawa devinfo->status = 0; /* XXX */ 761169130Ssimokawa devinfo->eui.hi = fc->eui.hi; 762169130Ssimokawa devinfo->eui.lo = fc->eui.lo; 763169130Ssimokawa STAILQ_FOREACH(fwdev, &fc->devices, link) { 764272214Skan if (len < FW_MAX_DEVLST) { 765109814Ssimokawa devinfo = &fwdevlst->dev[len++]; 766109814Ssimokawa devinfo->dst = fwdev->dst; 767272214Skan devinfo->status = 768272214Skan (fwdev->status == FWDEVINVAL) ? 0 : 1; 769109814Ssimokawa devinfo->eui.hi = fwdev->eui.hi; 770109814Ssimokawa devinfo->eui.lo = fwdev->eui.lo; 771106813Ssimokawa } 772106813Ssimokawa i++; 773106813Ssimokawa } 774106813Ssimokawa fwdevlst->n = i; 775109814Ssimokawa fwdevlst->info_len = len; 776106813Ssimokawa break; 777106813Ssimokawa case FW_GTPMAP: 778169130Ssimokawa bcopy(fc->topology_map, data, 779272214Skan (fc->topology_map->crc_len + 1) * 4); 780106813Ssimokawa break; 781106813Ssimokawa case FW_GCROM: 782169130Ssimokawa STAILQ_FOREACH(fwdev, &fc->devices, link) 783110193Ssimokawa if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 784106813Ssimokawa break; 785106813Ssimokawa if (fwdev == NULL) { 786169130Ssimokawa if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) { 787117473Ssimokawa err = FWNODE_INVAL; 788117473Ssimokawa break; 789117473Ssimokawa } 790117473Ssimokawa /* myself */ 791117473Ssimokawa ptr = malloc(CROMSIZE, M_FW, M_WAITOK); 792117473Ssimokawa len = CROMSIZE; 793117473Ssimokawa for (i = 0; i < CROMSIZE/4; i++) 794129585Sdfr ((uint32_t *)ptr)[i] 795169130Ssimokawa = ntohl(fc->config_rom[i]); 796117473Ssimokawa } else { 797117473Ssimokawa /* found */ 798117473Ssimokawa ptr = (void *)&fwdev->csrrom[0]; 799117473Ssimokawa if (fwdev->rommax < CSRROMOFF) 800117473Ssimokawa len = 0; 801117473Ssimokawa else 802117473Ssimokawa len = fwdev->rommax - CSRROMOFF + 4; 803106813Ssimokawa } 804169019Ssimokawa if (crom_buf->len < len) 805106813Ssimokawa len = crom_buf->len; 806106813Ssimokawa else 807106813Ssimokawa crom_buf->len = len; 808117473Ssimokawa err = copyout(ptr, crom_buf->ptr, len); 809117473Ssimokawa if (fwdev == NULL) 810117473Ssimokawa /* myself */ 811117473Ssimokawa free(ptr, M_FW); 812106813Ssimokawa break; 813106813Ssimokawa default: 814272214Skan fc->ioctl(dev, cmd, data, flag, td); 815106813Ssimokawa break; 816106813Ssimokawa } 817106813Ssimokawa return err; 818106813Ssimokawa} 819106813Ssimokawaint 820130585Sphkfw_poll(struct cdev *dev, int events, fw_proc *td) 821106813Ssimokawa{ 822118293Ssimokawa struct fw_xferq *ir; 823106813Ssimokawa int revents; 824106813Ssimokawa int tmp; 825106813Ssimokawa 826106813Ssimokawa if (DEV_FWMEM(dev)) 827106813Ssimokawa return fwmem_poll(dev, events, td); 828106813Ssimokawa 829118293Ssimokawa ir = ((struct fw_drv1 *)dev->si_drv1)->ir; 830106813Ssimokawa revents = 0; 831106813Ssimokawa tmp = POLLIN | POLLRDNORM; 832106813Ssimokawa if (events & tmp) { 833118293Ssimokawa if (STAILQ_FIRST(&ir->q) != NULL) 834106813Ssimokawa revents |= tmp; 835106813Ssimokawa else 836118293Ssimokawa selrecord(td, &ir->rsel); 837106813Ssimokawa } 838106813Ssimokawa tmp = POLLOUT | POLLWRNORM; 839106813Ssimokawa if (events & tmp) { 840272214Skan /* XXX should be fixed */ 841106813Ssimokawa revents |= tmp; 842106813Ssimokawa } 843106813Ssimokawa 844106813Ssimokawa return revents; 845106813Ssimokawa} 846106813Ssimokawa 847106813Ssimokawastatic int 848201223Srnolandfw_mmap (struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, 849201223Srnoland int nproto, vm_memattr_t *memattr) 850272214Skan{ 851106813Ssimokawa 852106813Ssimokawa if (DEV_FWMEM(dev)) 853201223Srnoland return fwmem_mmap(dev, offset, paddr, nproto, memattr); 854106813Ssimokawa 855106813Ssimokawa return EINVAL; 856106813Ssimokawa} 857118455Ssimokawa 858120660Ssimokawastatic void 859120660Ssimokawafw_strategy(struct bio *bp) 860120660Ssimokawa{ 861130585Sphk struct cdev *dev; 862120660Ssimokawa 863120660Ssimokawa dev = bp->bio_dev; 864120660Ssimokawa if (DEV_FWMEM(dev)) { 865120660Ssimokawa fwmem_strategy(bp); 866120660Ssimokawa return; 867120660Ssimokawa } 868120660Ssimokawa 869120660Ssimokawa bp->bio_error = EOPNOTSUPP; 870120660Ssimokawa bp->bio_flags |= BIO_ERROR; 871120660Ssimokawa bp->bio_resid = bp->bio_bcount; 872120660Ssimokawa biodone(bp); 873120660Ssimokawa} 874120660Ssimokawa 875118455Ssimokawaint 876118455Ssimokawafwdev_makedev(struct firewire_softc *sc) 877118455Ssimokawa{ 878118455Ssimokawa int err = 0; 879118455Ssimokawa 880130585Sphk struct cdev *d; 881118455Ssimokawa int unit; 882118455Ssimokawa 883118455Ssimokawa unit = device_get_unit(sc->fc->bdev); 884118455Ssimokawa sc->dev = make_dev(&firewire_cdevsw, MAKEMINOR(0, unit, 0), 885272214Skan UID_ROOT, GID_OPERATOR, 0660, "fw%d.%d", unit, 0); 886272214Skan d = make_dev(&firewire_cdevsw, MAKEMINOR(FWMEM_FLAG, unit, 0), 887272214Skan UID_ROOT, GID_OPERATOR, 0660, "fwmem%d.%d", unit, 0); 888118455Ssimokawa dev_depends(sc->dev, d); 889118455Ssimokawa make_dev_alias(sc->dev, "fw%d", unit); 890118455Ssimokawa make_dev_alias(d, "fwmem%d", unit); 891118455Ssimokawa 892118455Ssimokawa return (err); 893118455Ssimokawa} 894118455Ssimokawa 895118455Ssimokawaint 896118455Ssimokawafwdev_destroydev(struct firewire_softc *sc) 897118455Ssimokawa{ 898118455Ssimokawa int err = 0; 899118455Ssimokawa 900118455Ssimokawa destroy_dev(sc->dev); 901118455Ssimokawa return (err); 902118455Ssimokawa} 903118455Ssimokawa 904118455Ssimokawa#define NDEVTYPE 2 905118455Ssimokawavoid 906148868Srwatsonfwdev_clone(void *arg, struct ucred *cred, char *name, int namelen, 907148868Srwatson struct cdev **dev) 908118455Ssimokawa{ 909118455Ssimokawa struct firewire_softc *sc; 910118455Ssimokawa char *devnames[NDEVTYPE] = {"fw", "fwmem"}; 911118455Ssimokawa char *subp = NULL; 912118455Ssimokawa int devflag[NDEVTYPE] = {0, FWMEM_FLAG}; 913118455Ssimokawa int i, unit = 0, sub = 0; 914118455Ssimokawa 915130640Sphk if (*dev != NULL) 916118455Ssimokawa return; 917118455Ssimokawa 918118455Ssimokawa for (i = 0; i < NDEVTYPE; i++) 919120624Ssimokawa if (dev_stdclone(name, &subp, devnames[i], &unit) == 2) 920118455Ssimokawa goto found; 921118455Ssimokawa /* not match */ 922118455Ssimokawa return; 923118455Ssimokawafound: 924118455Ssimokawa 925118455Ssimokawa if (subp == NULL || *subp++ != '.') 926118455Ssimokawa return; 927118455Ssimokawa 928118455Ssimokawa /* /dev/fwU.S */ 929118455Ssimokawa while (isdigit(*subp)) { 930118455Ssimokawa sub *= 10; 931118455Ssimokawa sub += *subp++ - '0'; 932118455Ssimokawa } 933118455Ssimokawa if (*subp != '\0') 934118455Ssimokawa return; 935118455Ssimokawa 936118455Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 937118455Ssimokawa if (sc == NULL) 938118455Ssimokawa return; 939255359Sdavide *dev = make_dev_credf(MAKEDEV_REF, &firewire_cdevsw, 940255359Sdavide MAKEMINOR(devflag[i], unit, sub), cred, UID_ROOT, GID_OPERATOR, 941255359Sdavide 0660, "%s%d.%d", devnames[i], unit, sub); 942118455Ssimokawa dev_depends(sc->dev, *dev); 943118455Ssimokawa return; 944118455Ssimokawa} 945