fwdev.c revision 108782
1106813Ssimokawa/* 2106813Ssimokawa * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 3106813Ssimokawa * All rights reserved. 4106813Ssimokawa * 5106813Ssimokawa * Redistribution and use in source and binary forms, with or without 6106813Ssimokawa * modification, are permitted provided that the following conditions 7106813Ssimokawa * are met: 8106813Ssimokawa * 1. Redistributions of source code must retain the above copyright 9106813Ssimokawa * notice, this list of conditions and the following disclaimer. 10106813Ssimokawa * 2. Redistributions in binary form must reproduce the above copyright 11106813Ssimokawa * notice, this list of conditions and the following disclaimer in the 12106813Ssimokawa * documentation and/or other materials provided with the distribution. 13106813Ssimokawa * 3. All advertising materials mentioning features or use of this software 14106813Ssimokawa * must display the acknowledgement as bellow: 15106813Ssimokawa * 16106813Ssimokawa * This product includes software developed by K. Kobayashi and H. Shimokawa 17106813Ssimokawa * 18106813Ssimokawa * 4. The name of the author may not be used to endorse or promote products 19106813Ssimokawa * derived from this software without specific prior written permission. 20106813Ssimokawa * 21106813Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22106813Ssimokawa * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23106813Ssimokawa * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24106813Ssimokawa * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 25106813Ssimokawa * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26106813Ssimokawa * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27106813Ssimokawa * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28106813Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29106813Ssimokawa * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30106813Ssimokawa * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31106813Ssimokawa * POSSIBILITY OF SUCH DAMAGE. 32106813Ssimokawa * 33106813Ssimokawa * $FreeBSD: head/sys/dev/firewire/fwdev.c 108782 2003-01-06 08:07:20Z simokawa $ 34106813Ssimokawa * 35106813Ssimokawa */ 36106813Ssimokawa 37106813Ssimokawa#include <sys/param.h> 38106813Ssimokawa#include <sys/systm.h> 39106813Ssimokawa#include <sys/types.h> 40106813Ssimokawa#include <sys/mbuf.h> 41106813Ssimokawa 42106813Ssimokawa#include <sys/kernel.h> 43106813Ssimokawa#include <sys/malloc.h> 44106813Ssimokawa#include <sys/conf.h> 45106813Ssimokawa#include <sys/uio.h> 46106813Ssimokawa#include <sys/poll.h> 47106813Ssimokawa 48106813Ssimokawa#include <sys/bus.h> 49106813Ssimokawa 50106813Ssimokawa#include <sys/ioccom.h> 51106813Ssimokawa 52106813Ssimokawa#include <dev/firewire/firewire.h> 53106813Ssimokawa#include <dev/firewire/firewirereg.h> 54106813Ssimokawa#include <dev/firewire/fwmem.h> 55106813Ssimokawa 56106813Ssimokawa#define CDEV_MAJOR 127 57106813Ssimokawa#define FWNODE_INVAL 0xffff 58106813Ssimokawa 59106813Ssimokawastatic d_open_t fw_open; 60106813Ssimokawastatic d_close_t fw_close; 61106813Ssimokawastatic d_ioctl_t fw_ioctl; 62106813Ssimokawastatic d_poll_t fw_poll; 63106813Ssimokawastatic d_read_t fw_read; /* for Isochronous packet */ 64106813Ssimokawastatic d_write_t fw_write; 65106813Ssimokawastatic d_mmap_t fw_mmap; 66106813Ssimokawa 67106813Ssimokawastruct cdevsw firewire_cdevsw = 68106813Ssimokawa{ 69106813Ssimokawa fw_open, fw_close, fw_read, fw_write, fw_ioctl, 70106813Ssimokawa fw_poll, fw_mmap, nostrategy, "fw", CDEV_MAJOR, nodump, nopsize, D_MEM 71106813Ssimokawa}; 72106813Ssimokawa 73106813Ssimokawastatic int 74106813Ssimokawafw_open (dev_t dev, int flags, int fmt, fw_proc *td) 75106813Ssimokawa{ 76106813Ssimokawa struct firewire_softc *sc; 77106813Ssimokawa int unit = DEV2UNIT(dev); 78106813Ssimokawa int sub = DEV2DMACH(dev); 79106813Ssimokawa 80106813Ssimokawa int err = 0; 81106813Ssimokawa 82106813Ssimokawa if (DEV_FWMEM(dev)) 83106813Ssimokawa return fwmem_open(dev, flags, fmt, td); 84106813Ssimokawa 85106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 86106813Ssimokawa if(sc->fc->ir[sub]->flag & FWXFERQ_OPEN){ 87106813Ssimokawa err = EBUSY; 88106813Ssimokawa return err; 89106813Ssimokawa } 90106813Ssimokawa if(sc->fc->it[sub]->flag & FWXFERQ_OPEN){ 91106813Ssimokawa err = EBUSY; 92106813Ssimokawa return err; 93106813Ssimokawa } 94106813Ssimokawa if(sc->fc->ir[sub]->flag & FWXFERQ_MODEMASK){ 95106813Ssimokawa err = EBUSY; 96106813Ssimokawa return err; 97106813Ssimokawa } 98106813Ssimokawa/* Default is per packet mode */ 99106813Ssimokawa sc->fc->ir[sub]->flag |= FWXFERQ_OPEN; 100106813Ssimokawa sc->fc->it[sub]->flag |= FWXFERQ_OPEN; 101106813Ssimokawa sc->fc->ir[sub]->flag |= FWXFERQ_PACKET; 102106813Ssimokawa return err; 103106813Ssimokawa} 104106813Ssimokawa 105106813Ssimokawastatic int 106106813Ssimokawafw_close (dev_t dev, int flags, int fmt, fw_proc *td) 107106813Ssimokawa{ 108106813Ssimokawa struct firewire_softc *sc; 109106813Ssimokawa int unit = DEV2UNIT(dev); 110106813Ssimokawa int sub = DEV2DMACH(dev); 111106813Ssimokawa struct fw_xfer *xfer; 112106813Ssimokawa struct fw_dvbuf *dvbuf; 113106813Ssimokawa struct fw_bind *fwb; 114106813Ssimokawa int err = 0; 115106813Ssimokawa 116106813Ssimokawa if (DEV_FWMEM(dev)) 117106813Ssimokawa return fwmem_close(dev, flags, fmt, td); 118106813Ssimokawa 119106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 120106813Ssimokawa if(!(sc->fc->ir[sub]->flag & FWXFERQ_OPEN)){ 121106813Ssimokawa err = EINVAL; 122106813Ssimokawa return err; 123106813Ssimokawa } 124106813Ssimokawa sc->fc->ir[sub]->flag &= ~FWXFERQ_OPEN; 125106813Ssimokawa if(!(sc->fc->it[sub]->flag & FWXFERQ_OPEN)){ 126106813Ssimokawa err = EINVAL; 127106813Ssimokawa return err; 128106813Ssimokawa } 129106813Ssimokawa sc->fc->it[sub]->flag &= ~FWXFERQ_OPEN; 130106813Ssimokawa 131106813Ssimokawa if(sc->fc->ir[sub]->flag & FWXFERQ_RUNNING){ 132106813Ssimokawa sc->fc->irx_disable(sc->fc, sub); 133106813Ssimokawa } 134106813Ssimokawa if(sc->fc->it[sub]->flag & FWXFERQ_RUNNING){ 135106813Ssimokawa sc->fc->it[sub]->flag &= ~FWXFERQ_RUNNING; 136106813Ssimokawa sc->fc->itx_disable(sc->fc, sub); 137106813Ssimokawa } 138106813Ssimokawa if(sc->fc->it[sub]->flag & FWXFERQ_DV){ 139106813Ssimokawa if((dvbuf = sc->fc->it[sub]->dvproc) != NULL){ 140106813Ssimokawa free(dvbuf->buf, M_DEVBUF); 141106813Ssimokawa sc->fc->it[sub]->dvproc = NULL; 142106813Ssimokawa } 143106813Ssimokawa if((dvbuf = sc->fc->it[sub]->dvdma) != NULL){ 144106813Ssimokawa free(dvbuf->buf, M_DEVBUF); 145106813Ssimokawa sc->fc->it[sub]->dvdma = NULL; 146106813Ssimokawa } 147106813Ssimokawa while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvvalid)) != NULL){ 148106813Ssimokawa STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvvalid, link); 149106813Ssimokawa free(dvbuf->buf, M_DEVBUF); 150106813Ssimokawa } 151106813Ssimokawa while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvfree)) != NULL){ 152106813Ssimokawa STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvfree, link); 153106813Ssimokawa free(dvbuf->buf, M_DEVBUF); 154106813Ssimokawa } 155106813Ssimokawa free(sc->fc->it[sub]->dvbuf, M_DEVBUF); 156106813Ssimokawa sc->fc->it[sub]->dvbuf = NULL; 157106813Ssimokawa } 158106813Ssimokawa if(sc->fc->ir[sub]->flag & FWXFERQ_EXTBUF){ 159106813Ssimokawa free(sc->fc->ir[sub]->buf, M_DEVBUF); 160106813Ssimokawa sc->fc->ir[sub]->buf = NULL; 161106813Ssimokawa free(sc->fc->ir[sub]->bulkxfer, M_DEVBUF); 162106813Ssimokawa sc->fc->ir[sub]->bulkxfer = NULL; 163106813Ssimokawa sc->fc->ir[sub]->flag &= ~FWXFERQ_EXTBUF; 164106813Ssimokawa sc->fc->ir[sub]->psize = FWPMAX_S400; 165106813Ssimokawa sc->fc->ir[sub]->maxq = FWMAXQUEUE; 166106813Ssimokawa } 167106813Ssimokawa if(sc->fc->it[sub]->flag & FWXFERQ_EXTBUF){ 168106813Ssimokawa free(sc->fc->it[sub]->buf, M_DEVBUF); 169106813Ssimokawa sc->fc->it[sub]->buf = NULL; 170106813Ssimokawa free(sc->fc->it[sub]->bulkxfer, M_DEVBUF); 171106813Ssimokawa sc->fc->it[sub]->bulkxfer = NULL; 172106813Ssimokawa sc->fc->it[sub]->dvbuf = NULL; 173106813Ssimokawa sc->fc->it[sub]->flag &= ~FWXFERQ_EXTBUF; 174106813Ssimokawa sc->fc->it[sub]->psize = FWPMAX_S400; 175106813Ssimokawa sc->fc->it[sub]->maxq = FWMAXQUEUE; 176106813Ssimokawa } 177106813Ssimokawa for(xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q); 178106813Ssimokawa xfer != NULL; xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q)){ 179106813Ssimokawa sc->fc->ir[sub]->queued--; 180106813Ssimokawa STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->q, link); 181106813Ssimokawa 182106813Ssimokawa xfer->resp = 0; 183106813Ssimokawa switch(xfer->act_type){ 184106813Ssimokawa case FWACT_XFER: 185106813Ssimokawa fw_xfer_done(xfer); 186106813Ssimokawa break; 187106813Ssimokawa default: 188106813Ssimokawa break; 189106813Ssimokawa } 190106813Ssimokawa fw_xfer_free(xfer); 191106813Ssimokawa } 192106813Ssimokawa for(fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds); fwb != NULL; 193106813Ssimokawa fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds)){ 194106813Ssimokawa STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 195106813Ssimokawa STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->binds, chlist); 196106813Ssimokawa free(fwb, M_DEVBUF); 197106813Ssimokawa } 198106813Ssimokawa sc->fc->ir[sub]->flag &= ~FWXFERQ_MODEMASK; 199106813Ssimokawa sc->fc->it[sub]->flag &= ~FWXFERQ_MODEMASK; 200106813Ssimokawa return err; 201106813Ssimokawa} 202106813Ssimokawa 203106813Ssimokawa/* 204106813Ssimokawa * read request. 205106813Ssimokawa */ 206106813Ssimokawastatic int 207106813Ssimokawafw_read (dev_t dev, struct uio *uio, int ioflag) 208106813Ssimokawa{ 209106813Ssimokawa struct firewire_softc *sc; 210106813Ssimokawa struct fw_xferq *ir; 211106813Ssimokawa struct fw_xfer *xfer; 212106813Ssimokawa int err = 0, s, slept = 0; 213106813Ssimokawa int unit = DEV2UNIT(dev); 214106813Ssimokawa int sub = DEV2DMACH(dev); 215106813Ssimokawa struct fw_pkt *fp; 216106813Ssimokawa 217106813Ssimokawa if (DEV_FWMEM(dev)) 218106813Ssimokawa return fwmem_read(dev, uio, ioflag); 219106813Ssimokawa 220106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 221106813Ssimokawa 222106813Ssimokawa ir = sc->fc->ir[sub]; 223106813Ssimokawa 224106813Ssimokawa if(ir->flag & FWXFERQ_PACKET){ 225106813Ssimokawa ir->stproc = NULL; 226106813Ssimokawa } 227106813Ssimokawareadloop: 228106813Ssimokawa xfer = STAILQ_FIRST(&ir->q); 229106813Ssimokawa if(!(ir->flag & FWXFERQ_PACKET) && ir->stproc == NULL){ 230106813Ssimokawa ir->stproc = STAILQ_FIRST(&ir->stvalid); 231106813Ssimokawa if(ir->stproc != NULL){ 232106813Ssimokawa s = splfw(); 233106813Ssimokawa STAILQ_REMOVE_HEAD(&ir->stvalid, link); 234106813Ssimokawa splx(s); 235106813Ssimokawa ir->queued = 0; 236106813Ssimokawa } 237106813Ssimokawa } 238106813Ssimokawa 239106813Ssimokawa if(xfer == NULL && ir->stproc == NULL){ 240106813Ssimokawa if(slept == 0){ 241106813Ssimokawa slept = 1; 242106813Ssimokawa if(!(ir->flag & FWXFERQ_RUNNING) 243106813Ssimokawa && (ir->flag & FWXFERQ_PACKET)){ 244106813Ssimokawa err = sc->fc->irx_enable(sc->fc, sub); 245106813Ssimokawa } 246106813Ssimokawa if(err){ 247106813Ssimokawa return err; 248106813Ssimokawa } 249106813Ssimokawa ir->flag |= FWXFERQ_WAKEUP; 250106813Ssimokawa err = tsleep((caddr_t)ir, FWPRI, "fw_read", hz); 251106813Ssimokawa if(err){ 252106813Ssimokawa ir->flag &= ~FWXFERQ_WAKEUP; 253106813Ssimokawa return err; 254106813Ssimokawa } 255106813Ssimokawa goto readloop; 256106813Ssimokawa }else{ 257106813Ssimokawa err = EIO; 258106813Ssimokawa return err; 259106813Ssimokawa } 260106813Ssimokawa }else if(xfer != NULL){ 261106813Ssimokawa s = splfw(); 262106813Ssimokawa ir->queued --; 263106813Ssimokawa STAILQ_REMOVE_HEAD(&ir->q, link); 264106813Ssimokawa splx(s); 265106813Ssimokawa fp = (struct fw_pkt *)(xfer->recv.buf + xfer->recv.off); 266106813Ssimokawa if(sc->fc->irx_post != NULL) 267106813Ssimokawa sc->fc->irx_post(sc->fc, fp->mode.ld); 268106813Ssimokawa err = uiomove(xfer->recv.buf + xfer->recv.off, xfer->recv.len, uio); 269106813Ssimokawa fw_xfer_free( xfer); 270106813Ssimokawa }else if(ir->stproc != NULL){ 271106813Ssimokawa fp = (struct fw_pkt *)(ir->stproc->buf + ir->queued * ir->psize); 272106813Ssimokawa if(sc->fc->irx_post != NULL) 273106813Ssimokawa sc->fc->irx_post(sc->fc, fp->mode.ld); 274106813Ssimokawa if(ntohs(fp->mode.stream.len) == 0){ 275106813Ssimokawa err = EIO; 276106813Ssimokawa return err; 277106813Ssimokawa } 278106813Ssimokawa err = uiomove((caddr_t)fp, ntohs(fp->mode.stream.len) + sizeof(u_int32_t), uio); 279106813Ssimokawa fp->mode.stream.len = 0; 280106813Ssimokawa ir->queued ++; 281106813Ssimokawa if(ir->queued >= ir->bnpacket){ 282106813Ssimokawa s = splfw(); 283106813Ssimokawa ir->stproc->flag = 0; 284106813Ssimokawa STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 285106813Ssimokawa splx(s); 286106813Ssimokawa ir->stproc = NULL; 287106813Ssimokawa } 288106813Ssimokawa } 289106813Ssimokawa#if 0 290106813Ssimokawa if(STAILQ_FIRST(&ir->q) == NULL && 291106813Ssimokawa (ir->flag & FWXFERQ_RUNNING) && (ir->flag & FWXFERQ_PACKET)){ 292106813Ssimokawa err = sc->fc->irx_enable(sc->fc, sub); 293106813Ssimokawa } 294106813Ssimokawa#endif 295106813Ssimokawa#if 0 296106813Ssimokawa if(STAILQ_FIRST(&ir->stvalid) == NULL && 297106813Ssimokawa (ir->flag & FWXFERQ_RUNNING) && !(ir->flag & FWXFERQ_PACKET)){ 298106813Ssimokawa err = sc->fc->irx_enable(sc->fc, sub); 299106813Ssimokawa } 300106813Ssimokawa#endif 301106813Ssimokawa return err; 302106813Ssimokawa} 303106813Ssimokawa 304106813Ssimokawastatic int 305106813Ssimokawafw_write (dev_t dev, struct uio *uio, int ioflag) 306106813Ssimokawa{ 307106813Ssimokawa int err = 0; 308106813Ssimokawa struct firewire_softc *sc; 309106813Ssimokawa int unit = DEV2UNIT(dev); 310106813Ssimokawa int sub = DEV2DMACH(dev); 311106813Ssimokawa int s, slept = 0; 312106813Ssimokawa struct fw_pkt *fp; 313106813Ssimokawa struct fw_xfer *xfer; 314106813Ssimokawa struct fw_xferq *xferq; 315106813Ssimokawa struct firewire_comm *fc; 316106813Ssimokawa struct fw_xferq *it; 317106813Ssimokawa 318106813Ssimokawa if (DEV_FWMEM(dev)) 319106813Ssimokawa return fwmem_write(dev, uio, ioflag); 320106813Ssimokawa 321106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 322106813Ssimokawa fc = sc->fc; 323106813Ssimokawa it = sc->fc->it[sub]; 324106813Ssimokawa 325106813Ssimokawa fp = (struct fw_pkt *)uio->uio_iov->iov_base; 326106813Ssimokawa switch(fp->mode.common.tcode){ 327106813Ssimokawa case FWTCODE_RREQQ: 328106813Ssimokawa case FWTCODE_RREQB: 329106813Ssimokawa case FWTCODE_LREQ: 330106813Ssimokawa err = EINVAL; 331106813Ssimokawa return err; 332106813Ssimokawa case FWTCODE_WREQQ: 333106813Ssimokawa case FWTCODE_WREQB: 334106813Ssimokawa xferq = fc->atq; 335106813Ssimokawa break; 336106813Ssimokawa case FWTCODE_STREAM: 337106813Ssimokawa if(it->flag & FWXFERQ_PACKET){ 338106813Ssimokawa xferq = fc->atq; 339106813Ssimokawa }else{ 340106813Ssimokawa xferq = NULL; 341106813Ssimokawa } 342106813Ssimokawa break; 343106813Ssimokawa case FWTCODE_WRES: 344106813Ssimokawa case FWTCODE_RRESQ: 345106813Ssimokawa case FWTCODE_RRESB: 346106813Ssimokawa case FWTCODE_LRES: 347106813Ssimokawa xferq = fc->ats; 348106813Ssimokawa break; 349106813Ssimokawa default: 350106813Ssimokawa err = EINVAL; 351106813Ssimokawa return err; 352106813Ssimokawa } 353106813Ssimokawa /* Discard unsent buffered stream packet, when sending Asyrequrst */ 354106813Ssimokawa if(xferq != NULL && it->stproc != NULL){ 355106813Ssimokawa s = splfw(); 356106813Ssimokawa it->stproc->flag = 0; 357106813Ssimokawa STAILQ_INSERT_TAIL(&it->stfree, it->stproc, link); 358106813Ssimokawa splx(s); 359106813Ssimokawa it->stproc = NULL; 360106813Ssimokawa } 361106813Ssimokawa if(xferq == NULL && !(it->flag & FWXFERQ_DV)){ 362106813Ssimokawaisoloop: 363106813Ssimokawa if(it->stproc == NULL){ 364106813Ssimokawa it->stproc = STAILQ_FIRST(&it->stfree); 365106813Ssimokawa if(it->stproc != NULL){ 366106813Ssimokawa s = splfw(); 367106813Ssimokawa STAILQ_REMOVE_HEAD(&it->stfree, link); 368106813Ssimokawa splx(s); 369106813Ssimokawa it->queued = 0; 370106813Ssimokawa }else if(slept == 0){ 371106813Ssimokawa slept = 1; 372106813Ssimokawa err = sc->fc->itx_enable(sc->fc, sub); 373106813Ssimokawa if(err){ 374106813Ssimokawa return err; 375106813Ssimokawa } 376106813Ssimokawa err = tsleep((caddr_t)it, FWPRI, "fw_write", hz); 377106813Ssimokawa if(err){ 378106813Ssimokawa return err; 379106813Ssimokawa } 380106813Ssimokawa goto isoloop; 381106813Ssimokawa }else{ 382106813Ssimokawa err = EIO; 383106813Ssimokawa return err; 384106813Ssimokawa } 385106813Ssimokawa } 386106813Ssimokawa fp = (struct fw_pkt *)(it->stproc->buf + it->queued * it->psize); 387106813Ssimokawa fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t)); 388106813Ssimokawa err = uiomove(it->stproc->buf + it->queued * it->psize, 389106813Ssimokawa uio->uio_resid, uio); 390106813Ssimokawa it->queued ++; 391106813Ssimokawa if(it->queued >= it->btpacket){ 392106813Ssimokawa s = splfw(); 393106813Ssimokawa STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 394106813Ssimokawa splx(s); 395106813Ssimokawa it->stproc = NULL; 396106813Ssimokawa fw_tbuf_update(sc->fc, sub, 0); 397106813Ssimokawa err = sc->fc->itx_enable(sc->fc, sub); 398106813Ssimokawa } 399106813Ssimokawa return err; 400106813Ssimokawa } if(xferq == NULL && it->flag & FWXFERQ_DV){ 401106813Ssimokawadvloop: 402106813Ssimokawa if(it->dvproc == NULL){ 403106813Ssimokawa it->dvproc = STAILQ_FIRST(&it->dvfree); 404106813Ssimokawa if(it->dvproc != NULL){ 405106813Ssimokawa s = splfw(); 406106813Ssimokawa STAILQ_REMOVE_HEAD(&it->dvfree, link); 407106813Ssimokawa splx(s); 408106813Ssimokawa it->dvptr = 0; 409106813Ssimokawa }else if(slept == 0){ 410106813Ssimokawa slept = 1; 411106813Ssimokawa err = sc->fc->itx_enable(sc->fc, sub); 412106813Ssimokawa if(err){ 413106813Ssimokawa return err; 414106813Ssimokawa } 415106813Ssimokawa err = tsleep((caddr_t)it, FWPRI, "fw_write", hz); 416106813Ssimokawa if(err){ 417106813Ssimokawa return err; 418106813Ssimokawa } 419106813Ssimokawa goto dvloop; 420106813Ssimokawa }else{ 421106813Ssimokawa err = EIO; 422106813Ssimokawa return err; 423106813Ssimokawa } 424106813Ssimokawa } 425106813Ssimokawa fp = (struct fw_pkt *)(it->dvproc->buf + it->queued * it->psize); 426106813Ssimokawa fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t)); 427106813Ssimokawa err = uiomove(it->dvproc->buf + it->dvptr, 428106813Ssimokawa uio->uio_resid, uio); 429106813Ssimokawa it->dvptr += it->psize; 430106813Ssimokawa if(err){ 431106813Ssimokawa return err; 432106813Ssimokawa } 433106813Ssimokawa if(it->dvptr >= it->psize * it->dvpacket){ 434106813Ssimokawa s = splfw(); 435106813Ssimokawa STAILQ_INSERT_TAIL(&it->dvvalid, it->dvproc, link); 436106813Ssimokawa splx(s); 437106813Ssimokawa it->dvproc = NULL; 438106813Ssimokawa err = fw_tbuf_update(sc->fc, sub, 0); 439106813Ssimokawa if(err){ 440106813Ssimokawa return err; 441106813Ssimokawa } 442106813Ssimokawa err = sc->fc->itx_enable(sc->fc, sub); 443106813Ssimokawa } 444106813Ssimokawa return err; 445106813Ssimokawa } 446106813Ssimokawa if(xferq != NULL){ 447106813Ssimokawa xfer = fw_xfer_alloc(); 448106813Ssimokawa if(xfer == NULL){ 449106813Ssimokawa err = ENOMEM; 450106813Ssimokawa return err; 451106813Ssimokawa } 452106813Ssimokawa xfer->send.buf = malloc(uio->uio_resid, M_DEVBUF, M_NOWAIT); 453106813Ssimokawa if(xfer->send.buf == NULL){ 454106813Ssimokawa fw_xfer_free( xfer); 455106813Ssimokawa err = ENOBUFS; 456106813Ssimokawa return err; 457106813Ssimokawa } 458106813Ssimokawa xfer->dst = ntohs(fp->mode.hdr.dst); 459106813Ssimokawa#if 0 460106813Ssimokawa switch(fp->mode.common.tcode){ 461106813Ssimokawa case FWTCODE_WREQQ: 462106813Ssimokawa case FWTCODE_WREQB: 463106813Ssimokawa if((tl = fw_get_tlabel(fc, xfer)) == -1 ){ 464106813Ssimokawa fw_xfer_free( xfer); 465106813Ssimokawa err = EAGAIN; 466106813Ssimokawa return err; 467106813Ssimokawa } 468106813Ssimokawa fp->mode.hdr.tlrt = tl << 2; 469106813Ssimokawa default: 470106813Ssimokawa break; 471106813Ssimokawa } 472106813Ssimokawa 473106813Ssimokawa xfer->tl = fp->mode.hdr.tlrt >> 2; 474106813Ssimokawa xfer->tcode = fp->mode.common.tcode; 475106813Ssimokawa xfer->fc = fc; 476106813Ssimokawa xfer->q = xferq; 477106813Ssimokawa xfer->act_type = FWACT_XFER; 478106813Ssimokawa xfer->retry_req = fw_asybusy; 479106813Ssimokawa#endif 480106813Ssimokawa xfer->send.len = uio->uio_resid; 481106813Ssimokawa xfer->send.off = 0; 482106813Ssimokawa xfer->spd = 0;/* XXX: how to setup it */ 483106813Ssimokawa xfer->act.hand = fw_asy_callback; 484106813Ssimokawa 485106813Ssimokawa err = uiomove(xfer->send.buf, uio->uio_resid, uio); 486106813Ssimokawa if(err){ 487106813Ssimokawa fw_xfer_free( xfer); 488106813Ssimokawa return err; 489106813Ssimokawa } 490106813Ssimokawa#if 0 491106813Ssimokawa fw_asystart(xfer); 492106813Ssimokawa#else 493106813Ssimokawa fw_asyreq(fc, -1, xfer); 494106813Ssimokawa#endif 495106813Ssimokawa err = tsleep((caddr_t)xfer, FWPRI, "fw_write", hz); 496106813Ssimokawa if(xfer->resp == EBUSY) 497106813Ssimokawa return EBUSY; 498106813Ssimokawa fw_xfer_free( xfer); 499106813Ssimokawa return err; 500106813Ssimokawa } 501106813Ssimokawa return EINVAL; 502106813Ssimokawa} 503106813Ssimokawa 504106813Ssimokawa/* 505106813Ssimokawa * ioctl support. 506106813Ssimokawa */ 507106813Ssimokawaint 508106813Ssimokawafw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 509106813Ssimokawa{ 510106813Ssimokawa struct firewire_softc *sc; 511106813Ssimokawa int unit = DEV2UNIT(dev); 512106813Ssimokawa int sub = DEV2DMACH(dev); 513106813Ssimokawa int i, len, err = 0; 514106813Ssimokawa struct fw_device *fwdev; 515106813Ssimokawa struct fw_bind *fwb; 516106813Ssimokawa struct fw_xferq *ir, *it; 517106813Ssimokawa struct fw_xfer *xfer; 518106813Ssimokawa struct fw_pkt *fp; 519106813Ssimokawa 520106813Ssimokawa struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 521106813Ssimokawa struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 522106813Ssimokawa struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 523106813Ssimokawa struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 524106813Ssimokawa struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 525106813Ssimokawa#if 0 526106813Ssimokawa struct fw_map_buf *map_buf = (struct fw_map_buf *)data; 527106813Ssimokawa#endif 528106813Ssimokawa struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 529106813Ssimokawa 530106813Ssimokawa if (DEV_FWMEM(dev)) 531106813Ssimokawa return fwmem_ioctl(dev, cmd, data, flag, td); 532106813Ssimokawa 533106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 534106813Ssimokawa if (!data) 535106813Ssimokawa return(EINVAL); 536106813Ssimokawa 537106813Ssimokawa switch (cmd) { 538106813Ssimokawa case FW_STSTREAM: 539106813Ssimokawa sc->fc->it[sub]->flag &= ~0xff; 540106813Ssimokawa sc->fc->it[sub]->flag |= (0x3f & ichreq->ch); 541106813Ssimokawa sc->fc->it[sub]->flag |= ((0x3 & ichreq->tag) << 6); 542106813Ssimokawa err = 0; 543106813Ssimokawa break; 544106813Ssimokawa case FW_GTSTREAM: 545106813Ssimokawa ichreq->ch = sc->fc->it[sub]->flag & 0x3f; 546106813Ssimokawa ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3; 547106813Ssimokawa err = 0; 548106813Ssimokawa break; 549106813Ssimokawa case FW_SRSTREAM: 550106813Ssimokawa sc->fc->ir[sub]->flag &= ~0xff; 551106813Ssimokawa sc->fc->ir[sub]->flag |= (0x3f & ichreq->ch); 552106813Ssimokawa sc->fc->ir[sub]->flag |= ((0x3 & ichreq->tag) << 6); 553106813Ssimokawa err = sc->fc->irx_enable(sc->fc, sub); 554106813Ssimokawa break; 555106813Ssimokawa case FW_GRSTREAM: 556106813Ssimokawa ichreq->ch = sc->fc->ir[sub]->flag & 0x3f; 557106813Ssimokawa ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3; 558106813Ssimokawa err = 0; 559106813Ssimokawa break; 560106813Ssimokawa case FW_SSTDV: 561106813Ssimokawa ibufreq = (struct fw_isobufreq *) 562106813Ssimokawa malloc(sizeof(struct fw_isobufreq), M_DEVBUF, M_NOWAIT); 563106813Ssimokawa if(ibufreq == NULL){ 564106813Ssimokawa err = ENOMEM; 565106813Ssimokawa break; 566106813Ssimokawa } 567106813Ssimokawa#define FWDVPACKET 250 568106813Ssimokawa#define FWDVPMAX 512 569106813Ssimokawa ibufreq->rx.nchunk = 8; 570106813Ssimokawa ibufreq->rx.npacket = 50; 571106813Ssimokawa ibufreq->rx.psize = FWDVPMAX; 572106813Ssimokawa 573106813Ssimokawa ibufreq->tx.nchunk = 5; 574106813Ssimokawa ibufreq->tx.npacket = 300; 575106813Ssimokawa ibufreq->tx.psize = FWDVPMAX; 576106813Ssimokawa 577106813Ssimokawa err = fw_ioctl(dev, FW_SSTBUF, (caddr_t)ibufreq, flag, td); 578106813Ssimokawa sc->fc->it[sub]->dvpacket = FWDVPACKET; 579106813Ssimokawa free(ibufreq, M_DEVBUF); 580106813Ssimokawa/* reserve a buffer space */ 581106813Ssimokawa#define NDVCHUNK 8 582106813Ssimokawa sc->fc->it[sub]->dvproc = NULL; 583106813Ssimokawa sc->fc->it[sub]->dvdma = NULL; 584106813Ssimokawa sc->fc->it[sub]->flag |= FWXFERQ_DV; 585106813Ssimokawa sc->fc->it[sub]->dvbuf 586106813Ssimokawa = (struct fw_dvbuf *)malloc(sizeof(struct fw_dvbuf) * NDVCHUNK, M_DEVBUF, M_DONTWAIT); 587106813Ssimokawa STAILQ_INIT(&sc->fc->it[sub]->dvvalid); 588106813Ssimokawa STAILQ_INIT(&sc->fc->it[sub]->dvfree); 589106813Ssimokawa for( i = 0 ; i < NDVCHUNK ; i++){ 590106813Ssimokawa sc->fc->it[sub]->dvbuf[i].buf 591106813Ssimokawa = malloc(FWDVPMAX * sc->fc->it[sub]->dvpacket, M_DEVBUF, M_DONTWAIT); 592106813Ssimokawa STAILQ_INSERT_TAIL(&sc->fc->it[sub]->dvfree, 593106813Ssimokawa &sc->fc->it[sub]->dvbuf[i], link); 594106813Ssimokawa } 595106813Ssimokawa break; 596106813Ssimokawa case FW_SSTBUF: 597106813Ssimokawa ir = sc->fc->ir[sub]; 598106813Ssimokawa it = sc->fc->it[sub]; 599106813Ssimokawa 600106813Ssimokawa if(ir->flag & FWXFERQ_RUNNING || it->flag & FWXFERQ_RUNNING){ 601106813Ssimokawa return(EBUSY); 602106813Ssimokawa } 603106813Ssimokawa if((ir->flag & FWXFERQ_EXTBUF) || (it->flag & FWXFERQ_EXTBUF)){ 604106813Ssimokawa return(EBUSY); 605106813Ssimokawa } 606106813Ssimokawa if((ibufreq->rx.nchunk * 607106813Ssimokawa ibufreq->rx.psize * ibufreq->rx.npacket) + 608106813Ssimokawa (ibufreq->tx.nchunk * 609106813Ssimokawa ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){ 610106813Ssimokawa return(EINVAL); 611106813Ssimokawa } 612106813Ssimokawa if(ibufreq->rx.nchunk > FWSTMAXCHUNK || 613106813Ssimokawa ibufreq->tx.nchunk > FWSTMAXCHUNK){ 614106813Ssimokawa return(EINVAL); 615106813Ssimokawa } 616106813Ssimokawa ir->bulkxfer 617106813Ssimokawa = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_DEVBUF, M_DONTWAIT); 618106813Ssimokawa if(ir->bulkxfer == NULL){ 619106813Ssimokawa return(ENOMEM); 620106813Ssimokawa } 621106813Ssimokawa it->bulkxfer 622106813Ssimokawa = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_DEVBUF, M_DONTWAIT); 623106813Ssimokawa if(it->bulkxfer == NULL){ 624106813Ssimokawa return(ENOMEM); 625106813Ssimokawa } 626106813Ssimokawa ir->buf = malloc( 627106813Ssimokawa ibufreq->rx.nchunk * ibufreq->rx.npacket 628106813Ssimokawa * ((ibufreq->rx.psize + 3) &~3), 629106813Ssimokawa M_DEVBUF, M_DONTWAIT); 630106813Ssimokawa if(ir->buf == NULL){ 631106813Ssimokawa free(ir->bulkxfer, M_DEVBUF); 632106813Ssimokawa free(it->bulkxfer, M_DEVBUF); 633106813Ssimokawa ir->bulkxfer = NULL; 634106813Ssimokawa it->bulkxfer = NULL; 635106813Ssimokawa it->buf = NULL; 636106813Ssimokawa return(ENOMEM); 637106813Ssimokawa } 638106813Ssimokawa it->buf = malloc( 639106813Ssimokawa ibufreq->tx.nchunk * ibufreq->tx.npacket 640106813Ssimokawa * ((ibufreq->tx.psize + 3) &~3), 641106813Ssimokawa M_DEVBUF, M_DONTWAIT); 642106813Ssimokawa if(it->buf == NULL){ 643106813Ssimokawa free(ir->bulkxfer, M_DEVBUF); 644106813Ssimokawa free(it->bulkxfer, M_DEVBUF); 645106813Ssimokawa free(ir->buf, M_DEVBUF); 646106813Ssimokawa ir->bulkxfer = NULL; 647106813Ssimokawa it->bulkxfer = NULL; 648106813Ssimokawa it->buf = NULL; 649106813Ssimokawa return(ENOMEM); 650106813Ssimokawa } 651106813Ssimokawa 652106813Ssimokawa ir->bnchunk = ibufreq->rx.nchunk; 653106813Ssimokawa ir->bnpacket = ibufreq->rx.npacket; 654106813Ssimokawa ir->btpacket = ibufreq->rx.npacket; 655106813Ssimokawa ir->psize = (ibufreq->rx.psize + 3) & ~3; 656106813Ssimokawa ir->queued = 0; 657106813Ssimokawa 658106813Ssimokawa it->bnchunk = ibufreq->tx.nchunk; 659106813Ssimokawa it->bnpacket = ibufreq->tx.npacket; 660106813Ssimokawa it->btpacket = ibufreq->tx.npacket; 661106813Ssimokawa it->psize = (ibufreq->tx.psize + 3) & ~3; 662106813Ssimokawa ir->queued = 0; 663106813Ssimokawa it->dvdbc = 0; 664106813Ssimokawa it->dvdiff = 0; 665106813Ssimokawa it->dvsync = 0; 666106813Ssimokawa 667106813Ssimokawa STAILQ_INIT(&ir->stvalid); 668106813Ssimokawa STAILQ_INIT(&ir->stfree); 669106813Ssimokawa ir->stdma = NULL; 670106813Ssimokawa ir->stdma2 = NULL; 671106813Ssimokawa ir->stproc = NULL; 672106813Ssimokawa 673106813Ssimokawa STAILQ_INIT(&it->stvalid); 674106813Ssimokawa STAILQ_INIT(&it->stfree); 675106813Ssimokawa it->stdma = NULL; 676106813Ssimokawa it->stdma2 = NULL; 677106813Ssimokawa it->stproc = NULL; 678106813Ssimokawa 679106813Ssimokawa for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){ 680106813Ssimokawa ir->bulkxfer[i].buf = 681106813Ssimokawa ir->buf + 682106813Ssimokawa i * sc->fc->ir[sub]->bnpacket * 683106813Ssimokawa sc->fc->ir[sub]->psize; 684106813Ssimokawa ir->bulkxfer[i].flag = 0; 685106813Ssimokawa STAILQ_INSERT_TAIL(&ir->stfree, 686106813Ssimokawa &ir->bulkxfer[i], link); 687106813Ssimokawa ir->bulkxfer[i].npacket = ir->bnpacket; 688106813Ssimokawa } 689106813Ssimokawa for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){ 690106813Ssimokawa it->bulkxfer[i].buf = 691106813Ssimokawa it->buf + 692106813Ssimokawa i * sc->fc->it[sub]->bnpacket * 693106813Ssimokawa sc->fc->it[sub]->psize; 694106813Ssimokawa it->bulkxfer[i].flag = 0; 695106813Ssimokawa STAILQ_INSERT_TAIL(&it->stfree, 696106813Ssimokawa &it->bulkxfer[i], link); 697106813Ssimokawa it->bulkxfer[i].npacket = it->bnpacket; 698106813Ssimokawa } 699106813Ssimokawa ir->flag &= ~FWXFERQ_MODEMASK; 700106813Ssimokawa ir->flag |= FWXFERQ_STREAM; 701106813Ssimokawa ir->flag |= FWXFERQ_EXTBUF; 702106813Ssimokawa 703106813Ssimokawa it->flag &= ~FWXFERQ_MODEMASK; 704106813Ssimokawa it->flag |= FWXFERQ_STREAM; 705106813Ssimokawa it->flag |= FWXFERQ_EXTBUF; 706106813Ssimokawa err = 0; 707106813Ssimokawa break; 708106813Ssimokawa case FW_GSTBUF: 709106813Ssimokawa ibufreq->rx.nchunk = sc->fc->ir[sub]->bnchunk; 710106813Ssimokawa ibufreq->rx.npacket = sc->fc->ir[sub]->bnpacket; 711106813Ssimokawa ibufreq->rx.psize = sc->fc->ir[sub]->psize; 712106813Ssimokawa 713106813Ssimokawa ibufreq->tx.nchunk = sc->fc->it[sub]->bnchunk; 714106813Ssimokawa ibufreq->tx.npacket = sc->fc->it[sub]->bnpacket; 715106813Ssimokawa ibufreq->tx.psize = sc->fc->it[sub]->psize; 716106813Ssimokawa break; 717106813Ssimokawa case FW_ASYREQ: 718106813Ssimokawa xfer = fw_xfer_alloc(); 719106813Ssimokawa if(xfer == NULL){ 720106813Ssimokawa err = ENOMEM; 721106813Ssimokawa return err; 722106813Ssimokawa } 723106813Ssimokawa fp = &asyreq->pkt; 724106813Ssimokawa switch (asyreq->req.type) { 725106813Ssimokawa case FWASREQNODE: 726106813Ssimokawa xfer->dst = ntohs(fp->mode.hdr.dst); 727106813Ssimokawa break; 728106813Ssimokawa case FWASREQEUI: 729106813Ssimokawa fwdev = fw_noderesolve(sc->fc, asyreq->req.dst.eui); 730106813Ssimokawa if (fwdev == NULL) { 731108782Ssimokawa device_printf(sc->fc->bdev, 732108782Ssimokawa "cannot find node\n"); 733106813Ssimokawa err = EINVAL; 734106813Ssimokawa goto error; 735106813Ssimokawa } 736106813Ssimokawa xfer->dst = fwdev->dst; 737106813Ssimokawa fp->mode.hdr.dst = htons(FWLOCALBUS | xfer->dst); 738106813Ssimokawa break; 739106813Ssimokawa case FWASRESTL: 740106813Ssimokawa /* XXX what's this? */ 741106813Ssimokawa break; 742106813Ssimokawa case FWASREQSTREAM: 743106813Ssimokawa /* nothing to do */ 744106813Ssimokawa break; 745106813Ssimokawa } 746106813Ssimokawa xfer->spd = asyreq->req.sped; 747106813Ssimokawa xfer->send.len = asyreq->req.len; 748106813Ssimokawa xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT); 749106813Ssimokawa if(xfer->send.buf == NULL){ 750106813Ssimokawa return ENOMEM; 751106813Ssimokawa } 752106813Ssimokawa xfer->send.off = 0; 753106813Ssimokawa bcopy(fp, xfer->send.buf, xfer->send.len); 754106813Ssimokawa xfer->act.hand = fw_asy_callback; 755106813Ssimokawa err = fw_asyreq(sc->fc, sub, xfer); 756106813Ssimokawa if(err){ 757106813Ssimokawa fw_xfer_free( xfer); 758106813Ssimokawa return err; 759106813Ssimokawa } 760106813Ssimokawa err = tsleep((caddr_t)xfer, FWPRI, "asyreq", hz); 761106813Ssimokawa if(err == 0){ 762106813Ssimokawa if(asyreq->req.len >= xfer->recv.len){ 763106813Ssimokawa asyreq->req.len = xfer->recv.len; 764106813Ssimokawa }else{ 765106813Ssimokawa err = EINVAL; 766106813Ssimokawa } 767106813Ssimokawa bcopy(xfer->recv.buf + xfer->recv.off, fp, asyreq->req.len); 768106813Ssimokawa } 769106813Ssimokawaerror: 770106813Ssimokawa fw_xfer_free( xfer); 771106813Ssimokawa break; 772106813Ssimokawa case FW_IBUSRST: 773106813Ssimokawa sc->fc->ibr(sc->fc); 774106813Ssimokawa break; 775106813Ssimokawa case FW_CBINDADDR: 776106813Ssimokawa fwb = fw_bindlookup(sc->fc, 777106813Ssimokawa bindreq->start.hi, bindreq->start.lo); 778106813Ssimokawa if(fwb == NULL){ 779106813Ssimokawa err = EINVAL; 780106813Ssimokawa break; 781106813Ssimokawa } 782106813Ssimokawa STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 783106813Ssimokawa STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist); 784106813Ssimokawa free(fwb, M_DEVBUF); 785106813Ssimokawa break; 786106813Ssimokawa case FW_SBINDADDR: 787106813Ssimokawa if(bindreq->len <= 0 ){ 788106813Ssimokawa err = EINVAL; 789106813Ssimokawa break; 790106813Ssimokawa } 791106813Ssimokawa if(bindreq->start.hi > 0xffff ){ 792106813Ssimokawa err = EINVAL; 793106813Ssimokawa break; 794106813Ssimokawa } 795106813Ssimokawa fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_DEVBUF, M_DONTWAIT); 796106813Ssimokawa if(fwb == NULL){ 797106813Ssimokawa err = ENOMEM; 798106813Ssimokawa break; 799106813Ssimokawa } 800106813Ssimokawa fwb->start_hi = bindreq->start.hi; 801106813Ssimokawa fwb->start_lo = bindreq->start.lo; 802106813Ssimokawa fwb->addrlen = bindreq->len; 803106813Ssimokawa 804106813Ssimokawa xfer = fw_xfer_alloc(); 805106813Ssimokawa if(xfer == NULL){ 806106813Ssimokawa err = ENOMEM; 807106813Ssimokawa return err; 808106813Ssimokawa } 809106813Ssimokawa xfer->act_type = FWACT_CH; 810106813Ssimokawa xfer->sub = sub; 811106813Ssimokawa xfer->fc = sc->fc; 812106813Ssimokawa 813106813Ssimokawa fwb->xfer = xfer; 814106813Ssimokawa err = fw_bindadd(sc->fc, fwb); 815106813Ssimokawa break; 816106813Ssimokawa case FW_GDEVLST: 817106813Ssimokawa i = 0; 818106813Ssimokawa for(fwdev = TAILQ_FIRST(&sc->fc->devices); fwdev != NULL; 819106813Ssimokawa fwdev = TAILQ_NEXT(fwdev, link)){ 820106813Ssimokawa if(i < fwdevlst->n){ 821106813Ssimokawa fwdevlst->dst[i] = fwdev->dst; 822106813Ssimokawa fwdevlst->status[i] = 823106813Ssimokawa (fwdev->status == FWDEVATTACHED)?1:0; 824106813Ssimokawa fwdevlst->eui[i].hi = fwdev->eui.hi; 825106813Ssimokawa fwdevlst->eui[i].lo = fwdev->eui.lo; 826106813Ssimokawa } 827106813Ssimokawa i++; 828106813Ssimokawa } 829106813Ssimokawa fwdevlst->n = i; 830106813Ssimokawa break; 831106813Ssimokawa case FW_GTPMAP: 832106813Ssimokawa bcopy(sc->fc->topology_map, data, 833106813Ssimokawa (sc->fc->topology_map->crc_len + 1) * 4); 834106813Ssimokawa break; 835106813Ssimokawa case FW_GCROM: 836106813Ssimokawa for (fwdev = TAILQ_FIRST(&sc->fc->devices); fwdev != NULL; 837106813Ssimokawa fwdev = TAILQ_NEXT(fwdev, link)) { 838106813Ssimokawa if (fwdev->eui.hi == crom_buf->eui.hi && 839106813Ssimokawa fwdev->eui.lo == crom_buf->eui.lo) 840106813Ssimokawa break; 841106813Ssimokawa } 842106813Ssimokawa if (fwdev == NULL) { 843106813Ssimokawa err = FWNODE_INVAL; 844106813Ssimokawa break; 845106813Ssimokawa } 846106813Ssimokawa#if 0 847106813Ssimokawa if (fwdev->csrrom[0] >> 24 == 1) 848106813Ssimokawa len = 4; 849106813Ssimokawa else 850106813Ssimokawa len = (1 + ((fwdev->csrrom[0] >> 16) & 0xff)) * 4; 851106813Ssimokawa#else 852106813Ssimokawa if (fwdev->rommax < CSRROMOFF) 853106813Ssimokawa len = 0; 854106813Ssimokawa else 855106813Ssimokawa len = fwdev->rommax - CSRROMOFF + 4; 856106813Ssimokawa#endif 857106813Ssimokawa if (crom_buf->len < len) 858106813Ssimokawa len = crom_buf->len; 859106813Ssimokawa else 860106813Ssimokawa crom_buf->len = len; 861106813Ssimokawa err = copyout(&fwdev->csrrom[0], crom_buf->ptr, len); 862106813Ssimokawa break; 863106813Ssimokawa default: 864106813Ssimokawa sc->fc->ioctl (dev, cmd, data, flag, td); 865106813Ssimokawa break; 866106813Ssimokawa } 867106813Ssimokawa return err; 868106813Ssimokawa} 869106813Ssimokawaint 870106813Ssimokawafw_poll(dev_t dev, int events, fw_proc *td) 871106813Ssimokawa{ 872106813Ssimokawa int revents; 873106813Ssimokawa int tmp; 874106813Ssimokawa int unit = DEV2UNIT(dev); 875106813Ssimokawa int sub = DEV2DMACH(dev); 876106813Ssimokawa struct firewire_softc *sc; 877106813Ssimokawa 878106813Ssimokawa if (DEV_FWMEM(dev)) 879106813Ssimokawa return fwmem_poll(dev, events, td); 880106813Ssimokawa 881106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 882106813Ssimokawa revents = 0; 883106813Ssimokawa tmp = POLLIN | POLLRDNORM; 884106813Ssimokawa if (events & tmp) { 885106813Ssimokawa if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL) 886106813Ssimokawa revents |= tmp; 887106813Ssimokawa else 888106813Ssimokawa selrecord(td, &sc->fc->ir[sub]->rsel); 889106813Ssimokawa } 890106813Ssimokawa tmp = POLLOUT | POLLWRNORM; 891106813Ssimokawa if (events & tmp) { 892106813Ssimokawa /* XXX should be fixed */ 893106813Ssimokawa revents |= tmp; 894106813Ssimokawa } 895106813Ssimokawa 896106813Ssimokawa return revents; 897106813Ssimokawa} 898106813Ssimokawa 899106813Ssimokawastatic int 900106813Ssimokawafw_mmap (dev_t dev, vm_offset_t offset, int nproto) 901106813Ssimokawa{ 902106813Ssimokawa struct firewire_softc *fc; 903106813Ssimokawa int unit = DEV2UNIT(dev); 904106813Ssimokawa 905106813Ssimokawa if (DEV_FWMEM(dev)) 906106813Ssimokawa return fwmem_mmap(dev, offset, nproto); 907106813Ssimokawa 908106813Ssimokawa fc = devclass_get_softc(firewire_devclass, unit); 909106813Ssimokawa 910106813Ssimokawa return EINVAL; 911106813Ssimokawa} 912