fwdev.c revision 271795
1139749Simp/*- 2123120Simp * Copyright (c) 2003 Hidetoshi Shimokawa 3123120Simp * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 4123120Simp * All rights reserved. 5123120Simp * 6123120Simp * Redistribution and use in source and binary forms, with or without 7123120Simp * modification, are permitted provided that the following conditions 8123120Simp * are met: 9123120Simp * 1. Redistributions of source code must retain the above copyright 10123120Simp * notice, this list of conditions and the following disclaimer. 11123120Simp * 2. Redistributions in binary form must reproduce the above copyright 12123120Simp * notice, this list of conditions and the following disclaimer in the 13123120Simp * documentation and/or other materials provided with the distribution. 14123120Simp * 3. All advertising materials mentioning features or use of this software 15123120Simp * must display the acknowledgement as bellow: 16123120Simp * 17123120Simp * This product includes software developed by K. Kobayashi and H. Shimokawa 18123120Simp * 19123120Simp * 4. The name of the author may not be used to endorse or promote products 20123120Simp * derived from this software without specific prior written permission. 21123120Simp * 22123120Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23123120Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24123120Simp * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25123120Simp * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 26123120Simp * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27123120Simp * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28123120Simp * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29123120Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 30123120Simp * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31123120Simp * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32123120Simp * POSSIBILITY OF SUCH DAMAGE. 33123120Simp * 34123120Simp * $FreeBSD: head/sys/dev/firewire/fwdev.c 271795 2014-09-18 17:28:21Z will $ 35123120Simp * 36123120Simp */ 37123120Simp 38123120Simp#include <sys/param.h> 39123120Simp#include <sys/systm.h> 40123120Simp#include <sys/types.h> 41123120Simp#include <sys/mbuf.h> 42123120Simp#include <sys/bio.h> 43123120Simp 44123120Simp#include <sys/kernel.h> 45123120Simp#include <sys/malloc.h> 46123120Simp#include <sys/conf.h> 47123120Simp#include <sys/poll.h> 48123120Simp 49123120Simp#include <sys/bus.h> 50123120Simp#include <sys/ctype.h> 51123120Simp#include <machine/bus.h> 52123120Simp 53123120Simp#include <sys/ioccom.h> 54123120Simp 55123120Simp#ifdef __DragonFly__ 56123120Simp#include "firewire.h" 57123120Simp#include "firewirereg.h" 58123120Simp#include "fwdma.h" 59123120Simp#include "fwmem.h" 60123120Simp#include "iec68113.h" 61123120Simp#else 62123120Simp#include <dev/firewire/firewire.h> 63123120Simp#include <dev/firewire/firewirereg.h> 64123120Simp#include <dev/firewire/fwdma.h> 65123120Simp#include <dev/firewire/fwmem.h> 66123120Simp#include <dev/firewire/iec68113.h> 67123120Simp#endif 68123120Simp 69123120Simp#define FWNODE_INVAL 0xffff 70123120Simp 71123120Simpstatic d_open_t fw_open; 72123120Simpstatic d_close_t fw_close; 73123120Simpstatic d_ioctl_t fw_ioctl; 74123120Simpstatic d_poll_t fw_poll; 75123120Simpstatic d_read_t fw_read; /* for Isochronous packet */ 76123120Simpstatic d_write_t fw_write; 77123120Simpstatic d_mmap_t fw_mmap; 78123120Simpstatic d_strategy_t fw_strategy; 79123120Simp 80123120Simpstruct cdevsw firewire_cdevsw = { 81123120Simp#ifdef __DragonFly__ 82123120Simp#define CDEV_MAJOR 127 83123120Simp "fw", CDEV_MAJOR, D_MEM, NULL, 0, 84123120Simp fw_open, fw_close, fw_read, fw_write, fw_ioctl, 85123120Simp fw_poll, fw_mmap, fw_strategy, nodump, nopsize, 86123120Simp#elif __FreeBSD_version >= 500104 87123120Simp .d_version = D_VERSION, 88123120Simp .d_open = fw_open, 89123120Simp .d_close = fw_close, 90123120Simp .d_read = fw_read, 91123120Simp .d_write = fw_write, 92123120Simp .d_ioctl = fw_ioctl, 93123120Simp .d_poll = fw_poll, 94123120Simp .d_mmap = fw_mmap, 95123120Simp .d_strategy = fw_strategy, 96123120Simp .d_name = "fw", 97123120Simp .d_flags = D_MEM 98123120Simp#else 99123120Simp#define CDEV_MAJOR 127 100123120Simp fw_open, fw_close, fw_read, fw_write, fw_ioctl, 101123120Simp fw_poll, fw_mmap, fw_strategy, "fw", CDEV_MAJOR, 102123120Simp nodump, nopsize, D_MEM, -1 103123120Simp#endif 104123120Simp}; 105123120Simp 106123120Simpstruct fw_drv1 { 107123120Simp struct firewire_comm *fc; 108123120Simp struct fw_xferq *ir; 109123120Simp struct fw_xferq *it; 110123120Simp struct fw_isobufreq bufreq; 111123120Simp STAILQ_HEAD(, fw_bind) binds; 112123120Simp STAILQ_HEAD(, fw_xfer) rq; 113123120Simp}; 114123120Simp 115123120Simpstatic int 116123120Simpfwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q, 117123120Simp struct fw_bufspec *b) 118123120Simp{ 119123120Simp int i; 120123120Simp 121123120Simp if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF)) 122123120Simp return(EBUSY); 123123120Simp 124123120Simp q->bulkxfer = (struct fw_bulkxfer *) malloc( 125123120Simp sizeof(struct fw_bulkxfer) * b->nchunk, 126123120Simp M_FW, M_WAITOK); 127123120Simp if (q->bulkxfer == NULL) 128123120Simp return(ENOMEM); 129123120Simp 130123120Simp b->psize = roundup2(b->psize, sizeof(uint32_t)); 131123120Simp q->buf = fwdma_malloc_multiseg(fc, sizeof(uint32_t), 132123120Simp b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK); 133123120Simp 134123120Simp if (q->buf == NULL) { 135123120Simp free(q->bulkxfer, M_FW); 136123120Simp q->bulkxfer = NULL; 137123120Simp return(ENOMEM); 138123120Simp } 139123120Simp q->bnchunk = b->nchunk; 140123120Simp q->bnpacket = b->npacket; 141123120Simp q->psize = (b->psize + 3) & ~3; 142123120Simp q->queued = 0; 143123120Simp 144123120Simp STAILQ_INIT(&q->stvalid); 145123120Simp STAILQ_INIT(&q->stfree); 146123120Simp STAILQ_INIT(&q->stdma); 147123120Simp q->stproc = NULL; 148123120Simp 149123120Simp for(i = 0 ; i < q->bnchunk; i++){ 150123120Simp q->bulkxfer[i].poffset = i * q->bnpacket; 151123120Simp q->bulkxfer[i].mbuf = NULL; 152123120Simp STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link); 153123120Simp } 154123120Simp 155123120Simp q->flag &= ~FWXFERQ_MODEMASK; 156123120Simp q->flag |= FWXFERQ_STREAM; 157123120Simp q->flag |= FWXFERQ_EXTBUF; 158123120Simp 159123120Simp return (0); 160123120Simp} 161123120Simp 162123120Simpstatic int 163123120Simpfwdev_freebuf(struct fw_xferq *q) 164123120Simp{ 165123120Simp if (q->flag & FWXFERQ_EXTBUF) { 166123120Simp if (q->buf != NULL) 167123120Simp fwdma_free_multiseg(q->buf); 168123120Simp q->buf = NULL; 169123120Simp free(q->bulkxfer, M_FW); 170123120Simp q->bulkxfer = NULL; 171123120Simp q->flag &= ~FWXFERQ_EXTBUF; 172123120Simp q->psize = 0; 173123120Simp q->maxq = FWMAXQUEUE; 174123120Simp } 175123120Simp return (0); 176123120Simp} 177123120Simp 178123120Simp 179123120Simpstatic int 180123120Simpfw_open (struct cdev *dev, int flags, int fmt, fw_proc *td) 181123120Simp{ 182123120Simp int err = 0; 183123120Simp int unit = DEV2UNIT(dev); 184123120Simp struct fw_drv1 *d; 185123120Simp struct firewire_softc *sc; 186123120Simp 187123120Simp if (DEV_FWMEM(dev)) 188123120Simp return fwmem_open(dev, flags, fmt, td); 189123120Simp 190123120Simp sc = devclass_get_softc(firewire_devclass, unit); 191123120Simp if (sc == NULL) 192123120Simp return (ENXIO); 193123120Simp 194123120Simp FW_GLOCK(sc->fc); 195123120Simp if (dev->si_drv1 != NULL) { 196123120Simp FW_GUNLOCK(sc->fc); 197123120Simp return (EBUSY); 198123120Simp } 199123120Simp /* set dummy value for allocation */ 200123120Simp dev->si_drv1 = (void *)-1; 201123120Simp FW_GUNLOCK(sc->fc); 202123120Simp 203123120Simp dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); 204123120Simp if (dev->si_drv1 == NULL) 205123120Simp return (ENOMEM); 206123120Simp 207123120Simp if ((dev->si_flags & SI_NAMED) == 0) { 208123120Simp int unit = DEV2UNIT(dev); 209123120Simp int sub = DEV2SUB(dev); 210123120Simp 211123120Simp make_dev(&firewire_cdevsw, dev2unit(dev), 212123120Simp UID_ROOT, GID_OPERATOR, 0660, 213123120Simp "fw%d.%d", unit, sub); 214123120Simp } 215123120Simp d = (struct fw_drv1 *)dev->si_drv1; 216123120Simp d->fc = sc->fc; 217123120Simp STAILQ_INIT(&d->binds); 218123120Simp STAILQ_INIT(&d->rq); 219123120Simp 220123120Simp return err; 221123120Simp} 222123120Simp 223123120Simpstatic int 224123120Simpfw_close (struct cdev *dev, int flags, int fmt, fw_proc *td) 225123120Simp{ 226123120Simp struct firewire_comm *fc; 227123120Simp struct fw_drv1 *d; 228123120Simp struct fw_xfer *xfer; 229123120Simp struct fw_bind *fwb; 230123120Simp int err = 0; 231123120Simp 232123120Simp if (DEV_FWMEM(dev)) 233123120Simp return fwmem_close(dev, flags, fmt, td); 234123120Simp 235123120Simp d = (struct fw_drv1 *)dev->si_drv1; 236123120Simp fc = d->fc; 237123120Simp 238123120Simp /* remove binding */ 239123120Simp for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL; 240123120Simp fwb = STAILQ_FIRST(&d->binds)) { 241123120Simp fw_bindremove(fc, fwb); 242123120Simp STAILQ_REMOVE_HEAD(&d->binds, chlist); 243123120Simp fw_xferlist_remove(&fwb->xferlist); 244123120Simp free(fwb, M_FW); 245123120Simp } 246123120Simp if (d->ir != NULL) { 247123120Simp struct fw_xferq *ir = d->ir; 248123120Simp 249123120Simp if ((ir->flag & FWXFERQ_OPEN) == 0) 250123120Simp return (EINVAL); 251123120Simp if (ir->flag & FWXFERQ_RUNNING) { 252123120Simp ir->flag &= ~FWXFERQ_RUNNING; 253123120Simp fc->irx_disable(fc, ir->dmach); 254123120Simp } 255123120Simp /* free extbuf */ 256123120Simp fwdev_freebuf(ir); 257123120Simp /* drain receiving buffer */ 258123120Simp for (xfer = STAILQ_FIRST(&ir->q); 259123120Simp xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) { 260123120Simp ir->queued --; 261123120Simp STAILQ_REMOVE_HEAD(&ir->q, link); 262123120Simp 263123120Simp xfer->resp = 0; 264123120Simp fw_xfer_done(xfer); 265123120Simp } 266123120Simp ir->flag &= ~(FWXFERQ_OPEN | 267123120Simp FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 268123120Simp d->ir = NULL; 269123120Simp 270123120Simp } 271123120Simp if (d->it != NULL) { 272123120Simp struct fw_xferq *it = d->it; 273123120Simp 274123120Simp if ((it->flag & FWXFERQ_OPEN) == 0) 275123120Simp return (EINVAL); 276123120Simp if (it->flag & FWXFERQ_RUNNING) { 277123120Simp it->flag &= ~FWXFERQ_RUNNING; 278123120Simp fc->itx_disable(fc, it->dmach); 279123120Simp } 280123120Simp /* free extbuf */ 281123120Simp fwdev_freebuf(it); 282123120Simp it->flag &= ~(FWXFERQ_OPEN | 283123120Simp FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 284123120Simp d->it = NULL; 285123120Simp } 286123120Simp free(dev->si_drv1, M_FW); 287123120Simp dev->si_drv1 = NULL; 288123120Simp 289123120Simp return err; 290123120Simp} 291123120Simp 292123120Simpstatic int 293123120Simpfw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 294123120Simp{ 295123120Simp int err = 0, s; 296123120Simp struct fw_xfer *xfer; 297123120Simp struct fw_bind *fwb; 298123120Simp struct fw_pkt *fp; 299123120Simp struct tcode_info *tinfo; 300123120Simp 301123120Simp FW_GLOCK(d->fc); 302123120Simp while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == 0) 303123120Simp err = msleep(&d->rq, FW_GMTX(d->fc), FWPRI, "fwra", 0); 304123120Simp 305123120Simp if (err != 0) { 306123120Simp FW_GUNLOCK(d->fc); 307123120Simp return (err); 308123120Simp } 309123120Simp 310123120Simp s = splfw(); 311123120Simp STAILQ_REMOVE_HEAD(&d->rq, link); 312123120Simp FW_GUNLOCK(xfer->fc); 313123120Simp splx(s); 314123120Simp fp = &xfer->recv.hdr; 315123120Simp#if 0 /* for GASP ?? */ 316123120Simp if (fc->irx_post != NULL) 317123120Simp fc->irx_post(fc, fp->mode.ld); 318123120Simp#endif 319123120Simp tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode]; 320123120Simp err = uiomove((void *)fp, tinfo->hdr_len, uio); 321123120Simp if (err) 322123120Simp goto out; 323123120Simp err = uiomove((void *)xfer->recv.payload, xfer->recv.pay_len, uio); 324123120Simp 325123120Simpout: 326123120Simp /* recycle this xfer */ 327123120Simp fwb = (struct fw_bind *)xfer->sc; 328123120Simp fw_xfer_unload(xfer); 329123120Simp xfer->recv.pay_len = PAGE_SIZE; 330123120Simp FW_GLOCK(xfer->fc); 331123120Simp STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 332123120Simp FW_GUNLOCK(xfer->fc); 333123120Simp return (err); 334123120Simp} 335123120Simp 336123120Simp/* 337123120Simp * read request. 338123120Simp */ 339123120Simpstatic int 340123120Simpfw_read (struct cdev *dev, struct uio *uio, int ioflag) 341123120Simp{ 342123120Simp struct fw_drv1 *d; 343123120Simp struct fw_xferq *ir; 344123120Simp struct firewire_comm *fc; 345123120Simp int err = 0, s, slept = 0; 346123120Simp struct fw_pkt *fp; 347123120Simp 348123120Simp if (DEV_FWMEM(dev)) 349123120Simp return (physio(dev, uio, ioflag)); 350123120Simp 351123120Simp d = (struct fw_drv1 *)dev->si_drv1; 352123120Simp fc = d->fc; 353123120Simp ir = d->ir; 354123120Simp 355123120Simp if (ir == NULL) 356123120Simp return (fw_read_async(d, uio, ioflag)); 357123120Simp 358123120Simp if (ir->buf == NULL) 359123120Simp return (EIO); 360123120Simp 361123120Simp FW_GLOCK(fc); 362123120Simpreadloop: 363123120Simp if (ir->stproc == NULL) { 364123120Simp /* iso bulkxfer */ 365123120Simp ir->stproc = STAILQ_FIRST(&ir->stvalid); 366123120Simp if (ir->stproc != NULL) { 367123120Simp s = splfw(); 368123120Simp STAILQ_REMOVE_HEAD(&ir->stvalid, link); 369123120Simp splx(s); 370123120Simp ir->queued = 0; 371123120Simp } 372123120Simp } 373123120Simp if (ir->stproc == NULL) { 374123120Simp /* no data avaliable */ 375123120Simp if (slept == 0) { 376123120Simp slept = 1; 377123120Simp ir->flag |= FWXFERQ_WAKEUP; 378123120Simp err = msleep(ir, FW_GMTX(fc), FWPRI, "fw_read", hz); 379123120Simp ir->flag &= ~FWXFERQ_WAKEUP; 380123120Simp if (err == 0) 381123120Simp goto readloop; 382123120Simp } else if (slept == 1) 383123120Simp err = EIO; 384123120Simp FW_GUNLOCK(fc); 385123120Simp return err; 386123120Simp } else if(ir->stproc != NULL) { 387123120Simp /* iso bulkxfer */ 388123120Simp FW_GUNLOCK(fc); 389123120Simp fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 390123120Simp ir->stproc->poffset + ir->queued); 391123120Simp if(fc->irx_post != NULL) 392123120Simp fc->irx_post(fc, fp->mode.ld); 393123120Simp if(fp->mode.stream.len == 0){ 394123120Simp err = EIO; 395123120Simp return err; 396123120Simp } 397123120Simp err = uiomove((caddr_t)fp, 398123120Simp fp->mode.stream.len + sizeof(uint32_t), uio); 399123120Simp ir->queued ++; 400123120Simp if(ir->queued >= ir->bnpacket){ 401123120Simp s = splfw(); 402123120Simp STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 403123120Simp splx(s); 404123120Simp fc->irx_enable(fc, ir->dmach); 405123120Simp ir->stproc = NULL; 406123120Simp } 407123120Simp if (uio->uio_resid >= ir->psize) { 408123120Simp slept = -1; 409123120Simp FW_GLOCK(fc); 410123120Simp goto readloop; 411123120Simp } 412123120Simp } 413123120Simp return err; 414123120Simp} 415123120Simp 416123120Simpstatic int 417123120Simpfw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 418123120Simp{ 419123120Simp struct fw_xfer *xfer; 420123120Simp struct fw_pkt pkt; 421123120Simp struct tcode_info *tinfo; 422123120Simp int err; 423123120Simp 424123120Simp bzero(&pkt, sizeof(struct fw_pkt)); 425123120Simp if ((err = uiomove((caddr_t)&pkt, sizeof(uint32_t), uio))) 426123120Simp return (err); 427123120Simp tinfo = &d->fc->tcode[pkt.mode.hdr.tcode]; 428123120Simp if ((err = uiomove((caddr_t)&pkt + sizeof(uint32_t), 429123120Simp tinfo->hdr_len - sizeof(uint32_t), uio))) 430123120Simp return (err); 431123120Simp 432123120Simp if ((xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid, 433123120Simp PAGE_SIZE/*XXX*/)) == NULL) 434123120Simp return (ENOMEM); 435123120Simp 436123120Simp bcopy(&pkt, &xfer->send.hdr, sizeof(struct fw_pkt)); 437123120Simp xfer->send.pay_len = uio->uio_resid; 438123120Simp if (uio->uio_resid > 0) { 439123120Simp if ((err = uiomove((caddr_t)&xfer->send.payload[0], 440123120Simp uio->uio_resid, uio))) 441123120Simp goto out; 442123120Simp } 443315221Spfg 444123120Simp xfer->fc = d->fc; 445123120Simp xfer->sc = NULL; 446123120Simp xfer->hand = fw_xferwake; 447123120Simp xfer->send.spd = 2 /* XXX */; 448123120Simp 449123120Simp if ((err = fw_asyreq(xfer->fc, -1, xfer))) 450123120Simp goto out; 451123120Simp 452123120Simp if ((err = fw_xferwait(xfer))) 453123120Simp goto out; 454123120Simp 455123120Simp if (xfer->resp != 0) { 456123120Simp err = xfer->resp; 457123120Simp goto out; 458123120Simp } 459123120Simp 460123120Simp if (xfer->flag & FWXF_RCVD) { 461123120Simp FW_GLOCK(xfer->fc); 462123120Simp STAILQ_INSERT_TAIL(&d->rq, xfer, link); 463123120Simp FW_GUNLOCK(xfer->fc); 464123120Simp return (0); 465123120Simp } 466123120Simp 467123120Simpout: 468123120Simp fw_xfer_free(xfer); 469123120Simp return (err); 470123120Simp} 471123120Simp 472123120Simpstatic int 473123120Simpfw_write (struct cdev *dev, struct uio *uio, int ioflag) 474123120Simp{ 475123120Simp int err = 0; 476123120Simp int s, slept = 0; 477123120Simp struct fw_drv1 *d; 478123120Simp struct fw_pkt *fp; 479123120Simp struct firewire_comm *fc; 480123120Simp struct fw_xferq *it; 481123120Simp 482123120Simp if (DEV_FWMEM(dev)) 483123120Simp return (physio(dev, uio, ioflag)); 484123120Simp 485123120Simp d = (struct fw_drv1 *)dev->si_drv1; 486123120Simp fc = d->fc; 487123120Simp it = d->it; 488123120Simp 489123120Simp if (it == NULL) 490123120Simp return (fw_write_async(d, uio, ioflag)); 491123120Simp 492123120Simp if (it->buf == NULL) 493123120Simp return (EIO); 494123120Simp 495123120Simp FW_GLOCK(fc); 496123120Simpisoloop: 497123120Simp if (it->stproc == NULL) { 498123120Simp it->stproc = STAILQ_FIRST(&it->stfree); 499123120Simp if (it->stproc != NULL) { 500123120Simp s = splfw(); 501123120Simp STAILQ_REMOVE_HEAD(&it->stfree, link); 502123120Simp splx(s); 503123120Simp it->queued = 0; 504123120Simp } else if (slept == 0) { 505123120Simp slept = 1; 506123120Simp#if 0 /* XXX to avoid lock recursion */ 507123120Simp err = fc->itx_enable(fc, it->dmach); 508123120Simp if (err) 509123120Simp goto out; 510123120Simp#endif 511123120Simp err = msleep(it, FW_GMTX(fc), FWPRI, "fw_write", hz); 512123120Simp if (err) 513123120Simp goto out; 514123120Simp goto isoloop; 515123120Simp } else { 516123120Simp err = EIO; 517123120Simp goto out; 518123120Simp } 519123120Simp } 520123120Simp FW_GUNLOCK(fc); 521123120Simp fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 522123120Simp it->stproc->poffset + it->queued); 523123120Simp err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 524123120Simp err = uiomove((caddr_t)fp->mode.stream.payload, 525123120Simp fp->mode.stream.len, uio); 526123120Simp it->queued ++; 527123120Simp if (it->queued >= it->bnpacket) { 528123120Simp s = splfw(); 529123120Simp STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 530123120Simp splx(s); 531123120Simp it->stproc = NULL; 532123120Simp err = fc->itx_enable(fc, it->dmach); 533123120Simp } 534123120Simp if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 535123120Simp slept = 0; 536123120Simp FW_GLOCK(fc); 537123120Simp goto isoloop; 538123120Simp } 539123120Simp return err; 540123120Simp 541123120Simpout: 542123120Simp FW_GUNLOCK(fc); 543123120Simp return err; 544123120Simp} 545123120Simp 546123120Simpstatic void 547123120Simpfw_hand(struct fw_xfer *xfer) 548123120Simp{ 549123120Simp struct fw_bind *fwb; 550123120Simp struct fw_drv1 *d; 551123120Simp 552123120Simp fwb = (struct fw_bind *)xfer->sc; 553123120Simp d = (struct fw_drv1 *)fwb->sc; 554123120Simp FW_GLOCK(xfer->fc); 555123120Simp STAILQ_INSERT_TAIL(&d->rq, xfer, link); 556123120Simp FW_GUNLOCK(xfer->fc); 557123120Simp wakeup(&d->rq); 558123120Simp} 559123120Simp 560123120Simp/* 561123120Simp * ioctl support. 562123120Simp */ 563123120Simpint 564123120Simpfw_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 565123120Simp{ 566123120Simp struct firewire_comm *fc; 567123120Simp struct fw_drv1 *d; 568123120Simp int i, len, err = 0; 569123120Simp struct fw_device *fwdev; 570123120Simp struct fw_bind *fwb; 571123120Simp struct fw_xferq *ir, *it; 572123120Simp struct fw_xfer *xfer; 573123120Simp struct fw_pkt *fp; 574123120Simp struct fw_devinfo *devinfo; 575123120Simp void *ptr; 576123120Simp 577123120Simp struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 578123120Simp struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 579123120Simp struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 580123120Simp struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 581123120Simp struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 582123120Simp struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 583123120Simp 584123120Simp if (DEV_FWMEM(dev)) 585123120Simp return fwmem_ioctl(dev, cmd, data, flag, td); 586123120Simp 587123120Simp if (!data) 588123120Simp return(EINVAL); 589123120Simp 590123120Simp d = (struct fw_drv1 *)dev->si_drv1; 591123120Simp fc = d->fc; 592123120Simp ir = d->ir; 593123120Simp it = d->it; 594123120Simp 595123120Simp switch (cmd) { 596123120Simp case FW_STSTREAM: 597123120Simp if (it == NULL) { 598123120Simp i = fw_open_isodma(fc, /* tx */1); 599123120Simp if (i < 0) { 600123120Simp err = EBUSY; 601123120Simp break; 602123120Simp } 603123120Simp it = fc->it[i]; 604123120Simp err = fwdev_allocbuf(fc, it, &d->bufreq.tx); 605123120Simp if (err) { 606123120Simp it->flag &= ~FWXFERQ_OPEN; 607123120Simp break; 608123120Simp } 609123120Simp } 610123120Simp it->flag &= ~0xff; 611123120Simp it->flag |= (0x3f & ichreq->ch); 612123120Simp it->flag |= ((0x3 & ichreq->tag) << 6); 613123120Simp d->it = it; 614123120Simp break; 615123120Simp case FW_GTSTREAM: 616123120Simp if (it != NULL) { 617123120Simp ichreq->ch = it->flag & 0x3f; 618123120Simp ichreq->tag = it->flag >> 2 & 0x3; 619123120Simp } else 620123120Simp err = EINVAL; 621123120Simp break; 622123120Simp case FW_SRSTREAM: 623123120Simp if (ir == NULL) { 624123120Simp i = fw_open_isodma(fc, /* tx */0); 625123120Simp if (i < 0) { 626123120Simp err = EBUSY; 627123120Simp break; 628123120Simp } 629123120Simp ir = fc->ir[i]; 630123120Simp err = fwdev_allocbuf(fc, ir, &d->bufreq.rx); 631123120Simp if (err) { 632123120Simp ir->flag &= ~FWXFERQ_OPEN; 633123120Simp break; 634123120Simp } 635123120Simp } 636123120Simp ir->flag &= ~0xff; 637123120Simp ir->flag |= (0x3f & ichreq->ch); 638123120Simp ir->flag |= ((0x3 & ichreq->tag) << 6); 639123120Simp d->ir = ir; 640123120Simp err = fc->irx_enable(fc, ir->dmach); 641123120Simp break; 642123120Simp case FW_GRSTREAM: 643123120Simp if (d->ir != NULL) { 644123120Simp ichreq->ch = ir->flag & 0x3f; 645123120Simp ichreq->tag = ir->flag >> 2 & 0x3; 646123120Simp } else 647123120Simp err = EINVAL; 648123120Simp break; 649123120Simp case FW_SSTBUF: 650123120Simp bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq)); 651123120Simp break; 652123120Simp case FW_GSTBUF: 653123120Simp bzero(&ibufreq->rx, sizeof(ibufreq->rx)); 654123120Simp if (ir != NULL) { 655123120Simp ibufreq->rx.nchunk = ir->bnchunk; 656123120Simp ibufreq->rx.npacket = ir->bnpacket; 657123120Simp ibufreq->rx.psize = ir->psize; 658123120Simp } 659123120Simp bzero(&ibufreq->tx, sizeof(ibufreq->tx)); 660123120Simp if (it != NULL) { 661123120Simp ibufreq->tx.nchunk = it->bnchunk; 662123120Simp ibufreq->tx.npacket = it->bnpacket; 663123120Simp ibufreq->tx.psize = it->psize; 664123120Simp } 665123120Simp break; 666123120Simp case FW_ASYREQ: 667123120Simp { 668123120Simp struct tcode_info *tinfo; 669123120Simp int pay_len = 0; 670123120Simp 671123120Simp fp = &asyreq->pkt; 672123120Simp tinfo = &fc->tcode[fp->mode.hdr.tcode]; 673123120Simp 674123120Simp if ((tinfo->flag & FWTI_BLOCK_ASY) != 0) 675123120Simp pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len); 676123120Simp 677123120Simp xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/); 678123120Simp if (xfer == NULL) 679123120Simp return (ENOMEM); 680123120Simp 681123120Simp switch (asyreq->req.type) { 682123120Simp case FWASREQNODE: 683123120Simp break; 684123120Simp case FWASREQEUI: 685123120Simp fwdev = fw_noderesolve_eui64(fc, 686123120Simp &asyreq->req.dst.eui); 687123120Simp if (fwdev == NULL) { 688123120Simp device_printf(fc->bdev, 689123120Simp "cannot find node\n"); 690123120Simp err = EINVAL; 691123120Simp goto out; 692123120Simp } 693123120Simp fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst; 694123120Simp break; 695123120Simp case FWASRESTL: 696123120Simp /* XXX what's this? */ 697123120Simp break; 698123120Simp case FWASREQSTREAM: 699123120Simp /* nothing to do */ 700123120Simp break; 701123120Simp } 702123120Simp 703123120Simp bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len); 704123120Simp if (pay_len > 0) 705123120Simp bcopy((char *)fp + tinfo->hdr_len, 706123120Simp (void *)xfer->send.payload, pay_len); 707123120Simp xfer->send.spd = asyreq->req.sped; 708123120Simp xfer->hand = fw_xferwake; 709123120Simp 710123120Simp if ((err = fw_asyreq(fc, -1, xfer)) != 0) 711123120Simp goto out; 712123120Simp if ((err = fw_xferwait(xfer)) != 0) 713123120Simp goto out; 714123120Simp if (xfer->resp != 0) { 715123120Simp err = EIO; 716123120Simp goto out; 717123120Simp } 718123120Simp if ((tinfo->flag & FWTI_TLABEL) == 0) 719123120Simp goto out; 720123120Simp 721123120Simp /* copy response */ 722123120Simp tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode]; 723123120Simp if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB || 724123120Simp xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) { 725123120Simp pay_len = xfer->recv.pay_len; 726123120Simp if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) { 727123120Simp asyreq->req.len = xfer->recv.pay_len + 728123120Simp tinfo->hdr_len; 729123120Simp } else { 730123120Simp err = EINVAL; 731123120Simp pay_len = 0; 732123120Simp } 733123120Simp } else { 734123120Simp pay_len = 0; 735123120Simp } 736123120Simp bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len); 737123120Simp bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, pay_len); 738123120Simpout: 739123120Simp fw_xfer_free_buf(xfer); 740123120Simp break; 741123120Simp } 742123120Simp case FW_IBUSRST: 743123120Simp fc->ibr(fc); 744123120Simp break; 745123120Simp case FW_CBINDADDR: 746123120Simp fwb = fw_bindlookup(fc, 747123120Simp bindreq->start.hi, bindreq->start.lo); 748123120Simp if(fwb == NULL){ 749123120Simp err = EINVAL; 750123120Simp break; 751123120Simp } 752123120Simp fw_bindremove(fc, fwb); 753123120Simp STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist); 754123120Simp fw_xferlist_remove(&fwb->xferlist); 755123120Simp free(fwb, M_FW); 756123120Simp break; 757123120Simp case FW_SBINDADDR: 758123120Simp if(bindreq->len <= 0 ){ 759123120Simp err = EINVAL; 760123120Simp break; 761123120Simp } 762123120Simp if(bindreq->start.hi > 0xffff ){ 763123120Simp err = EINVAL; 764123120Simp break; 765123120Simp } 766123120Simp fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_WAITOK); 767123120Simp if(fwb == NULL){ 768123120Simp err = ENOMEM; 769123120Simp break; 770123120Simp } 771123120Simp fwb->start = ((u_int64_t)bindreq->start.hi << 32) | 772123120Simp bindreq->start.lo; 773123120Simp fwb->end = fwb->start + bindreq->len; 774123120Simp fwb->sc = (void *)d; 775123120Simp STAILQ_INIT(&fwb->xferlist); 776123120Simp err = fw_bindadd(fc, fwb); 777123120Simp if (err == 0) { 778123120Simp fw_xferlist_add(&fwb->xferlist, M_FWXFER, 779123120Simp /* XXX */ 780123120Simp PAGE_SIZE, PAGE_SIZE, 5, 781123120Simp fc, (void *)fwb, fw_hand); 782123120Simp STAILQ_INSERT_TAIL(&d->binds, fwb, chlist); 783123120Simp } 784123120Simp break; 785123120Simp case FW_GDEVLST: 786123120Simp i = len = 1; 787123120Simp /* myself */ 788123120Simp devinfo = &fwdevlst->dev[0]; 789123120Simp devinfo->dst = fc->nodeid; 790123120Simp devinfo->status = 0; /* XXX */ 791123120Simp devinfo->eui.hi = fc->eui.hi; 792123120Simp devinfo->eui.lo = fc->eui.lo; 793123120Simp STAILQ_FOREACH(fwdev, &fc->devices, link) { 794123120Simp if(len < FW_MAX_DEVLST){ 795123120Simp devinfo = &fwdevlst->dev[len++]; 796123120Simp devinfo->dst = fwdev->dst; 797123120Simp devinfo->status = 798123120Simp (fwdev->status == FWDEVINVAL)?0:1; 799123120Simp devinfo->eui.hi = fwdev->eui.hi; 800123120Simp devinfo->eui.lo = fwdev->eui.lo; 801123120Simp } 802123120Simp i++; 803123120Simp } 804123120Simp fwdevlst->n = i; 805123120Simp fwdevlst->info_len = len; 806123120Simp break; 807123120Simp case FW_GTPMAP: 808123120Simp bcopy(fc->topology_map, data, 809123120Simp (fc->topology_map->crc_len + 1) * 4); 810123120Simp break; 811123120Simp case FW_GCROM: 812123120Simp STAILQ_FOREACH(fwdev, &fc->devices, link) 813123120Simp if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 814123120Simp break; 815123120Simp if (fwdev == NULL) { 816123120Simp if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) { 817123120Simp err = FWNODE_INVAL; 818123120Simp break; 819123120Simp } 820123120Simp /* myself */ 821123120Simp ptr = malloc(CROMSIZE, M_FW, M_WAITOK); 822123120Simp len = CROMSIZE; 823123120Simp for (i = 0; i < CROMSIZE/4; i++) 824123120Simp ((uint32_t *)ptr)[i] 825123120Simp = ntohl(fc->config_rom[i]); 826123120Simp } else { 827123120Simp /* found */ 828123120Simp ptr = (void *)&fwdev->csrrom[0]; 829123120Simp if (fwdev->rommax < CSRROMOFF) 830123120Simp len = 0; 831123120Simp else 832123120Simp len = fwdev->rommax - CSRROMOFF + 4; 833123120Simp } 834123120Simp if (crom_buf->len < len) 835123120Simp len = crom_buf->len; 836123120Simp else 837123120Simp crom_buf->len = len; 838123120Simp err = copyout(ptr, crom_buf->ptr, len); 839123120Simp if (fwdev == NULL) 840123120Simp /* myself */ 841123120Simp free(ptr, M_FW); 842123120Simp break; 843123120Simp default: 844123120Simp fc->ioctl (dev, cmd, data, flag, td); 845123120Simp break; 846123120Simp } 847123120Simp return err; 848123120Simp} 849123120Simpint 850123120Simpfw_poll(struct cdev *dev, int events, fw_proc *td) 851123120Simp{ 852123120Simp struct fw_xferq *ir; 853123120Simp int revents; 854123120Simp int tmp; 855123120Simp 856123120Simp if (DEV_FWMEM(dev)) 857123120Simp return fwmem_poll(dev, events, td); 858123120Simp 859123120Simp ir = ((struct fw_drv1 *)dev->si_drv1)->ir; 860123120Simp revents = 0; 861123120Simp tmp = POLLIN | POLLRDNORM; 862123120Simp if (events & tmp) { 863123120Simp if (STAILQ_FIRST(&ir->q) != NULL) 864123120Simp revents |= tmp; 865123120Simp else 866123120Simp selrecord(td, &ir->rsel); 867123120Simp } 868123120Simp tmp = POLLOUT | POLLWRNORM; 869123120Simp if (events & tmp) { 870123120Simp /* XXX should be fixed */ 871123120Simp revents |= tmp; 872123120Simp } 873123120Simp 874123120Simp return revents; 875123120Simp} 876123120Simp 877123120Simpstatic int 878277565Skevlofw_mmap (struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, 879277565Skevlo int nproto, vm_memattr_t *memattr) 880277565Skevlo{ 881123120Simp 882123120Simp if (DEV_FWMEM(dev)) 883123120Simp return fwmem_mmap(dev, offset, paddr, nproto, memattr); 884123120Simp 885123120Simp return EINVAL; 886123120Simp} 887123120Simp 888123120Simpstatic void 889123120Simpfw_strategy(struct bio *bp) 890123120Simp{ 891123120Simp struct cdev *dev; 892123120Simp 893123120Simp dev = bp->bio_dev; 894123120Simp if (DEV_FWMEM(dev)) { 895123120Simp fwmem_strategy(bp); 896123120Simp return; 897123120Simp } 898123120Simp 899123120Simp bp->bio_error = EOPNOTSUPP; 900123120Simp bp->bio_flags |= BIO_ERROR; 901123120Simp bp->bio_resid = bp->bio_bcount; 902123120Simp biodone(bp); 903123120Simp} 904123120Simp 905123120Simpint 906fwdev_makedev(struct firewire_softc *sc) 907{ 908 int err = 0; 909 910 struct cdev *d; 911 int unit; 912 913 unit = device_get_unit(sc->fc->bdev); 914 sc->dev = make_dev(&firewire_cdevsw, MAKEMINOR(0, unit, 0), 915 UID_ROOT, GID_OPERATOR, 0660, 916 "fw%d.%d", unit, 0); 917 d = make_dev(&firewire_cdevsw, 918 MAKEMINOR(FWMEM_FLAG, unit, 0), 919 UID_ROOT, GID_OPERATOR, 0660, 920 "fwmem%d.%d", unit, 0); 921 dev_depends(sc->dev, d); 922 make_dev_alias(sc->dev, "fw%d", unit); 923 make_dev_alias(d, "fwmem%d", unit); 924 925 return (err); 926} 927 928int 929fwdev_destroydev(struct firewire_softc *sc) 930{ 931 int err = 0; 932 933 destroy_dev(sc->dev); 934 return (err); 935} 936 937#define NDEVTYPE 2 938void 939fwdev_clone(void *arg, struct ucred *cred, char *name, int namelen, 940 struct cdev **dev) 941{ 942 struct firewire_softc *sc; 943 char *devnames[NDEVTYPE] = {"fw", "fwmem"}; 944 char *subp = NULL; 945 int devflag[NDEVTYPE] = {0, FWMEM_FLAG}; 946 int i, unit = 0, sub = 0; 947 948 if (*dev != NULL) 949 return; 950 951 for (i = 0; i < NDEVTYPE; i++) 952 if (dev_stdclone(name, &subp, devnames[i], &unit) == 2) 953 goto found; 954 /* not match */ 955 return; 956found: 957 958 if (subp == NULL || *subp++ != '.') 959 return; 960 961 /* /dev/fwU.S */ 962 while (isdigit(*subp)) { 963 sub *= 10; 964 sub += *subp++ - '0'; 965 } 966 if (*subp != '\0') 967 return; 968 969 sc = devclass_get_softc(firewire_devclass, unit); 970 if (sc == NULL) 971 return; 972 *dev = make_dev_credf(MAKEDEV_REF, &firewire_cdevsw, 973 MAKEMINOR(devflag[i], unit, sub), cred, UID_ROOT, GID_OPERATOR, 974 0660, "%s%d.%d", devnames[i], unit, sub); 975 dev_depends(sc->dev, *dev); 976 return; 977} 978