fwdev.c revision 111942
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 111942 2003-03-06 05:06:44Z 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{ 70111942Ssimokawa#if __FreeBSD_version >= 500104 71111815Sphk .d_open = fw_open, 72111815Sphk .d_close = fw_close, 73111815Sphk .d_read = fw_read, 74111815Sphk .d_write = fw_write, 75111815Sphk .d_ioctl = fw_ioctl, 76111815Sphk .d_poll = fw_poll, 77111815Sphk .d_mmap = fw_mmap, 78111815Sphk .d_name = "fw", 79111815Sphk .d_maj = CDEV_MAJOR, 80111815Sphk .d_flags = D_MEM 81111942Ssimokawa#else 82111942Ssimokawa fw_open, fw_close, fw_read, fw_write, fw_ioctl, 83111942Ssimokawa fw_poll, fw_mmap, nostrategy, "fw", CDEV_MAJOR, nodump, nopsize, D_MEM 84111942Ssimokawa#endif 85106813Ssimokawa}; 86106813Ssimokawa 87106813Ssimokawastatic int 88106813Ssimokawafw_open (dev_t dev, int flags, int fmt, fw_proc *td) 89106813Ssimokawa{ 90106813Ssimokawa struct firewire_softc *sc; 91106813Ssimokawa int unit = DEV2UNIT(dev); 92106813Ssimokawa int sub = DEV2DMACH(dev); 93106813Ssimokawa 94106813Ssimokawa int err = 0; 95106813Ssimokawa 96106813Ssimokawa if (DEV_FWMEM(dev)) 97106813Ssimokawa return fwmem_open(dev, flags, fmt, td); 98106813Ssimokawa 99106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 100106813Ssimokawa if(sc->fc->ir[sub]->flag & FWXFERQ_OPEN){ 101106813Ssimokawa err = EBUSY; 102106813Ssimokawa return err; 103106813Ssimokawa } 104106813Ssimokawa if(sc->fc->it[sub]->flag & FWXFERQ_OPEN){ 105106813Ssimokawa err = EBUSY; 106106813Ssimokawa return err; 107106813Ssimokawa } 108106813Ssimokawa if(sc->fc->ir[sub]->flag & FWXFERQ_MODEMASK){ 109106813Ssimokawa err = EBUSY; 110106813Ssimokawa return err; 111106813Ssimokawa } 112106813Ssimokawa/* Default is per packet mode */ 113106813Ssimokawa sc->fc->ir[sub]->flag |= FWXFERQ_OPEN; 114106813Ssimokawa sc->fc->it[sub]->flag |= FWXFERQ_OPEN; 115106813Ssimokawa sc->fc->ir[sub]->flag |= FWXFERQ_PACKET; 116106813Ssimokawa return err; 117106813Ssimokawa} 118106813Ssimokawa 119106813Ssimokawastatic int 120106813Ssimokawafw_close (dev_t dev, int flags, int fmt, fw_proc *td) 121106813Ssimokawa{ 122106813Ssimokawa struct firewire_softc *sc; 123106813Ssimokawa int unit = DEV2UNIT(dev); 124106813Ssimokawa int sub = DEV2DMACH(dev); 125106813Ssimokawa struct fw_xfer *xfer; 126106813Ssimokawa struct fw_bind *fwb; 127106813Ssimokawa int err = 0; 128106813Ssimokawa 129106813Ssimokawa if (DEV_FWMEM(dev)) 130106813Ssimokawa return fwmem_close(dev, flags, fmt, td); 131106813Ssimokawa 132106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 133106813Ssimokawa if(!(sc->fc->ir[sub]->flag & FWXFERQ_OPEN)){ 134106813Ssimokawa err = EINVAL; 135106813Ssimokawa return err; 136106813Ssimokawa } 137106813Ssimokawa sc->fc->ir[sub]->flag &= ~FWXFERQ_OPEN; 138106813Ssimokawa if(!(sc->fc->it[sub]->flag & FWXFERQ_OPEN)){ 139106813Ssimokawa err = EINVAL; 140106813Ssimokawa return err; 141106813Ssimokawa } 142106813Ssimokawa sc->fc->it[sub]->flag &= ~FWXFERQ_OPEN; 143106813Ssimokawa 144106813Ssimokawa if(sc->fc->ir[sub]->flag & FWXFERQ_RUNNING){ 145106813Ssimokawa sc->fc->irx_disable(sc->fc, sub); 146106813Ssimokawa } 147106813Ssimokawa if(sc->fc->it[sub]->flag & FWXFERQ_RUNNING){ 148106813Ssimokawa sc->fc->it[sub]->flag &= ~FWXFERQ_RUNNING; 149106813Ssimokawa sc->fc->itx_disable(sc->fc, sub); 150106813Ssimokawa } 151109802Ssimokawa#ifdef FWXFERQ_DV 152106813Ssimokawa if(sc->fc->it[sub]->flag & FWXFERQ_DV){ 153109802Ssimokawa struct fw_dvbuf *dvbuf; 154109802Ssimokawa 155106813Ssimokawa if((dvbuf = sc->fc->it[sub]->dvproc) != NULL){ 156110195Ssimokawa free(dvbuf->buf, M_FW); 157106813Ssimokawa sc->fc->it[sub]->dvproc = NULL; 158106813Ssimokawa } 159106813Ssimokawa if((dvbuf = sc->fc->it[sub]->dvdma) != NULL){ 160110195Ssimokawa free(dvbuf->buf, M_FW); 161106813Ssimokawa sc->fc->it[sub]->dvdma = NULL; 162106813Ssimokawa } 163106813Ssimokawa while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvvalid)) != NULL){ 164106813Ssimokawa STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvvalid, link); 165110195Ssimokawa free(dvbuf->buf, M_FW); 166106813Ssimokawa } 167106813Ssimokawa while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvfree)) != NULL){ 168106813Ssimokawa STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvfree, link); 169110195Ssimokawa free(dvbuf->buf, M_FW); 170106813Ssimokawa } 171110195Ssimokawa free(sc->fc->it[sub]->dvbuf, M_FW); 172106813Ssimokawa sc->fc->it[sub]->dvbuf = NULL; 173106813Ssimokawa } 174109802Ssimokawa#endif 175106813Ssimokawa if(sc->fc->ir[sub]->flag & FWXFERQ_EXTBUF){ 176110195Ssimokawa free(sc->fc->ir[sub]->buf, M_FW); 177106813Ssimokawa sc->fc->ir[sub]->buf = NULL; 178110195Ssimokawa free(sc->fc->ir[sub]->bulkxfer, M_FW); 179106813Ssimokawa sc->fc->ir[sub]->bulkxfer = NULL; 180106813Ssimokawa sc->fc->ir[sub]->flag &= ~FWXFERQ_EXTBUF; 181109379Ssimokawa sc->fc->ir[sub]->psize = PAGE_SIZE; 182106813Ssimokawa sc->fc->ir[sub]->maxq = FWMAXQUEUE; 183106813Ssimokawa } 184106813Ssimokawa if(sc->fc->it[sub]->flag & FWXFERQ_EXTBUF){ 185110195Ssimokawa free(sc->fc->it[sub]->buf, M_FW); 186106813Ssimokawa sc->fc->it[sub]->buf = NULL; 187110195Ssimokawa free(sc->fc->it[sub]->bulkxfer, M_FW); 188106813Ssimokawa sc->fc->it[sub]->bulkxfer = NULL; 189109890Ssimokawa#ifdef FWXFERQ_DV 190106813Ssimokawa sc->fc->it[sub]->dvbuf = NULL; 191109890Ssimokawa#endif 192106813Ssimokawa sc->fc->it[sub]->flag &= ~FWXFERQ_EXTBUF; 193109379Ssimokawa sc->fc->it[sub]->psize = 0; 194106813Ssimokawa sc->fc->it[sub]->maxq = FWMAXQUEUE; 195106813Ssimokawa } 196106813Ssimokawa for(xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q); 197106813Ssimokawa xfer != NULL; xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q)){ 198106813Ssimokawa sc->fc->ir[sub]->queued--; 199106813Ssimokawa STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->q, link); 200106813Ssimokawa 201106813Ssimokawa xfer->resp = 0; 202106813Ssimokawa switch(xfer->act_type){ 203106813Ssimokawa case FWACT_XFER: 204106813Ssimokawa fw_xfer_done(xfer); 205106813Ssimokawa break; 206106813Ssimokawa default: 207106813Ssimokawa break; 208106813Ssimokawa } 209106813Ssimokawa fw_xfer_free(xfer); 210106813Ssimokawa } 211106813Ssimokawa for(fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds); fwb != NULL; 212106813Ssimokawa fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds)){ 213106813Ssimokawa STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 214106813Ssimokawa STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->binds, chlist); 215110195Ssimokawa free(fwb, M_FW); 216106813Ssimokawa } 217106813Ssimokawa sc->fc->ir[sub]->flag &= ~FWXFERQ_MODEMASK; 218106813Ssimokawa sc->fc->it[sub]->flag &= ~FWXFERQ_MODEMASK; 219106813Ssimokawa return err; 220106813Ssimokawa} 221106813Ssimokawa 222106813Ssimokawa/* 223106813Ssimokawa * read request. 224106813Ssimokawa */ 225106813Ssimokawastatic int 226106813Ssimokawafw_read (dev_t dev, struct uio *uio, int ioflag) 227106813Ssimokawa{ 228106813Ssimokawa struct firewire_softc *sc; 229106813Ssimokawa struct fw_xferq *ir; 230106813Ssimokawa struct fw_xfer *xfer; 231106813Ssimokawa int err = 0, s, slept = 0; 232106813Ssimokawa int unit = DEV2UNIT(dev); 233106813Ssimokawa int sub = DEV2DMACH(dev); 234106813Ssimokawa struct fw_pkt *fp; 235106813Ssimokawa 236106813Ssimokawa if (DEV_FWMEM(dev)) 237106813Ssimokawa return fwmem_read(dev, uio, ioflag); 238106813Ssimokawa 239106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 240106813Ssimokawa 241106813Ssimokawa ir = sc->fc->ir[sub]; 242106813Ssimokawa 243109988Ssimokawa if (ir->flag & FWXFERQ_PACKET) { 244106813Ssimokawa ir->stproc = NULL; 245106813Ssimokawa } 246106813Ssimokawareadloop: 247106813Ssimokawa xfer = STAILQ_FIRST(&ir->q); 248109988Ssimokawa if ((ir->flag & FWXFERQ_PACKET) == 0 && ir->stproc == NULL) { 249109988Ssimokawa /* iso bulkxfer */ 250106813Ssimokawa ir->stproc = STAILQ_FIRST(&ir->stvalid); 251109988Ssimokawa if (ir->stproc != NULL) { 252106813Ssimokawa s = splfw(); 253106813Ssimokawa STAILQ_REMOVE_HEAD(&ir->stvalid, link); 254106813Ssimokawa splx(s); 255106813Ssimokawa ir->queued = 0; 256106813Ssimokawa } 257106813Ssimokawa } 258109988Ssimokawa if (xfer == NULL && ir->stproc == NULL) { 259109988Ssimokawa /* no data avaliable */ 260109988Ssimokawa if (slept == 0) { 261106813Ssimokawa slept = 1; 262109988Ssimokawa if ((ir->flag & FWXFERQ_RUNNING) == 0 263109988Ssimokawa && (ir->flag & FWXFERQ_PACKET)) { 264106813Ssimokawa err = sc->fc->irx_enable(sc->fc, sub); 265109988Ssimokawa if (err) 266109988Ssimokawa return err; 267106813Ssimokawa } 268106813Ssimokawa ir->flag |= FWXFERQ_WAKEUP; 269111748Sdes err = tsleep(ir, FWPRI, "fw_read", hz); 270109988Ssimokawa ir->flag &= ~FWXFERQ_WAKEUP; 271109988Ssimokawa if (err == 0) 272109988Ssimokawa goto readloop; 273109988Ssimokawa } else if (slept == 1) 274106813Ssimokawa err = EIO; 275109988Ssimokawa return err; 276109988Ssimokawa } else if(xfer != NULL) { 277109988Ssimokawa /* per packet mode */ 278106813Ssimokawa s = splfw(); 279106813Ssimokawa ir->queued --; 280106813Ssimokawa STAILQ_REMOVE_HEAD(&ir->q, link); 281106813Ssimokawa splx(s); 282106813Ssimokawa fp = (struct fw_pkt *)(xfer->recv.buf + xfer->recv.off); 283106813Ssimokawa if(sc->fc->irx_post != NULL) 284106813Ssimokawa sc->fc->irx_post(sc->fc, fp->mode.ld); 285106813Ssimokawa err = uiomove(xfer->recv.buf + xfer->recv.off, xfer->recv.len, uio); 286106813Ssimokawa fw_xfer_free( xfer); 287109988Ssimokawa } else if(ir->stproc != NULL) { 288109988Ssimokawa /* iso bulkxfer */ 289106813Ssimokawa fp = (struct fw_pkt *)(ir->stproc->buf + ir->queued * ir->psize); 290106813Ssimokawa if(sc->fc->irx_post != NULL) 291106813Ssimokawa sc->fc->irx_post(sc->fc, fp->mode.ld); 292106813Ssimokawa if(ntohs(fp->mode.stream.len) == 0){ 293106813Ssimokawa err = EIO; 294106813Ssimokawa return err; 295106813Ssimokawa } 296109988Ssimokawa err = uiomove((caddr_t)fp, 297109988Ssimokawa ntohs(fp->mode.stream.len) + sizeof(u_int32_t), uio); 298109988Ssimokawa#if 0 299106813Ssimokawa fp->mode.stream.len = 0; 300109988Ssimokawa#endif 301106813Ssimokawa ir->queued ++; 302106813Ssimokawa if(ir->queued >= ir->bnpacket){ 303106813Ssimokawa s = splfw(); 304106813Ssimokawa STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 305106813Ssimokawa splx(s); 306109890Ssimokawa sc->fc->irx_enable(sc->fc, sub); 307106813Ssimokawa ir->stproc = NULL; 308106813Ssimokawa } 309109988Ssimokawa if (uio->uio_resid >= ir->psize) { 310109988Ssimokawa slept = -1; 311109988Ssimokawa goto readloop; 312109988Ssimokawa } 313106813Ssimokawa } 314106813Ssimokawa return err; 315106813Ssimokawa} 316106813Ssimokawa 317106813Ssimokawastatic int 318106813Ssimokawafw_write (dev_t dev, struct uio *uio, int ioflag) 319106813Ssimokawa{ 320106813Ssimokawa int err = 0; 321106813Ssimokawa struct firewire_softc *sc; 322106813Ssimokawa int unit = DEV2UNIT(dev); 323106813Ssimokawa int sub = DEV2DMACH(dev); 324106813Ssimokawa int s, slept = 0; 325106813Ssimokawa struct fw_pkt *fp; 326106813Ssimokawa struct fw_xfer *xfer; 327106813Ssimokawa struct fw_xferq *xferq; 328106813Ssimokawa struct firewire_comm *fc; 329106813Ssimokawa struct fw_xferq *it; 330106813Ssimokawa 331106813Ssimokawa if (DEV_FWMEM(dev)) 332106813Ssimokawa return fwmem_write(dev, uio, ioflag); 333106813Ssimokawa 334106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 335106813Ssimokawa fc = sc->fc; 336106813Ssimokawa it = sc->fc->it[sub]; 337106813Ssimokawa 338106813Ssimokawa fp = (struct fw_pkt *)uio->uio_iov->iov_base; 339106813Ssimokawa switch(fp->mode.common.tcode){ 340106813Ssimokawa case FWTCODE_RREQQ: 341106813Ssimokawa case FWTCODE_RREQB: 342106813Ssimokawa case FWTCODE_LREQ: 343106813Ssimokawa err = EINVAL; 344106813Ssimokawa return err; 345106813Ssimokawa case FWTCODE_WREQQ: 346106813Ssimokawa case FWTCODE_WREQB: 347106813Ssimokawa xferq = fc->atq; 348106813Ssimokawa break; 349106813Ssimokawa case FWTCODE_STREAM: 350106813Ssimokawa if(it->flag & FWXFERQ_PACKET){ 351106813Ssimokawa xferq = fc->atq; 352106813Ssimokawa }else{ 353106813Ssimokawa xferq = NULL; 354106813Ssimokawa } 355106813Ssimokawa break; 356106813Ssimokawa case FWTCODE_WRES: 357106813Ssimokawa case FWTCODE_RRESQ: 358106813Ssimokawa case FWTCODE_RRESB: 359106813Ssimokawa case FWTCODE_LRES: 360106813Ssimokawa xferq = fc->ats; 361106813Ssimokawa break; 362106813Ssimokawa default: 363106813Ssimokawa err = EINVAL; 364106813Ssimokawa return err; 365106813Ssimokawa } 366106813Ssimokawa /* Discard unsent buffered stream packet, when sending Asyrequrst */ 367106813Ssimokawa if(xferq != NULL && it->stproc != NULL){ 368106813Ssimokawa s = splfw(); 369106813Ssimokawa STAILQ_INSERT_TAIL(&it->stfree, it->stproc, link); 370106813Ssimokawa splx(s); 371106813Ssimokawa it->stproc = NULL; 372106813Ssimokawa } 373109802Ssimokawa#ifdef FWXFERQ_DV 374106813Ssimokawa if(xferq == NULL && !(it->flag & FWXFERQ_DV)){ 375109802Ssimokawa#else 376109802Ssimokawa if (xferq == NULL) { 377109802Ssimokawa#endif 378106813Ssimokawaisoloop: 379109890Ssimokawa if (it->stproc == NULL) { 380106813Ssimokawa it->stproc = STAILQ_FIRST(&it->stfree); 381109890Ssimokawa if (it->stproc != NULL) { 382106813Ssimokawa s = splfw(); 383106813Ssimokawa STAILQ_REMOVE_HEAD(&it->stfree, link); 384106813Ssimokawa splx(s); 385106813Ssimokawa it->queued = 0; 386109890Ssimokawa } else if (slept == 0) { 387106813Ssimokawa slept = 1; 388106813Ssimokawa err = sc->fc->itx_enable(sc->fc, sub); 389109988Ssimokawa if (err) 390106813Ssimokawa return err; 391111748Sdes err = tsleep(it, FWPRI, 392109988Ssimokawa "fw_write", hz); 393109988Ssimokawa if (err) 394106813Ssimokawa return err; 395106813Ssimokawa goto isoloop; 396109988Ssimokawa } else { 397106813Ssimokawa err = EIO; 398106813Ssimokawa return err; 399106813Ssimokawa } 400106813Ssimokawa } 401109988Ssimokawa fp = (struct fw_pkt *) 402109988Ssimokawa (it->stproc->buf + it->queued * it->psize); 403109988Ssimokawa err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 404109988Ssimokawa err = uiomove((caddr_t)fp->mode.stream.payload, 405109988Ssimokawa ntohs(fp->mode.stream.len), uio); 406106813Ssimokawa it->queued ++; 407109988Ssimokawa if (it->queued >= it->bnpacket) { 408106813Ssimokawa s = splfw(); 409106813Ssimokawa STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 410106813Ssimokawa splx(s); 411106813Ssimokawa it->stproc = NULL; 412106813Ssimokawa err = sc->fc->itx_enable(sc->fc, sub); 413106813Ssimokawa } 414109988Ssimokawa if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 415109988Ssimokawa slept = 0; 416109988Ssimokawa goto isoloop; 417109988Ssimokawa } 418106813Ssimokawa return err; 419109802Ssimokawa } 420109802Ssimokawa#ifdef FWXFERQ_DV 421109802Ssimokawa if(xferq == NULL && it->flag & FWXFERQ_DV){ 422106813Ssimokawadvloop: 423106813Ssimokawa if(it->dvproc == NULL){ 424106813Ssimokawa it->dvproc = STAILQ_FIRST(&it->dvfree); 425106813Ssimokawa if(it->dvproc != NULL){ 426106813Ssimokawa s = splfw(); 427106813Ssimokawa STAILQ_REMOVE_HEAD(&it->dvfree, link); 428106813Ssimokawa splx(s); 429106813Ssimokawa it->dvptr = 0; 430106813Ssimokawa }else if(slept == 0){ 431106813Ssimokawa slept = 1; 432106813Ssimokawa err = sc->fc->itx_enable(sc->fc, sub); 433106813Ssimokawa if(err){ 434106813Ssimokawa return err; 435106813Ssimokawa } 436111748Sdes err = tsleep(it, FWPRI, "fw_write", hz); 437106813Ssimokawa if(err){ 438106813Ssimokawa return err; 439106813Ssimokawa } 440106813Ssimokawa goto dvloop; 441106813Ssimokawa }else{ 442106813Ssimokawa err = EIO; 443106813Ssimokawa return err; 444106813Ssimokawa } 445106813Ssimokawa } 446109179Ssimokawa#if 0 /* What's this for? (it->dvptr? overwritten by the following uiomove)*/ 447106813Ssimokawa fp = (struct fw_pkt *)(it->dvproc->buf + it->queued * it->psize); 448106813Ssimokawa fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t)); 449109179Ssimokawa#endif 450106813Ssimokawa err = uiomove(it->dvproc->buf + it->dvptr, 451106813Ssimokawa uio->uio_resid, uio); 452106813Ssimokawa it->dvptr += it->psize; 453106813Ssimokawa if(err){ 454106813Ssimokawa return err; 455106813Ssimokawa } 456106813Ssimokawa if(it->dvptr >= it->psize * it->dvpacket){ 457106813Ssimokawa s = splfw(); 458106813Ssimokawa STAILQ_INSERT_TAIL(&it->dvvalid, it->dvproc, link); 459106813Ssimokawa splx(s); 460106813Ssimokawa it->dvproc = NULL; 461106813Ssimokawa err = fw_tbuf_update(sc->fc, sub, 0); 462106813Ssimokawa if(err){ 463106813Ssimokawa return err; 464106813Ssimokawa } 465106813Ssimokawa err = sc->fc->itx_enable(sc->fc, sub); 466106813Ssimokawa } 467106813Ssimokawa return err; 468106813Ssimokawa } 469109802Ssimokawa#endif 470106813Ssimokawa if(xferq != NULL){ 471110269Ssimokawa xfer = fw_xfer_alloc(M_FWXFER); 472106813Ssimokawa if(xfer == NULL){ 473106813Ssimokawa err = ENOMEM; 474106813Ssimokawa return err; 475106813Ssimokawa } 476110195Ssimokawa xfer->send.buf = malloc(uio->uio_resid, M_FW, M_NOWAIT); 477106813Ssimokawa if(xfer->send.buf == NULL){ 478106813Ssimokawa fw_xfer_free( xfer); 479106813Ssimokawa err = ENOBUFS; 480106813Ssimokawa return err; 481106813Ssimokawa } 482106813Ssimokawa xfer->dst = ntohs(fp->mode.hdr.dst); 483106813Ssimokawa#if 0 484106813Ssimokawa switch(fp->mode.common.tcode){ 485106813Ssimokawa case FWTCODE_WREQQ: 486106813Ssimokawa case FWTCODE_WREQB: 487106813Ssimokawa if((tl = fw_get_tlabel(fc, xfer)) == -1 ){ 488106813Ssimokawa fw_xfer_free( xfer); 489106813Ssimokawa err = EAGAIN; 490106813Ssimokawa return err; 491106813Ssimokawa } 492106813Ssimokawa fp->mode.hdr.tlrt = tl << 2; 493106813Ssimokawa default: 494106813Ssimokawa break; 495106813Ssimokawa } 496106813Ssimokawa 497106813Ssimokawa xfer->tl = fp->mode.hdr.tlrt >> 2; 498106813Ssimokawa xfer->tcode = fp->mode.common.tcode; 499106813Ssimokawa xfer->fc = fc; 500106813Ssimokawa xfer->q = xferq; 501106813Ssimokawa xfer->act_type = FWACT_XFER; 502106813Ssimokawa xfer->retry_req = fw_asybusy; 503106813Ssimokawa#endif 504106813Ssimokawa xfer->send.len = uio->uio_resid; 505106813Ssimokawa xfer->send.off = 0; 506106813Ssimokawa xfer->spd = 0;/* XXX: how to setup it */ 507106813Ssimokawa xfer->act.hand = fw_asy_callback; 508106813Ssimokawa 509106813Ssimokawa err = uiomove(xfer->send.buf, uio->uio_resid, uio); 510106813Ssimokawa if(err){ 511106813Ssimokawa fw_xfer_free( xfer); 512106813Ssimokawa return err; 513106813Ssimokawa } 514106813Ssimokawa#if 0 515106813Ssimokawa fw_asystart(xfer); 516106813Ssimokawa#else 517106813Ssimokawa fw_asyreq(fc, -1, xfer); 518106813Ssimokawa#endif 519111748Sdes err = tsleep(xfer, FWPRI, "fw_write", hz); 520106813Ssimokawa if(xfer->resp == EBUSY) 521106813Ssimokawa return EBUSY; 522106813Ssimokawa fw_xfer_free( xfer); 523106813Ssimokawa return err; 524106813Ssimokawa } 525106813Ssimokawa return EINVAL; 526106813Ssimokawa} 527106813Ssimokawa 528106813Ssimokawa/* 529106813Ssimokawa * ioctl support. 530106813Ssimokawa */ 531106813Ssimokawaint 532106813Ssimokawafw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 533106813Ssimokawa{ 534106813Ssimokawa struct firewire_softc *sc; 535106813Ssimokawa int unit = DEV2UNIT(dev); 536106813Ssimokawa int sub = DEV2DMACH(dev); 537106813Ssimokawa int i, len, err = 0; 538106813Ssimokawa struct fw_device *fwdev; 539106813Ssimokawa struct fw_bind *fwb; 540106813Ssimokawa struct fw_xferq *ir, *it; 541106813Ssimokawa struct fw_xfer *xfer; 542106813Ssimokawa struct fw_pkt *fp; 543109814Ssimokawa struct fw_devinfo *devinfo; 544106813Ssimokawa 545106813Ssimokawa struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 546106813Ssimokawa struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 547106813Ssimokawa struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 548106813Ssimokawa struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 549106813Ssimokawa struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 550106813Ssimokawa struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 551106813Ssimokawa 552106813Ssimokawa if (DEV_FWMEM(dev)) 553106813Ssimokawa return fwmem_ioctl(dev, cmd, data, flag, td); 554106813Ssimokawa 555106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 556106813Ssimokawa if (!data) 557106813Ssimokawa return(EINVAL); 558106813Ssimokawa 559106813Ssimokawa switch (cmd) { 560106813Ssimokawa case FW_STSTREAM: 561106813Ssimokawa sc->fc->it[sub]->flag &= ~0xff; 562106813Ssimokawa sc->fc->it[sub]->flag |= (0x3f & ichreq->ch); 563106813Ssimokawa sc->fc->it[sub]->flag |= ((0x3 & ichreq->tag) << 6); 564106813Ssimokawa err = 0; 565106813Ssimokawa break; 566106813Ssimokawa case FW_GTSTREAM: 567106813Ssimokawa ichreq->ch = sc->fc->it[sub]->flag & 0x3f; 568106813Ssimokawa ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3; 569106813Ssimokawa err = 0; 570106813Ssimokawa break; 571106813Ssimokawa case FW_SRSTREAM: 572106813Ssimokawa sc->fc->ir[sub]->flag &= ~0xff; 573106813Ssimokawa sc->fc->ir[sub]->flag |= (0x3f & ichreq->ch); 574106813Ssimokawa sc->fc->ir[sub]->flag |= ((0x3 & ichreq->tag) << 6); 575106813Ssimokawa err = sc->fc->irx_enable(sc->fc, sub); 576106813Ssimokawa break; 577106813Ssimokawa case FW_GRSTREAM: 578106813Ssimokawa ichreq->ch = sc->fc->ir[sub]->flag & 0x3f; 579106813Ssimokawa ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3; 580106813Ssimokawa err = 0; 581106813Ssimokawa break; 582109802Ssimokawa#ifdef FWXFERQ_DV 583106813Ssimokawa case FW_SSTDV: 584106813Ssimokawa ibufreq = (struct fw_isobufreq *) 585110195Ssimokawa malloc(sizeof(struct fw_isobufreq), M_FW, M_NOWAIT); 586106813Ssimokawa if(ibufreq == NULL){ 587106813Ssimokawa err = ENOMEM; 588106813Ssimokawa break; 589106813Ssimokawa } 590109282Ssimokawa#if DV_PAL 591109282Ssimokawa#define FWDVPACKET 300 592109282Ssimokawa#else 593109282Ssimokawa#define FWDVPACKET 250 594109282Ssimokawa#endif 595106813Ssimokawa#define FWDVPMAX 512 596106813Ssimokawa ibufreq->rx.nchunk = 8; 597106813Ssimokawa ibufreq->rx.npacket = 50; 598106813Ssimokawa ibufreq->rx.psize = FWDVPMAX; 599106813Ssimokawa 600106813Ssimokawa ibufreq->tx.nchunk = 5; 601109282Ssimokawa ibufreq->tx.npacket = FWDVPACKET + 30; /* > 320 or 267 */ 602106813Ssimokawa ibufreq->tx.psize = FWDVPMAX; 603106813Ssimokawa 604106813Ssimokawa err = fw_ioctl(dev, FW_SSTBUF, (caddr_t)ibufreq, flag, td); 605106813Ssimokawa sc->fc->it[sub]->dvpacket = FWDVPACKET; 606110195Ssimokawa free(ibufreq, M_FW); 607106813Ssimokawa/* reserve a buffer space */ 608106813Ssimokawa#define NDVCHUNK 8 609106813Ssimokawa sc->fc->it[sub]->dvproc = NULL; 610106813Ssimokawa sc->fc->it[sub]->dvdma = NULL; 611106813Ssimokawa sc->fc->it[sub]->flag |= FWXFERQ_DV; 612109179Ssimokawa /* XXX check malloc failure */ 613106813Ssimokawa sc->fc->it[sub]->dvbuf 614110195Ssimokawa = (struct fw_dvbuf *)malloc(sizeof(struct fw_dvbuf) * NDVCHUNK, M_FW, M_NOWAIT); 615106813Ssimokawa STAILQ_INIT(&sc->fc->it[sub]->dvvalid); 616106813Ssimokawa STAILQ_INIT(&sc->fc->it[sub]->dvfree); 617106813Ssimokawa for( i = 0 ; i < NDVCHUNK ; i++){ 618109179Ssimokawa /* XXX check malloc failure */ 619106813Ssimokawa sc->fc->it[sub]->dvbuf[i].buf 620110195Ssimokawa = malloc(FWDVPMAX * sc->fc->it[sub]->dvpacket, M_FW, M_NOWAIT); 621106813Ssimokawa STAILQ_INSERT_TAIL(&sc->fc->it[sub]->dvfree, 622106813Ssimokawa &sc->fc->it[sub]->dvbuf[i], link); 623106813Ssimokawa } 624106813Ssimokawa break; 625109802Ssimokawa#endif 626106813Ssimokawa case FW_SSTBUF: 627106813Ssimokawa ir = sc->fc->ir[sub]; 628106813Ssimokawa it = sc->fc->it[sub]; 629106813Ssimokawa 630106813Ssimokawa if(ir->flag & FWXFERQ_RUNNING || it->flag & FWXFERQ_RUNNING){ 631106813Ssimokawa return(EBUSY); 632106813Ssimokawa } 633106813Ssimokawa if((ir->flag & FWXFERQ_EXTBUF) || (it->flag & FWXFERQ_EXTBUF)){ 634106813Ssimokawa return(EBUSY); 635106813Ssimokawa } 636106813Ssimokawa if((ibufreq->rx.nchunk * 637106813Ssimokawa ibufreq->rx.psize * ibufreq->rx.npacket) + 638106813Ssimokawa (ibufreq->tx.nchunk * 639106813Ssimokawa ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){ 640106813Ssimokawa return(EINVAL); 641106813Ssimokawa } 642106813Ssimokawa if(ibufreq->rx.nchunk > FWSTMAXCHUNK || 643106813Ssimokawa ibufreq->tx.nchunk > FWSTMAXCHUNK){ 644106813Ssimokawa return(EINVAL); 645106813Ssimokawa } 646106813Ssimokawa ir->bulkxfer 647110273Ssimokawa = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_FW, 0); 648106813Ssimokawa if(ir->bulkxfer == NULL){ 649106813Ssimokawa return(ENOMEM); 650106813Ssimokawa } 651106813Ssimokawa it->bulkxfer 652110273Ssimokawa = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_FW, 0); 653106813Ssimokawa if(it->bulkxfer == NULL){ 654106813Ssimokawa return(ENOMEM); 655106813Ssimokawa } 656106813Ssimokawa ir->buf = malloc( 657106813Ssimokawa ibufreq->rx.nchunk * ibufreq->rx.npacket 658109403Ssimokawa /* XXX psize must be 2^n and less or 659109403Ssimokawa equal to PAGE_SIZE */ 660106813Ssimokawa * ((ibufreq->rx.psize + 3) &~3), 661110273Ssimokawa M_FW, 0); 662106813Ssimokawa if(ir->buf == NULL){ 663110195Ssimokawa free(ir->bulkxfer, M_FW); 664110195Ssimokawa free(it->bulkxfer, M_FW); 665106813Ssimokawa ir->bulkxfer = NULL; 666106813Ssimokawa it->bulkxfer = NULL; 667106813Ssimokawa it->buf = NULL; 668106813Ssimokawa return(ENOMEM); 669106813Ssimokawa } 670106813Ssimokawa it->buf = malloc( 671106813Ssimokawa ibufreq->tx.nchunk * ibufreq->tx.npacket 672109403Ssimokawa /* XXX psize must be 2^n and less or 673109403Ssimokawa equal to PAGE_SIZE */ 674106813Ssimokawa * ((ibufreq->tx.psize + 3) &~3), 675110273Ssimokawa M_FW, 0); 676106813Ssimokawa if(it->buf == NULL){ 677110195Ssimokawa free(ir->bulkxfer, M_FW); 678110195Ssimokawa free(it->bulkxfer, M_FW); 679110195Ssimokawa free(ir->buf, M_FW); 680106813Ssimokawa ir->bulkxfer = NULL; 681106813Ssimokawa it->bulkxfer = NULL; 682106813Ssimokawa it->buf = NULL; 683106813Ssimokawa return(ENOMEM); 684106813Ssimokawa } 685106813Ssimokawa 686106813Ssimokawa ir->bnchunk = ibufreq->rx.nchunk; 687106813Ssimokawa ir->bnpacket = ibufreq->rx.npacket; 688106813Ssimokawa ir->psize = (ibufreq->rx.psize + 3) & ~3; 689106813Ssimokawa ir->queued = 0; 690106813Ssimokawa 691106813Ssimokawa it->bnchunk = ibufreq->tx.nchunk; 692106813Ssimokawa it->bnpacket = ibufreq->tx.npacket; 693106813Ssimokawa it->psize = (ibufreq->tx.psize + 3) & ~3; 694109890Ssimokawa it->queued = 0; 695109890Ssimokawa 696109890Ssimokawa#ifdef FWXFERQ_DV 697106813Ssimokawa it->dvdbc = 0; 698106813Ssimokawa it->dvdiff = 0; 699106813Ssimokawa it->dvsync = 0; 700109179Ssimokawa it->dvoffset = 0; 701109890Ssimokawa#endif 702106813Ssimokawa 703106813Ssimokawa STAILQ_INIT(&ir->stvalid); 704106813Ssimokawa STAILQ_INIT(&ir->stfree); 705109890Ssimokawa STAILQ_INIT(&ir->stdma); 706106813Ssimokawa ir->stproc = NULL; 707106813Ssimokawa 708106813Ssimokawa STAILQ_INIT(&it->stvalid); 709106813Ssimokawa STAILQ_INIT(&it->stfree); 710109890Ssimokawa STAILQ_INIT(&it->stdma); 711106813Ssimokawa it->stproc = NULL; 712106813Ssimokawa 713106813Ssimokawa for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){ 714106813Ssimokawa ir->bulkxfer[i].buf = 715111942Ssimokawa ir->buf + i * ir->bnpacket * ir->psize; 716106813Ssimokawa STAILQ_INSERT_TAIL(&ir->stfree, 717106813Ssimokawa &ir->bulkxfer[i], link); 718106813Ssimokawa ir->bulkxfer[i].npacket = ir->bnpacket; 719106813Ssimokawa } 720106813Ssimokawa for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){ 721106813Ssimokawa it->bulkxfer[i].buf = 722111942Ssimokawa it->buf + i * it->bnpacket * it->psize; 723106813Ssimokawa STAILQ_INSERT_TAIL(&it->stfree, 724106813Ssimokawa &it->bulkxfer[i], link); 725106813Ssimokawa it->bulkxfer[i].npacket = it->bnpacket; 726106813Ssimokawa } 727106813Ssimokawa ir->flag &= ~FWXFERQ_MODEMASK; 728106813Ssimokawa ir->flag |= FWXFERQ_STREAM; 729106813Ssimokawa ir->flag |= FWXFERQ_EXTBUF; 730106813Ssimokawa 731106813Ssimokawa it->flag &= ~FWXFERQ_MODEMASK; 732106813Ssimokawa it->flag |= FWXFERQ_STREAM; 733106813Ssimokawa it->flag |= FWXFERQ_EXTBUF; 734106813Ssimokawa err = 0; 735106813Ssimokawa break; 736106813Ssimokawa case FW_GSTBUF: 737106813Ssimokawa ibufreq->rx.nchunk = sc->fc->ir[sub]->bnchunk; 738106813Ssimokawa ibufreq->rx.npacket = sc->fc->ir[sub]->bnpacket; 739106813Ssimokawa ibufreq->rx.psize = sc->fc->ir[sub]->psize; 740106813Ssimokawa 741106813Ssimokawa ibufreq->tx.nchunk = sc->fc->it[sub]->bnchunk; 742106813Ssimokawa ibufreq->tx.npacket = sc->fc->it[sub]->bnpacket; 743106813Ssimokawa ibufreq->tx.psize = sc->fc->it[sub]->psize; 744106813Ssimokawa break; 745106813Ssimokawa case FW_ASYREQ: 746110269Ssimokawa xfer = fw_xfer_alloc(M_FWXFER); 747106813Ssimokawa if(xfer == NULL){ 748106813Ssimokawa err = ENOMEM; 749106813Ssimokawa return err; 750106813Ssimokawa } 751106813Ssimokawa fp = &asyreq->pkt; 752106813Ssimokawa switch (asyreq->req.type) { 753106813Ssimokawa case FWASREQNODE: 754106813Ssimokawa xfer->dst = ntohs(fp->mode.hdr.dst); 755106813Ssimokawa break; 756106813Ssimokawa case FWASREQEUI: 757110072Ssimokawa fwdev = fw_noderesolve_eui64(sc->fc, 758110582Ssimokawa &asyreq->req.dst.eui); 759106813Ssimokawa if (fwdev == NULL) { 760108782Ssimokawa device_printf(sc->fc->bdev, 761108782Ssimokawa "cannot find node\n"); 762106813Ssimokawa err = EINVAL; 763106813Ssimokawa goto error; 764106813Ssimokawa } 765106813Ssimokawa xfer->dst = fwdev->dst; 766106813Ssimokawa fp->mode.hdr.dst = htons(FWLOCALBUS | xfer->dst); 767106813Ssimokawa break; 768106813Ssimokawa case FWASRESTL: 769106813Ssimokawa /* XXX what's this? */ 770106813Ssimokawa break; 771106813Ssimokawa case FWASREQSTREAM: 772106813Ssimokawa /* nothing to do */ 773106813Ssimokawa break; 774106813Ssimokawa } 775106813Ssimokawa xfer->spd = asyreq->req.sped; 776106813Ssimokawa xfer->send.len = asyreq->req.len; 777110195Ssimokawa xfer->send.buf = malloc(xfer->send.len, M_FW, M_NOWAIT); 778106813Ssimokawa if(xfer->send.buf == NULL){ 779106813Ssimokawa return ENOMEM; 780106813Ssimokawa } 781106813Ssimokawa xfer->send.off = 0; 782106813Ssimokawa bcopy(fp, xfer->send.buf, xfer->send.len); 783106813Ssimokawa xfer->act.hand = fw_asy_callback; 784106813Ssimokawa err = fw_asyreq(sc->fc, sub, xfer); 785106813Ssimokawa if(err){ 786106813Ssimokawa fw_xfer_free( xfer); 787106813Ssimokawa return err; 788106813Ssimokawa } 789111748Sdes err = tsleep(xfer, FWPRI, "asyreq", hz); 790106813Ssimokawa if(err == 0){ 791106813Ssimokawa if(asyreq->req.len >= xfer->recv.len){ 792106813Ssimokawa asyreq->req.len = xfer->recv.len; 793106813Ssimokawa }else{ 794106813Ssimokawa err = EINVAL; 795106813Ssimokawa } 796106813Ssimokawa bcopy(xfer->recv.buf + xfer->recv.off, fp, asyreq->req.len); 797106813Ssimokawa } 798106813Ssimokawaerror: 799106813Ssimokawa fw_xfer_free( xfer); 800106813Ssimokawa break; 801106813Ssimokawa case FW_IBUSRST: 802106813Ssimokawa sc->fc->ibr(sc->fc); 803106813Ssimokawa break; 804106813Ssimokawa case FW_CBINDADDR: 805106813Ssimokawa fwb = fw_bindlookup(sc->fc, 806106813Ssimokawa bindreq->start.hi, bindreq->start.lo); 807106813Ssimokawa if(fwb == NULL){ 808106813Ssimokawa err = EINVAL; 809106813Ssimokawa break; 810106813Ssimokawa } 811106813Ssimokawa STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 812106813Ssimokawa STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist); 813110195Ssimokawa free(fwb, M_FW); 814106813Ssimokawa break; 815106813Ssimokawa case FW_SBINDADDR: 816106813Ssimokawa if(bindreq->len <= 0 ){ 817106813Ssimokawa err = EINVAL; 818106813Ssimokawa break; 819106813Ssimokawa } 820106813Ssimokawa if(bindreq->start.hi > 0xffff ){ 821106813Ssimokawa err = EINVAL; 822106813Ssimokawa break; 823106813Ssimokawa } 824110195Ssimokawa fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT); 825106813Ssimokawa if(fwb == NULL){ 826106813Ssimokawa err = ENOMEM; 827106813Ssimokawa break; 828106813Ssimokawa } 829106813Ssimokawa fwb->start_hi = bindreq->start.hi; 830106813Ssimokawa fwb->start_lo = bindreq->start.lo; 831106813Ssimokawa fwb->addrlen = bindreq->len; 832106813Ssimokawa 833110269Ssimokawa xfer = fw_xfer_alloc(M_FWXFER); 834106813Ssimokawa if(xfer == NULL){ 835106813Ssimokawa err = ENOMEM; 836106813Ssimokawa return err; 837106813Ssimokawa } 838106813Ssimokawa xfer->act_type = FWACT_CH; 839106813Ssimokawa xfer->sub = sub; 840106813Ssimokawa xfer->fc = sc->fc; 841106813Ssimokawa 842106813Ssimokawa fwb->xfer = xfer; 843106813Ssimokawa err = fw_bindadd(sc->fc, fwb); 844106813Ssimokawa break; 845106813Ssimokawa case FW_GDEVLST: 846109814Ssimokawa i = len = 1; 847109814Ssimokawa /* myself */ 848109814Ssimokawa devinfo = &fwdevlst->dev[0]; 849109814Ssimokawa devinfo->dst = sc->fc->nodeid; 850109814Ssimokawa devinfo->status = 0; /* XXX */ 851109814Ssimokawa devinfo->eui.hi = sc->fc->eui.hi; 852109814Ssimokawa devinfo->eui.lo = sc->fc->eui.lo; 853110193Ssimokawa STAILQ_FOREACH(fwdev, &sc->fc->devices, link) { 854109814Ssimokawa if(len < FW_MAX_DEVLST){ 855109814Ssimokawa devinfo = &fwdevlst->dev[len++]; 856109814Ssimokawa devinfo->dst = fwdev->dst; 857109814Ssimokawa devinfo->status = 858109814Ssimokawa (fwdev->status == FWDEVINVAL)?0:1; 859109814Ssimokawa devinfo->eui.hi = fwdev->eui.hi; 860109814Ssimokawa devinfo->eui.lo = fwdev->eui.lo; 861106813Ssimokawa } 862106813Ssimokawa i++; 863106813Ssimokawa } 864106813Ssimokawa fwdevlst->n = i; 865109814Ssimokawa fwdevlst->info_len = len; 866106813Ssimokawa break; 867106813Ssimokawa case FW_GTPMAP: 868106813Ssimokawa bcopy(sc->fc->topology_map, data, 869106813Ssimokawa (sc->fc->topology_map->crc_len + 1) * 4); 870106813Ssimokawa break; 871106813Ssimokawa case FW_GCROM: 872110193Ssimokawa STAILQ_FOREACH(fwdev, &sc->fc->devices, link) 873110193Ssimokawa if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 874106813Ssimokawa break; 875106813Ssimokawa if (fwdev == NULL) { 876106813Ssimokawa err = FWNODE_INVAL; 877106813Ssimokawa break; 878106813Ssimokawa } 879106813Ssimokawa#if 0 880106813Ssimokawa if (fwdev->csrrom[0] >> 24 == 1) 881106813Ssimokawa len = 4; 882106813Ssimokawa else 883106813Ssimokawa len = (1 + ((fwdev->csrrom[0] >> 16) & 0xff)) * 4; 884106813Ssimokawa#else 885106813Ssimokawa if (fwdev->rommax < CSRROMOFF) 886106813Ssimokawa len = 0; 887106813Ssimokawa else 888106813Ssimokawa len = fwdev->rommax - CSRROMOFF + 4; 889106813Ssimokawa#endif 890106813Ssimokawa if (crom_buf->len < len) 891106813Ssimokawa len = crom_buf->len; 892106813Ssimokawa else 893106813Ssimokawa crom_buf->len = len; 894106813Ssimokawa err = copyout(&fwdev->csrrom[0], crom_buf->ptr, len); 895106813Ssimokawa break; 896106813Ssimokawa default: 897106813Ssimokawa sc->fc->ioctl (dev, cmd, data, flag, td); 898106813Ssimokawa break; 899106813Ssimokawa } 900106813Ssimokawa return err; 901106813Ssimokawa} 902106813Ssimokawaint 903106813Ssimokawafw_poll(dev_t dev, int events, fw_proc *td) 904106813Ssimokawa{ 905106813Ssimokawa int revents; 906106813Ssimokawa int tmp; 907106813Ssimokawa int unit = DEV2UNIT(dev); 908106813Ssimokawa int sub = DEV2DMACH(dev); 909106813Ssimokawa struct firewire_softc *sc; 910106813Ssimokawa 911106813Ssimokawa if (DEV_FWMEM(dev)) 912106813Ssimokawa return fwmem_poll(dev, events, td); 913106813Ssimokawa 914106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 915106813Ssimokawa revents = 0; 916106813Ssimokawa tmp = POLLIN | POLLRDNORM; 917106813Ssimokawa if (events & tmp) { 918106813Ssimokawa if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL) 919106813Ssimokawa revents |= tmp; 920106813Ssimokawa else 921106813Ssimokawa selrecord(td, &sc->fc->ir[sub]->rsel); 922106813Ssimokawa } 923106813Ssimokawa tmp = POLLOUT | POLLWRNORM; 924106813Ssimokawa if (events & tmp) { 925106813Ssimokawa /* XXX should be fixed */ 926106813Ssimokawa revents |= tmp; 927106813Ssimokawa } 928106813Ssimokawa 929106813Ssimokawa return revents; 930106813Ssimokawa} 931106813Ssimokawa 932106813Ssimokawastatic int 933111615Ssimokawa#if __FreeBSD_version < 500000 934111615Ssimokawafw_mmap (dev_t dev, vm_offset_t offset, int nproto) 935111615Ssimokawa#else 936111462Smuxfw_mmap (dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nproto) 937111615Ssimokawa#endif 938106813Ssimokawa{ 939106813Ssimokawa struct firewire_softc *fc; 940106813Ssimokawa int unit = DEV2UNIT(dev); 941106813Ssimokawa 942106813Ssimokawa if (DEV_FWMEM(dev)) 943111615Ssimokawa#if __FreeBSD_version < 500000 944111615Ssimokawa return fwmem_mmap(dev, offset, nproto); 945111615Ssimokawa#else 946111462Smux return fwmem_mmap(dev, offset, paddr, nproto); 947111615Ssimokawa#endif 948106813Ssimokawa 949106813Ssimokawa fc = devclass_get_softc(firewire_devclass, unit); 950106813Ssimokawa 951106813Ssimokawa return EINVAL; 952106813Ssimokawa} 953