fwdev.c revision 109814
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 109814 2003-01-25 14:47:33Z 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> 55109282Ssimokawa#include <dev/firewire/iec68113.h> 56106813Ssimokawa 57106813Ssimokawa#define CDEV_MAJOR 127 58106813Ssimokawa#define FWNODE_INVAL 0xffff 59106813Ssimokawa 60106813Ssimokawastatic d_open_t fw_open; 61106813Ssimokawastatic d_close_t fw_close; 62106813Ssimokawastatic d_ioctl_t fw_ioctl; 63106813Ssimokawastatic d_poll_t fw_poll; 64106813Ssimokawastatic d_read_t fw_read; /* for Isochronous packet */ 65106813Ssimokawastatic d_write_t fw_write; 66106813Ssimokawastatic d_mmap_t fw_mmap; 67106813Ssimokawa 68106813Ssimokawastruct cdevsw firewire_cdevsw = 69106813Ssimokawa{ 70106813Ssimokawa fw_open, fw_close, fw_read, fw_write, fw_ioctl, 71106813Ssimokawa fw_poll, fw_mmap, nostrategy, "fw", CDEV_MAJOR, nodump, nopsize, D_MEM 72106813Ssimokawa}; 73106813Ssimokawa 74106813Ssimokawastatic int 75106813Ssimokawafw_open (dev_t dev, int flags, int fmt, fw_proc *td) 76106813Ssimokawa{ 77106813Ssimokawa struct firewire_softc *sc; 78106813Ssimokawa int unit = DEV2UNIT(dev); 79106813Ssimokawa int sub = DEV2DMACH(dev); 80106813Ssimokawa 81106813Ssimokawa int err = 0; 82106813Ssimokawa 83106813Ssimokawa if (DEV_FWMEM(dev)) 84106813Ssimokawa return fwmem_open(dev, flags, fmt, td); 85106813Ssimokawa 86106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 87106813Ssimokawa if(sc->fc->ir[sub]->flag & FWXFERQ_OPEN){ 88106813Ssimokawa err = EBUSY; 89106813Ssimokawa return err; 90106813Ssimokawa } 91106813Ssimokawa if(sc->fc->it[sub]->flag & FWXFERQ_OPEN){ 92106813Ssimokawa err = EBUSY; 93106813Ssimokawa return err; 94106813Ssimokawa } 95106813Ssimokawa if(sc->fc->ir[sub]->flag & FWXFERQ_MODEMASK){ 96106813Ssimokawa err = EBUSY; 97106813Ssimokawa return err; 98106813Ssimokawa } 99106813Ssimokawa/* Default is per packet mode */ 100106813Ssimokawa sc->fc->ir[sub]->flag |= FWXFERQ_OPEN; 101106813Ssimokawa sc->fc->it[sub]->flag |= FWXFERQ_OPEN; 102106813Ssimokawa sc->fc->ir[sub]->flag |= FWXFERQ_PACKET; 103106813Ssimokawa return err; 104106813Ssimokawa} 105106813Ssimokawa 106106813Ssimokawastatic int 107106813Ssimokawafw_close (dev_t dev, int flags, int fmt, fw_proc *td) 108106813Ssimokawa{ 109106813Ssimokawa struct firewire_softc *sc; 110106813Ssimokawa int unit = DEV2UNIT(dev); 111106813Ssimokawa int sub = DEV2DMACH(dev); 112106813Ssimokawa struct fw_xfer *xfer; 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 } 138109802Ssimokawa#ifdef FWXFERQ_DV 139106813Ssimokawa if(sc->fc->it[sub]->flag & FWXFERQ_DV){ 140109802Ssimokawa struct fw_dvbuf *dvbuf; 141109802Ssimokawa 142106813Ssimokawa if((dvbuf = sc->fc->it[sub]->dvproc) != NULL){ 143106813Ssimokawa free(dvbuf->buf, M_DEVBUF); 144106813Ssimokawa sc->fc->it[sub]->dvproc = NULL; 145106813Ssimokawa } 146106813Ssimokawa if((dvbuf = sc->fc->it[sub]->dvdma) != NULL){ 147106813Ssimokawa free(dvbuf->buf, M_DEVBUF); 148106813Ssimokawa sc->fc->it[sub]->dvdma = NULL; 149106813Ssimokawa } 150106813Ssimokawa while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvvalid)) != NULL){ 151106813Ssimokawa STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvvalid, link); 152106813Ssimokawa free(dvbuf->buf, M_DEVBUF); 153106813Ssimokawa } 154106813Ssimokawa while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvfree)) != NULL){ 155106813Ssimokawa STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvfree, link); 156106813Ssimokawa free(dvbuf->buf, M_DEVBUF); 157106813Ssimokawa } 158106813Ssimokawa free(sc->fc->it[sub]->dvbuf, M_DEVBUF); 159106813Ssimokawa sc->fc->it[sub]->dvbuf = NULL; 160106813Ssimokawa } 161109802Ssimokawa#endif 162106813Ssimokawa if(sc->fc->ir[sub]->flag & FWXFERQ_EXTBUF){ 163106813Ssimokawa free(sc->fc->ir[sub]->buf, M_DEVBUF); 164106813Ssimokawa sc->fc->ir[sub]->buf = NULL; 165106813Ssimokawa free(sc->fc->ir[sub]->bulkxfer, M_DEVBUF); 166106813Ssimokawa sc->fc->ir[sub]->bulkxfer = NULL; 167106813Ssimokawa sc->fc->ir[sub]->flag &= ~FWXFERQ_EXTBUF; 168109379Ssimokawa sc->fc->ir[sub]->psize = PAGE_SIZE; 169106813Ssimokawa sc->fc->ir[sub]->maxq = FWMAXQUEUE; 170106813Ssimokawa } 171106813Ssimokawa if(sc->fc->it[sub]->flag & FWXFERQ_EXTBUF){ 172106813Ssimokawa free(sc->fc->it[sub]->buf, M_DEVBUF); 173106813Ssimokawa sc->fc->it[sub]->buf = NULL; 174106813Ssimokawa free(sc->fc->it[sub]->bulkxfer, M_DEVBUF); 175106813Ssimokawa sc->fc->it[sub]->bulkxfer = NULL; 176106813Ssimokawa sc->fc->it[sub]->dvbuf = NULL; 177106813Ssimokawa sc->fc->it[sub]->flag &= ~FWXFERQ_EXTBUF; 178109379Ssimokawa sc->fc->it[sub]->psize = 0; 179106813Ssimokawa sc->fc->it[sub]->maxq = FWMAXQUEUE; 180106813Ssimokawa } 181106813Ssimokawa for(xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q); 182106813Ssimokawa xfer != NULL; xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q)){ 183106813Ssimokawa sc->fc->ir[sub]->queued--; 184106813Ssimokawa STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->q, link); 185106813Ssimokawa 186106813Ssimokawa xfer->resp = 0; 187106813Ssimokawa switch(xfer->act_type){ 188106813Ssimokawa case FWACT_XFER: 189106813Ssimokawa fw_xfer_done(xfer); 190106813Ssimokawa break; 191106813Ssimokawa default: 192106813Ssimokawa break; 193106813Ssimokawa } 194106813Ssimokawa fw_xfer_free(xfer); 195106813Ssimokawa } 196106813Ssimokawa for(fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds); fwb != NULL; 197106813Ssimokawa fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds)){ 198106813Ssimokawa STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 199106813Ssimokawa STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->binds, chlist); 200106813Ssimokawa free(fwb, M_DEVBUF); 201106813Ssimokawa } 202106813Ssimokawa sc->fc->ir[sub]->flag &= ~FWXFERQ_MODEMASK; 203106813Ssimokawa sc->fc->it[sub]->flag &= ~FWXFERQ_MODEMASK; 204106813Ssimokawa return err; 205106813Ssimokawa} 206106813Ssimokawa 207106813Ssimokawa/* 208106813Ssimokawa * read request. 209106813Ssimokawa */ 210106813Ssimokawastatic int 211106813Ssimokawafw_read (dev_t dev, struct uio *uio, int ioflag) 212106813Ssimokawa{ 213106813Ssimokawa struct firewire_softc *sc; 214106813Ssimokawa struct fw_xferq *ir; 215106813Ssimokawa struct fw_xfer *xfer; 216106813Ssimokawa int err = 0, s, slept = 0; 217106813Ssimokawa int unit = DEV2UNIT(dev); 218106813Ssimokawa int sub = DEV2DMACH(dev); 219106813Ssimokawa struct fw_pkt *fp; 220106813Ssimokawa 221106813Ssimokawa if (DEV_FWMEM(dev)) 222106813Ssimokawa return fwmem_read(dev, uio, ioflag); 223106813Ssimokawa 224106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 225106813Ssimokawa 226106813Ssimokawa ir = sc->fc->ir[sub]; 227106813Ssimokawa 228106813Ssimokawa if(ir->flag & FWXFERQ_PACKET){ 229106813Ssimokawa ir->stproc = NULL; 230106813Ssimokawa } 231106813Ssimokawareadloop: 232106813Ssimokawa xfer = STAILQ_FIRST(&ir->q); 233106813Ssimokawa if(!(ir->flag & FWXFERQ_PACKET) && ir->stproc == NULL){ 234106813Ssimokawa ir->stproc = STAILQ_FIRST(&ir->stvalid); 235106813Ssimokawa if(ir->stproc != NULL){ 236106813Ssimokawa s = splfw(); 237106813Ssimokawa STAILQ_REMOVE_HEAD(&ir->stvalid, link); 238106813Ssimokawa splx(s); 239106813Ssimokawa ir->queued = 0; 240106813Ssimokawa } 241106813Ssimokawa } 242106813Ssimokawa 243106813Ssimokawa if(xfer == NULL && ir->stproc == NULL){ 244106813Ssimokawa if(slept == 0){ 245106813Ssimokawa slept = 1; 246106813Ssimokawa if(!(ir->flag & FWXFERQ_RUNNING) 247106813Ssimokawa && (ir->flag & FWXFERQ_PACKET)){ 248106813Ssimokawa err = sc->fc->irx_enable(sc->fc, sub); 249106813Ssimokawa } 250106813Ssimokawa if(err){ 251106813Ssimokawa return err; 252106813Ssimokawa } 253106813Ssimokawa ir->flag |= FWXFERQ_WAKEUP; 254106813Ssimokawa err = tsleep((caddr_t)ir, FWPRI, "fw_read", hz); 255106813Ssimokawa if(err){ 256106813Ssimokawa ir->flag &= ~FWXFERQ_WAKEUP; 257106813Ssimokawa return err; 258106813Ssimokawa } 259106813Ssimokawa goto readloop; 260106813Ssimokawa }else{ 261106813Ssimokawa err = EIO; 262106813Ssimokawa return err; 263106813Ssimokawa } 264106813Ssimokawa }else if(xfer != NULL){ 265106813Ssimokawa s = splfw(); 266106813Ssimokawa ir->queued --; 267106813Ssimokawa STAILQ_REMOVE_HEAD(&ir->q, link); 268106813Ssimokawa splx(s); 269106813Ssimokawa fp = (struct fw_pkt *)(xfer->recv.buf + xfer->recv.off); 270106813Ssimokawa if(sc->fc->irx_post != NULL) 271106813Ssimokawa sc->fc->irx_post(sc->fc, fp->mode.ld); 272106813Ssimokawa err = uiomove(xfer->recv.buf + xfer->recv.off, xfer->recv.len, uio); 273106813Ssimokawa fw_xfer_free( xfer); 274106813Ssimokawa }else if(ir->stproc != NULL){ 275106813Ssimokawa fp = (struct fw_pkt *)(ir->stproc->buf + ir->queued * ir->psize); 276106813Ssimokawa if(sc->fc->irx_post != NULL) 277106813Ssimokawa sc->fc->irx_post(sc->fc, fp->mode.ld); 278106813Ssimokawa if(ntohs(fp->mode.stream.len) == 0){ 279106813Ssimokawa err = EIO; 280106813Ssimokawa return err; 281106813Ssimokawa } 282106813Ssimokawa err = uiomove((caddr_t)fp, ntohs(fp->mode.stream.len) + sizeof(u_int32_t), uio); 283106813Ssimokawa fp->mode.stream.len = 0; 284106813Ssimokawa ir->queued ++; 285106813Ssimokawa if(ir->queued >= ir->bnpacket){ 286106813Ssimokawa s = splfw(); 287106813Ssimokawa ir->stproc->flag = 0; 288106813Ssimokawa STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 289106813Ssimokawa splx(s); 290106813Ssimokawa ir->stproc = NULL; 291106813Ssimokawa } 292106813Ssimokawa } 293106813Ssimokawa#if 0 294106813Ssimokawa if(STAILQ_FIRST(&ir->q) == NULL && 295106813Ssimokawa (ir->flag & FWXFERQ_RUNNING) && (ir->flag & FWXFERQ_PACKET)){ 296106813Ssimokawa err = sc->fc->irx_enable(sc->fc, sub); 297106813Ssimokawa } 298106813Ssimokawa#endif 299106813Ssimokawa#if 0 300106813Ssimokawa if(STAILQ_FIRST(&ir->stvalid) == NULL && 301106813Ssimokawa (ir->flag & FWXFERQ_RUNNING) && !(ir->flag & FWXFERQ_PACKET)){ 302106813Ssimokawa err = sc->fc->irx_enable(sc->fc, sub); 303106813Ssimokawa } 304106813Ssimokawa#endif 305106813Ssimokawa return err; 306106813Ssimokawa} 307106813Ssimokawa 308106813Ssimokawastatic int 309106813Ssimokawafw_write (dev_t dev, struct uio *uio, int ioflag) 310106813Ssimokawa{ 311106813Ssimokawa int err = 0; 312106813Ssimokawa struct firewire_softc *sc; 313106813Ssimokawa int unit = DEV2UNIT(dev); 314106813Ssimokawa int sub = DEV2DMACH(dev); 315106813Ssimokawa int s, slept = 0; 316106813Ssimokawa struct fw_pkt *fp; 317106813Ssimokawa struct fw_xfer *xfer; 318106813Ssimokawa struct fw_xferq *xferq; 319106813Ssimokawa struct firewire_comm *fc; 320106813Ssimokawa struct fw_xferq *it; 321106813Ssimokawa 322106813Ssimokawa if (DEV_FWMEM(dev)) 323106813Ssimokawa return fwmem_write(dev, uio, ioflag); 324106813Ssimokawa 325106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 326106813Ssimokawa fc = sc->fc; 327106813Ssimokawa it = sc->fc->it[sub]; 328106813Ssimokawa 329106813Ssimokawa fp = (struct fw_pkt *)uio->uio_iov->iov_base; 330106813Ssimokawa switch(fp->mode.common.tcode){ 331106813Ssimokawa case FWTCODE_RREQQ: 332106813Ssimokawa case FWTCODE_RREQB: 333106813Ssimokawa case FWTCODE_LREQ: 334106813Ssimokawa err = EINVAL; 335106813Ssimokawa return err; 336106813Ssimokawa case FWTCODE_WREQQ: 337106813Ssimokawa case FWTCODE_WREQB: 338106813Ssimokawa xferq = fc->atq; 339106813Ssimokawa break; 340106813Ssimokawa case FWTCODE_STREAM: 341106813Ssimokawa if(it->flag & FWXFERQ_PACKET){ 342106813Ssimokawa xferq = fc->atq; 343106813Ssimokawa }else{ 344106813Ssimokawa xferq = NULL; 345106813Ssimokawa } 346106813Ssimokawa break; 347106813Ssimokawa case FWTCODE_WRES: 348106813Ssimokawa case FWTCODE_RRESQ: 349106813Ssimokawa case FWTCODE_RRESB: 350106813Ssimokawa case FWTCODE_LRES: 351106813Ssimokawa xferq = fc->ats; 352106813Ssimokawa break; 353106813Ssimokawa default: 354106813Ssimokawa err = EINVAL; 355106813Ssimokawa return err; 356106813Ssimokawa } 357106813Ssimokawa /* Discard unsent buffered stream packet, when sending Asyrequrst */ 358106813Ssimokawa if(xferq != NULL && it->stproc != NULL){ 359106813Ssimokawa s = splfw(); 360106813Ssimokawa it->stproc->flag = 0; 361106813Ssimokawa STAILQ_INSERT_TAIL(&it->stfree, it->stproc, link); 362106813Ssimokawa splx(s); 363106813Ssimokawa it->stproc = NULL; 364106813Ssimokawa } 365109802Ssimokawa#ifdef FWXFERQ_DV 366106813Ssimokawa if(xferq == NULL && !(it->flag & FWXFERQ_DV)){ 367109802Ssimokawa#else 368109802Ssimokawa if (xferq == NULL) { 369109802Ssimokawa#endif 370106813Ssimokawaisoloop: 371106813Ssimokawa if(it->stproc == NULL){ 372106813Ssimokawa it->stproc = STAILQ_FIRST(&it->stfree); 373106813Ssimokawa if(it->stproc != NULL){ 374106813Ssimokawa s = splfw(); 375106813Ssimokawa STAILQ_REMOVE_HEAD(&it->stfree, link); 376106813Ssimokawa splx(s); 377106813Ssimokawa it->queued = 0; 378106813Ssimokawa }else if(slept == 0){ 379106813Ssimokawa slept = 1; 380106813Ssimokawa err = sc->fc->itx_enable(sc->fc, sub); 381106813Ssimokawa if(err){ 382106813Ssimokawa return err; 383106813Ssimokawa } 384106813Ssimokawa err = tsleep((caddr_t)it, FWPRI, "fw_write", hz); 385106813Ssimokawa if(err){ 386106813Ssimokawa return err; 387106813Ssimokawa } 388106813Ssimokawa goto isoloop; 389106813Ssimokawa }else{ 390106813Ssimokawa err = EIO; 391106813Ssimokawa return err; 392106813Ssimokawa } 393106813Ssimokawa } 394109179Ssimokawa#if 0 /* What's this for? (overwritten by the following uiomove)*/ 395106813Ssimokawa fp = (struct fw_pkt *)(it->stproc->buf + it->queued * it->psize); 396106813Ssimokawa fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t)); 397109179Ssimokawa#endif 398106813Ssimokawa err = uiomove(it->stproc->buf + it->queued * it->psize, 399106813Ssimokawa uio->uio_resid, uio); 400106813Ssimokawa it->queued ++; 401106813Ssimokawa if(it->queued >= it->btpacket){ 402106813Ssimokawa s = splfw(); 403106813Ssimokawa STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 404106813Ssimokawa splx(s); 405106813Ssimokawa it->stproc = NULL; 406106813Ssimokawa fw_tbuf_update(sc->fc, sub, 0); 407106813Ssimokawa err = sc->fc->itx_enable(sc->fc, sub); 408106813Ssimokawa } 409106813Ssimokawa return err; 410109802Ssimokawa } 411109802Ssimokawa#ifdef FWXFERQ_DV 412109802Ssimokawa if(xferq == NULL && it->flag & FWXFERQ_DV){ 413106813Ssimokawadvloop: 414106813Ssimokawa if(it->dvproc == NULL){ 415106813Ssimokawa it->dvproc = STAILQ_FIRST(&it->dvfree); 416106813Ssimokawa if(it->dvproc != NULL){ 417106813Ssimokawa s = splfw(); 418106813Ssimokawa STAILQ_REMOVE_HEAD(&it->dvfree, link); 419106813Ssimokawa splx(s); 420106813Ssimokawa it->dvptr = 0; 421106813Ssimokawa }else if(slept == 0){ 422106813Ssimokawa slept = 1; 423106813Ssimokawa err = sc->fc->itx_enable(sc->fc, sub); 424106813Ssimokawa if(err){ 425106813Ssimokawa return err; 426106813Ssimokawa } 427106813Ssimokawa err = tsleep((caddr_t)it, FWPRI, "fw_write", hz); 428106813Ssimokawa if(err){ 429106813Ssimokawa return err; 430106813Ssimokawa } 431106813Ssimokawa goto dvloop; 432106813Ssimokawa }else{ 433106813Ssimokawa err = EIO; 434106813Ssimokawa return err; 435106813Ssimokawa } 436106813Ssimokawa } 437109179Ssimokawa#if 0 /* What's this for? (it->dvptr? overwritten by the following uiomove)*/ 438106813Ssimokawa fp = (struct fw_pkt *)(it->dvproc->buf + it->queued * it->psize); 439106813Ssimokawa fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t)); 440109179Ssimokawa#endif 441106813Ssimokawa err = uiomove(it->dvproc->buf + it->dvptr, 442106813Ssimokawa uio->uio_resid, uio); 443106813Ssimokawa it->dvptr += it->psize; 444106813Ssimokawa if(err){ 445106813Ssimokawa return err; 446106813Ssimokawa } 447106813Ssimokawa if(it->dvptr >= it->psize * it->dvpacket){ 448106813Ssimokawa s = splfw(); 449106813Ssimokawa STAILQ_INSERT_TAIL(&it->dvvalid, it->dvproc, link); 450106813Ssimokawa splx(s); 451106813Ssimokawa it->dvproc = NULL; 452106813Ssimokawa err = fw_tbuf_update(sc->fc, sub, 0); 453106813Ssimokawa if(err){ 454106813Ssimokawa return err; 455106813Ssimokawa } 456106813Ssimokawa err = sc->fc->itx_enable(sc->fc, sub); 457106813Ssimokawa } 458106813Ssimokawa return err; 459106813Ssimokawa } 460109802Ssimokawa#endif 461106813Ssimokawa if(xferq != NULL){ 462106813Ssimokawa xfer = fw_xfer_alloc(); 463106813Ssimokawa if(xfer == NULL){ 464106813Ssimokawa err = ENOMEM; 465106813Ssimokawa return err; 466106813Ssimokawa } 467106813Ssimokawa xfer->send.buf = malloc(uio->uio_resid, M_DEVBUF, M_NOWAIT); 468106813Ssimokawa if(xfer->send.buf == NULL){ 469106813Ssimokawa fw_xfer_free( xfer); 470106813Ssimokawa err = ENOBUFS; 471106813Ssimokawa return err; 472106813Ssimokawa } 473106813Ssimokawa xfer->dst = ntohs(fp->mode.hdr.dst); 474106813Ssimokawa#if 0 475106813Ssimokawa switch(fp->mode.common.tcode){ 476106813Ssimokawa case FWTCODE_WREQQ: 477106813Ssimokawa case FWTCODE_WREQB: 478106813Ssimokawa if((tl = fw_get_tlabel(fc, xfer)) == -1 ){ 479106813Ssimokawa fw_xfer_free( xfer); 480106813Ssimokawa err = EAGAIN; 481106813Ssimokawa return err; 482106813Ssimokawa } 483106813Ssimokawa fp->mode.hdr.tlrt = tl << 2; 484106813Ssimokawa default: 485106813Ssimokawa break; 486106813Ssimokawa } 487106813Ssimokawa 488106813Ssimokawa xfer->tl = fp->mode.hdr.tlrt >> 2; 489106813Ssimokawa xfer->tcode = fp->mode.common.tcode; 490106813Ssimokawa xfer->fc = fc; 491106813Ssimokawa xfer->q = xferq; 492106813Ssimokawa xfer->act_type = FWACT_XFER; 493106813Ssimokawa xfer->retry_req = fw_asybusy; 494106813Ssimokawa#endif 495106813Ssimokawa xfer->send.len = uio->uio_resid; 496106813Ssimokawa xfer->send.off = 0; 497106813Ssimokawa xfer->spd = 0;/* XXX: how to setup it */ 498106813Ssimokawa xfer->act.hand = fw_asy_callback; 499106813Ssimokawa 500106813Ssimokawa err = uiomove(xfer->send.buf, uio->uio_resid, uio); 501106813Ssimokawa if(err){ 502106813Ssimokawa fw_xfer_free( xfer); 503106813Ssimokawa return err; 504106813Ssimokawa } 505106813Ssimokawa#if 0 506106813Ssimokawa fw_asystart(xfer); 507106813Ssimokawa#else 508106813Ssimokawa fw_asyreq(fc, -1, xfer); 509106813Ssimokawa#endif 510106813Ssimokawa err = tsleep((caddr_t)xfer, FWPRI, "fw_write", hz); 511106813Ssimokawa if(xfer->resp == EBUSY) 512106813Ssimokawa return EBUSY; 513106813Ssimokawa fw_xfer_free( xfer); 514106813Ssimokawa return err; 515106813Ssimokawa } 516106813Ssimokawa return EINVAL; 517106813Ssimokawa} 518106813Ssimokawa 519106813Ssimokawa/* 520106813Ssimokawa * ioctl support. 521106813Ssimokawa */ 522106813Ssimokawaint 523106813Ssimokawafw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 524106813Ssimokawa{ 525106813Ssimokawa struct firewire_softc *sc; 526106813Ssimokawa int unit = DEV2UNIT(dev); 527106813Ssimokawa int sub = DEV2DMACH(dev); 528106813Ssimokawa int i, len, err = 0; 529106813Ssimokawa struct fw_device *fwdev; 530106813Ssimokawa struct fw_bind *fwb; 531106813Ssimokawa struct fw_xferq *ir, *it; 532106813Ssimokawa struct fw_xfer *xfer; 533106813Ssimokawa struct fw_pkt *fp; 534109814Ssimokawa struct fw_devinfo *devinfo; 535106813Ssimokawa 536106813Ssimokawa struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 537106813Ssimokawa struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 538106813Ssimokawa struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 539106813Ssimokawa struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 540106813Ssimokawa struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 541106813Ssimokawa struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 542106813Ssimokawa 543106813Ssimokawa if (DEV_FWMEM(dev)) 544106813Ssimokawa return fwmem_ioctl(dev, cmd, data, flag, td); 545106813Ssimokawa 546106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 547106813Ssimokawa if (!data) 548106813Ssimokawa return(EINVAL); 549106813Ssimokawa 550106813Ssimokawa switch (cmd) { 551106813Ssimokawa case FW_STSTREAM: 552106813Ssimokawa sc->fc->it[sub]->flag &= ~0xff; 553106813Ssimokawa sc->fc->it[sub]->flag |= (0x3f & ichreq->ch); 554106813Ssimokawa sc->fc->it[sub]->flag |= ((0x3 & ichreq->tag) << 6); 555106813Ssimokawa err = 0; 556106813Ssimokawa break; 557106813Ssimokawa case FW_GTSTREAM: 558106813Ssimokawa ichreq->ch = sc->fc->it[sub]->flag & 0x3f; 559106813Ssimokawa ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3; 560106813Ssimokawa err = 0; 561106813Ssimokawa break; 562106813Ssimokawa case FW_SRSTREAM: 563106813Ssimokawa sc->fc->ir[sub]->flag &= ~0xff; 564106813Ssimokawa sc->fc->ir[sub]->flag |= (0x3f & ichreq->ch); 565106813Ssimokawa sc->fc->ir[sub]->flag |= ((0x3 & ichreq->tag) << 6); 566106813Ssimokawa err = sc->fc->irx_enable(sc->fc, sub); 567106813Ssimokawa break; 568106813Ssimokawa case FW_GRSTREAM: 569106813Ssimokawa ichreq->ch = sc->fc->ir[sub]->flag & 0x3f; 570106813Ssimokawa ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3; 571106813Ssimokawa err = 0; 572106813Ssimokawa break; 573109802Ssimokawa#ifdef FWXFERQ_DV 574106813Ssimokawa case FW_SSTDV: 575106813Ssimokawa ibufreq = (struct fw_isobufreq *) 576106813Ssimokawa malloc(sizeof(struct fw_isobufreq), M_DEVBUF, M_NOWAIT); 577106813Ssimokawa if(ibufreq == NULL){ 578106813Ssimokawa err = ENOMEM; 579106813Ssimokawa break; 580106813Ssimokawa } 581109282Ssimokawa#if DV_PAL 582109282Ssimokawa#define FWDVPACKET 300 583109282Ssimokawa#else 584109282Ssimokawa#define FWDVPACKET 250 585109282Ssimokawa#endif 586106813Ssimokawa#define FWDVPMAX 512 587106813Ssimokawa ibufreq->rx.nchunk = 8; 588106813Ssimokawa ibufreq->rx.npacket = 50; 589106813Ssimokawa ibufreq->rx.psize = FWDVPMAX; 590106813Ssimokawa 591106813Ssimokawa ibufreq->tx.nchunk = 5; 592109282Ssimokawa ibufreq->tx.npacket = FWDVPACKET + 30; /* > 320 or 267 */ 593106813Ssimokawa ibufreq->tx.psize = FWDVPMAX; 594106813Ssimokawa 595106813Ssimokawa err = fw_ioctl(dev, FW_SSTBUF, (caddr_t)ibufreq, flag, td); 596106813Ssimokawa sc->fc->it[sub]->dvpacket = FWDVPACKET; 597106813Ssimokawa free(ibufreq, M_DEVBUF); 598106813Ssimokawa/* reserve a buffer space */ 599106813Ssimokawa#define NDVCHUNK 8 600106813Ssimokawa sc->fc->it[sub]->dvproc = NULL; 601106813Ssimokawa sc->fc->it[sub]->dvdma = NULL; 602106813Ssimokawa sc->fc->it[sub]->flag |= FWXFERQ_DV; 603109179Ssimokawa /* XXX check malloc failure */ 604106813Ssimokawa sc->fc->it[sub]->dvbuf 605109424Ssimokawa = (struct fw_dvbuf *)malloc(sizeof(struct fw_dvbuf) * NDVCHUNK, M_DEVBUF, M_NOWAIT); 606106813Ssimokawa STAILQ_INIT(&sc->fc->it[sub]->dvvalid); 607106813Ssimokawa STAILQ_INIT(&sc->fc->it[sub]->dvfree); 608106813Ssimokawa for( i = 0 ; i < NDVCHUNK ; i++){ 609109179Ssimokawa /* XXX check malloc failure */ 610106813Ssimokawa sc->fc->it[sub]->dvbuf[i].buf 611109424Ssimokawa = malloc(FWDVPMAX * sc->fc->it[sub]->dvpacket, M_DEVBUF, M_NOWAIT); 612106813Ssimokawa STAILQ_INSERT_TAIL(&sc->fc->it[sub]->dvfree, 613106813Ssimokawa &sc->fc->it[sub]->dvbuf[i], link); 614106813Ssimokawa } 615106813Ssimokawa break; 616109802Ssimokawa#endif 617106813Ssimokawa case FW_SSTBUF: 618106813Ssimokawa ir = sc->fc->ir[sub]; 619106813Ssimokawa it = sc->fc->it[sub]; 620106813Ssimokawa 621106813Ssimokawa if(ir->flag & FWXFERQ_RUNNING || it->flag & FWXFERQ_RUNNING){ 622106813Ssimokawa return(EBUSY); 623106813Ssimokawa } 624106813Ssimokawa if((ir->flag & FWXFERQ_EXTBUF) || (it->flag & FWXFERQ_EXTBUF)){ 625106813Ssimokawa return(EBUSY); 626106813Ssimokawa } 627106813Ssimokawa if((ibufreq->rx.nchunk * 628106813Ssimokawa ibufreq->rx.psize * ibufreq->rx.npacket) + 629106813Ssimokawa (ibufreq->tx.nchunk * 630106813Ssimokawa ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){ 631106813Ssimokawa return(EINVAL); 632106813Ssimokawa } 633106813Ssimokawa if(ibufreq->rx.nchunk > FWSTMAXCHUNK || 634106813Ssimokawa ibufreq->tx.nchunk > FWSTMAXCHUNK){ 635106813Ssimokawa return(EINVAL); 636106813Ssimokawa } 637106813Ssimokawa ir->bulkxfer 638109424Ssimokawa = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_DEVBUF, M_NOWAIT); 639106813Ssimokawa if(ir->bulkxfer == NULL){ 640106813Ssimokawa return(ENOMEM); 641106813Ssimokawa } 642106813Ssimokawa it->bulkxfer 643109424Ssimokawa = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_DEVBUF, M_NOWAIT); 644106813Ssimokawa if(it->bulkxfer == NULL){ 645106813Ssimokawa return(ENOMEM); 646106813Ssimokawa } 647106813Ssimokawa ir->buf = malloc( 648106813Ssimokawa ibufreq->rx.nchunk * ibufreq->rx.npacket 649109403Ssimokawa /* XXX psize must be 2^n and less or 650109403Ssimokawa equal to PAGE_SIZE */ 651106813Ssimokawa * ((ibufreq->rx.psize + 3) &~3), 652109424Ssimokawa M_DEVBUF, M_NOWAIT); 653106813Ssimokawa if(ir->buf == NULL){ 654106813Ssimokawa free(ir->bulkxfer, M_DEVBUF); 655106813Ssimokawa free(it->bulkxfer, M_DEVBUF); 656106813Ssimokawa ir->bulkxfer = NULL; 657106813Ssimokawa it->bulkxfer = NULL; 658106813Ssimokawa it->buf = NULL; 659106813Ssimokawa return(ENOMEM); 660106813Ssimokawa } 661106813Ssimokawa it->buf = malloc( 662106813Ssimokawa ibufreq->tx.nchunk * ibufreq->tx.npacket 663109403Ssimokawa /* XXX psize must be 2^n and less or 664109403Ssimokawa equal to PAGE_SIZE */ 665106813Ssimokawa * ((ibufreq->tx.psize + 3) &~3), 666109424Ssimokawa M_DEVBUF, M_NOWAIT); 667106813Ssimokawa if(it->buf == NULL){ 668106813Ssimokawa free(ir->bulkxfer, M_DEVBUF); 669106813Ssimokawa free(it->bulkxfer, M_DEVBUF); 670106813Ssimokawa free(ir->buf, M_DEVBUF); 671106813Ssimokawa ir->bulkxfer = NULL; 672106813Ssimokawa it->bulkxfer = NULL; 673106813Ssimokawa it->buf = NULL; 674106813Ssimokawa return(ENOMEM); 675106813Ssimokawa } 676106813Ssimokawa 677106813Ssimokawa ir->bnchunk = ibufreq->rx.nchunk; 678106813Ssimokawa ir->bnpacket = ibufreq->rx.npacket; 679106813Ssimokawa ir->btpacket = ibufreq->rx.npacket; 680106813Ssimokawa ir->psize = (ibufreq->rx.psize + 3) & ~3; 681106813Ssimokawa ir->queued = 0; 682106813Ssimokawa 683106813Ssimokawa it->bnchunk = ibufreq->tx.nchunk; 684106813Ssimokawa it->bnpacket = ibufreq->tx.npacket; 685106813Ssimokawa it->btpacket = ibufreq->tx.npacket; 686106813Ssimokawa it->psize = (ibufreq->tx.psize + 3) & ~3; 687106813Ssimokawa ir->queued = 0; 688106813Ssimokawa it->dvdbc = 0; 689106813Ssimokawa it->dvdiff = 0; 690106813Ssimokawa it->dvsync = 0; 691109179Ssimokawa it->dvoffset = 0; 692106813Ssimokawa 693106813Ssimokawa STAILQ_INIT(&ir->stvalid); 694106813Ssimokawa STAILQ_INIT(&ir->stfree); 695106813Ssimokawa ir->stdma = NULL; 696106813Ssimokawa ir->stdma2 = NULL; 697106813Ssimokawa ir->stproc = NULL; 698106813Ssimokawa 699106813Ssimokawa STAILQ_INIT(&it->stvalid); 700106813Ssimokawa STAILQ_INIT(&it->stfree); 701106813Ssimokawa it->stdma = NULL; 702106813Ssimokawa it->stdma2 = NULL; 703106813Ssimokawa it->stproc = NULL; 704106813Ssimokawa 705106813Ssimokawa for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){ 706106813Ssimokawa ir->bulkxfer[i].buf = 707106813Ssimokawa ir->buf + 708106813Ssimokawa i * sc->fc->ir[sub]->bnpacket * 709106813Ssimokawa sc->fc->ir[sub]->psize; 710106813Ssimokawa ir->bulkxfer[i].flag = 0; 711106813Ssimokawa STAILQ_INSERT_TAIL(&ir->stfree, 712106813Ssimokawa &ir->bulkxfer[i], link); 713106813Ssimokawa ir->bulkxfer[i].npacket = ir->bnpacket; 714106813Ssimokawa } 715106813Ssimokawa for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){ 716106813Ssimokawa it->bulkxfer[i].buf = 717106813Ssimokawa it->buf + 718106813Ssimokawa i * sc->fc->it[sub]->bnpacket * 719106813Ssimokawa sc->fc->it[sub]->psize; 720106813Ssimokawa it->bulkxfer[i].flag = 0; 721106813Ssimokawa STAILQ_INSERT_TAIL(&it->stfree, 722106813Ssimokawa &it->bulkxfer[i], link); 723106813Ssimokawa it->bulkxfer[i].npacket = it->bnpacket; 724106813Ssimokawa } 725106813Ssimokawa ir->flag &= ~FWXFERQ_MODEMASK; 726106813Ssimokawa ir->flag |= FWXFERQ_STREAM; 727106813Ssimokawa ir->flag |= FWXFERQ_EXTBUF; 728106813Ssimokawa 729106813Ssimokawa it->flag &= ~FWXFERQ_MODEMASK; 730106813Ssimokawa it->flag |= FWXFERQ_STREAM; 731106813Ssimokawa it->flag |= FWXFERQ_EXTBUF; 732106813Ssimokawa err = 0; 733106813Ssimokawa break; 734106813Ssimokawa case FW_GSTBUF: 735106813Ssimokawa ibufreq->rx.nchunk = sc->fc->ir[sub]->bnchunk; 736106813Ssimokawa ibufreq->rx.npacket = sc->fc->ir[sub]->bnpacket; 737106813Ssimokawa ibufreq->rx.psize = sc->fc->ir[sub]->psize; 738106813Ssimokawa 739106813Ssimokawa ibufreq->tx.nchunk = sc->fc->it[sub]->bnchunk; 740106813Ssimokawa ibufreq->tx.npacket = sc->fc->it[sub]->bnpacket; 741106813Ssimokawa ibufreq->tx.psize = sc->fc->it[sub]->psize; 742106813Ssimokawa break; 743106813Ssimokawa case FW_ASYREQ: 744106813Ssimokawa xfer = fw_xfer_alloc(); 745106813Ssimokawa if(xfer == NULL){ 746106813Ssimokawa err = ENOMEM; 747106813Ssimokawa return err; 748106813Ssimokawa } 749106813Ssimokawa fp = &asyreq->pkt; 750106813Ssimokawa switch (asyreq->req.type) { 751106813Ssimokawa case FWASREQNODE: 752106813Ssimokawa xfer->dst = ntohs(fp->mode.hdr.dst); 753106813Ssimokawa break; 754106813Ssimokawa case FWASREQEUI: 755106813Ssimokawa fwdev = fw_noderesolve(sc->fc, asyreq->req.dst.eui); 756106813Ssimokawa if (fwdev == NULL) { 757108782Ssimokawa device_printf(sc->fc->bdev, 758108782Ssimokawa "cannot find node\n"); 759106813Ssimokawa err = EINVAL; 760106813Ssimokawa goto error; 761106813Ssimokawa } 762106813Ssimokawa xfer->dst = fwdev->dst; 763106813Ssimokawa fp->mode.hdr.dst = htons(FWLOCALBUS | xfer->dst); 764106813Ssimokawa break; 765106813Ssimokawa case FWASRESTL: 766106813Ssimokawa /* XXX what's this? */ 767106813Ssimokawa break; 768106813Ssimokawa case FWASREQSTREAM: 769106813Ssimokawa /* nothing to do */ 770106813Ssimokawa break; 771106813Ssimokawa } 772106813Ssimokawa xfer->spd = asyreq->req.sped; 773106813Ssimokawa xfer->send.len = asyreq->req.len; 774106813Ssimokawa xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT); 775106813Ssimokawa if(xfer->send.buf == NULL){ 776106813Ssimokawa return ENOMEM; 777106813Ssimokawa } 778106813Ssimokawa xfer->send.off = 0; 779106813Ssimokawa bcopy(fp, xfer->send.buf, xfer->send.len); 780106813Ssimokawa xfer->act.hand = fw_asy_callback; 781106813Ssimokawa err = fw_asyreq(sc->fc, sub, xfer); 782106813Ssimokawa if(err){ 783106813Ssimokawa fw_xfer_free( xfer); 784106813Ssimokawa return err; 785106813Ssimokawa } 786106813Ssimokawa err = tsleep((caddr_t)xfer, FWPRI, "asyreq", hz); 787106813Ssimokawa if(err == 0){ 788106813Ssimokawa if(asyreq->req.len >= xfer->recv.len){ 789106813Ssimokawa asyreq->req.len = xfer->recv.len; 790106813Ssimokawa }else{ 791106813Ssimokawa err = EINVAL; 792106813Ssimokawa } 793106813Ssimokawa bcopy(xfer->recv.buf + xfer->recv.off, fp, asyreq->req.len); 794106813Ssimokawa } 795106813Ssimokawaerror: 796106813Ssimokawa fw_xfer_free( xfer); 797106813Ssimokawa break; 798106813Ssimokawa case FW_IBUSRST: 799106813Ssimokawa sc->fc->ibr(sc->fc); 800106813Ssimokawa break; 801106813Ssimokawa case FW_CBINDADDR: 802106813Ssimokawa fwb = fw_bindlookup(sc->fc, 803106813Ssimokawa bindreq->start.hi, bindreq->start.lo); 804106813Ssimokawa if(fwb == NULL){ 805106813Ssimokawa err = EINVAL; 806106813Ssimokawa break; 807106813Ssimokawa } 808106813Ssimokawa STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 809106813Ssimokawa STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist); 810106813Ssimokawa free(fwb, M_DEVBUF); 811106813Ssimokawa break; 812106813Ssimokawa case FW_SBINDADDR: 813106813Ssimokawa if(bindreq->len <= 0 ){ 814106813Ssimokawa err = EINVAL; 815106813Ssimokawa break; 816106813Ssimokawa } 817106813Ssimokawa if(bindreq->start.hi > 0xffff ){ 818106813Ssimokawa err = EINVAL; 819106813Ssimokawa break; 820106813Ssimokawa } 821109424Ssimokawa fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_DEVBUF, M_NOWAIT); 822106813Ssimokawa if(fwb == NULL){ 823106813Ssimokawa err = ENOMEM; 824106813Ssimokawa break; 825106813Ssimokawa } 826106813Ssimokawa fwb->start_hi = bindreq->start.hi; 827106813Ssimokawa fwb->start_lo = bindreq->start.lo; 828106813Ssimokawa fwb->addrlen = bindreq->len; 829106813Ssimokawa 830106813Ssimokawa xfer = fw_xfer_alloc(); 831106813Ssimokawa if(xfer == NULL){ 832106813Ssimokawa err = ENOMEM; 833106813Ssimokawa return err; 834106813Ssimokawa } 835106813Ssimokawa xfer->act_type = FWACT_CH; 836106813Ssimokawa xfer->sub = sub; 837106813Ssimokawa xfer->fc = sc->fc; 838106813Ssimokawa 839106813Ssimokawa fwb->xfer = xfer; 840106813Ssimokawa err = fw_bindadd(sc->fc, fwb); 841106813Ssimokawa break; 842106813Ssimokawa case FW_GDEVLST: 843109814Ssimokawa i = len = 1; 844109814Ssimokawa /* myself */ 845109814Ssimokawa devinfo = &fwdevlst->dev[0]; 846109814Ssimokawa devinfo->dst = sc->fc->nodeid; 847109814Ssimokawa devinfo->status = 0; /* XXX */ 848109814Ssimokawa devinfo->eui.hi = sc->fc->eui.hi; 849109814Ssimokawa devinfo->eui.lo = sc->fc->eui.lo; 850109814Ssimokawa for (fwdev = TAILQ_FIRST(&sc->fc->devices); fwdev != NULL; 851109814Ssimokawa fwdev = TAILQ_NEXT(fwdev, link)) { 852109814Ssimokawa if(len < FW_MAX_DEVLST){ 853109814Ssimokawa devinfo = &fwdevlst->dev[len++]; 854109814Ssimokawa devinfo->dst = fwdev->dst; 855109814Ssimokawa devinfo->status = 856109814Ssimokawa (fwdev->status == FWDEVINVAL)?0:1; 857109814Ssimokawa devinfo->eui.hi = fwdev->eui.hi; 858109814Ssimokawa devinfo->eui.lo = fwdev->eui.lo; 859106813Ssimokawa } 860106813Ssimokawa i++; 861106813Ssimokawa } 862106813Ssimokawa fwdevlst->n = i; 863109814Ssimokawa fwdevlst->info_len = len; 864106813Ssimokawa break; 865106813Ssimokawa case FW_GTPMAP: 866106813Ssimokawa bcopy(sc->fc->topology_map, data, 867106813Ssimokawa (sc->fc->topology_map->crc_len + 1) * 4); 868106813Ssimokawa break; 869106813Ssimokawa case FW_GCROM: 870106813Ssimokawa for (fwdev = TAILQ_FIRST(&sc->fc->devices); fwdev != NULL; 871106813Ssimokawa fwdev = TAILQ_NEXT(fwdev, link)) { 872106813Ssimokawa if (fwdev->eui.hi == crom_buf->eui.hi && 873106813Ssimokawa fwdev->eui.lo == crom_buf->eui.lo) 874106813Ssimokawa break; 875106813Ssimokawa } 876106813Ssimokawa if (fwdev == NULL) { 877106813Ssimokawa err = FWNODE_INVAL; 878106813Ssimokawa break; 879106813Ssimokawa } 880106813Ssimokawa#if 0 881106813Ssimokawa if (fwdev->csrrom[0] >> 24 == 1) 882106813Ssimokawa len = 4; 883106813Ssimokawa else 884106813Ssimokawa len = (1 + ((fwdev->csrrom[0] >> 16) & 0xff)) * 4; 885106813Ssimokawa#else 886106813Ssimokawa if (fwdev->rommax < CSRROMOFF) 887106813Ssimokawa len = 0; 888106813Ssimokawa else 889106813Ssimokawa len = fwdev->rommax - CSRROMOFF + 4; 890106813Ssimokawa#endif 891106813Ssimokawa if (crom_buf->len < len) 892106813Ssimokawa len = crom_buf->len; 893106813Ssimokawa else 894106813Ssimokawa crom_buf->len = len; 895106813Ssimokawa err = copyout(&fwdev->csrrom[0], crom_buf->ptr, len); 896106813Ssimokawa break; 897106813Ssimokawa default: 898106813Ssimokawa sc->fc->ioctl (dev, cmd, data, flag, td); 899106813Ssimokawa break; 900106813Ssimokawa } 901106813Ssimokawa return err; 902106813Ssimokawa} 903106813Ssimokawaint 904106813Ssimokawafw_poll(dev_t dev, int events, fw_proc *td) 905106813Ssimokawa{ 906106813Ssimokawa int revents; 907106813Ssimokawa int tmp; 908106813Ssimokawa int unit = DEV2UNIT(dev); 909106813Ssimokawa int sub = DEV2DMACH(dev); 910106813Ssimokawa struct firewire_softc *sc; 911106813Ssimokawa 912106813Ssimokawa if (DEV_FWMEM(dev)) 913106813Ssimokawa return fwmem_poll(dev, events, td); 914106813Ssimokawa 915106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 916106813Ssimokawa revents = 0; 917106813Ssimokawa tmp = POLLIN | POLLRDNORM; 918106813Ssimokawa if (events & tmp) { 919106813Ssimokawa if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL) 920106813Ssimokawa revents |= tmp; 921106813Ssimokawa else 922106813Ssimokawa selrecord(td, &sc->fc->ir[sub]->rsel); 923106813Ssimokawa } 924106813Ssimokawa tmp = POLLOUT | POLLWRNORM; 925106813Ssimokawa if (events & tmp) { 926106813Ssimokawa /* XXX should be fixed */ 927106813Ssimokawa revents |= tmp; 928106813Ssimokawa } 929106813Ssimokawa 930106813Ssimokawa return revents; 931106813Ssimokawa} 932106813Ssimokawa 933106813Ssimokawastatic int 934106813Ssimokawafw_mmap (dev_t dev, vm_offset_t offset, int nproto) 935106813Ssimokawa{ 936106813Ssimokawa struct firewire_softc *fc; 937106813Ssimokawa int unit = DEV2UNIT(dev); 938106813Ssimokawa 939106813Ssimokawa if (DEV_FWMEM(dev)) 940106813Ssimokawa return fwmem_mmap(dev, offset, nproto); 941106813Ssimokawa 942106813Ssimokawa fc = devclass_get_softc(firewire_devclass, unit); 943106813Ssimokawa 944106813Ssimokawa return EINVAL; 945106813Ssimokawa} 946