fwdev.c revision 117473
1106813Ssimokawa/* 2113584Ssimokawa * Copyright (c) 2003 Hidetoshi Shimokawa 3106813Ssimokawa * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 4106813Ssimokawa * All rights reserved. 5106813Ssimokawa * 6106813Ssimokawa * Redistribution and use in source and binary forms, with or without 7106813Ssimokawa * modification, are permitted provided that the following conditions 8106813Ssimokawa * are met: 9106813Ssimokawa * 1. Redistributions of source code must retain the above copyright 10106813Ssimokawa * notice, this list of conditions and the following disclaimer. 11106813Ssimokawa * 2. Redistributions in binary form must reproduce the above copyright 12106813Ssimokawa * notice, this list of conditions and the following disclaimer in the 13106813Ssimokawa * documentation and/or other materials provided with the distribution. 14106813Ssimokawa * 3. All advertising materials mentioning features or use of this software 15106813Ssimokawa * must display the acknowledgement as bellow: 16106813Ssimokawa * 17106813Ssimokawa * This product includes software developed by K. Kobayashi and H. Shimokawa 18106813Ssimokawa * 19106813Ssimokawa * 4. The name of the author may not be used to endorse or promote products 20106813Ssimokawa * derived from this software without specific prior written permission. 21106813Ssimokawa * 22106813Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23106813Ssimokawa * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24106813Ssimokawa * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25106813Ssimokawa * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 26106813Ssimokawa * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27106813Ssimokawa * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28106813Ssimokawa * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29106813Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 30106813Ssimokawa * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31106813Ssimokawa * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32106813Ssimokawa * POSSIBILITY OF SUCH DAMAGE. 33106813Ssimokawa * 34106813Ssimokawa * $FreeBSD: head/sys/dev/firewire/fwdev.c 117473 2003-07-12 09:34:44Z simokawa $ 35106813Ssimokawa * 36106813Ssimokawa */ 37106813Ssimokawa 38106813Ssimokawa#include <sys/param.h> 39106813Ssimokawa#include <sys/systm.h> 40106813Ssimokawa#include <sys/types.h> 41106813Ssimokawa#include <sys/mbuf.h> 42106813Ssimokawa 43106813Ssimokawa#include <sys/kernel.h> 44106813Ssimokawa#include <sys/malloc.h> 45106813Ssimokawa#include <sys/conf.h> 46106813Ssimokawa#include <sys/poll.h> 47106813Ssimokawa 48106813Ssimokawa#include <sys/bus.h> 49113584Ssimokawa#include <machine/bus.h> 50106813Ssimokawa 51106813Ssimokawa#include <sys/ioccom.h> 52106813Ssimokawa 53106813Ssimokawa#include <dev/firewire/firewire.h> 54106813Ssimokawa#include <dev/firewire/firewirereg.h> 55113584Ssimokawa#include <dev/firewire/fwdma.h> 56106813Ssimokawa#include <dev/firewire/fwmem.h> 57109282Ssimokawa#include <dev/firewire/iec68113.h> 58106813Ssimokawa 59106813Ssimokawa#define CDEV_MAJOR 127 60106813Ssimokawa#define FWNODE_INVAL 0xffff 61106813Ssimokawa 62106813Ssimokawastatic d_open_t fw_open; 63106813Ssimokawastatic d_close_t fw_close; 64106813Ssimokawastatic d_ioctl_t fw_ioctl; 65106813Ssimokawastatic d_poll_t fw_poll; 66106813Ssimokawastatic d_read_t fw_read; /* for Isochronous packet */ 67106813Ssimokawastatic d_write_t fw_write; 68106813Ssimokawastatic d_mmap_t fw_mmap; 69106813Ssimokawa 70106813Ssimokawastruct cdevsw firewire_cdevsw = 71106813Ssimokawa{ 72111942Ssimokawa#if __FreeBSD_version >= 500104 73111815Sphk .d_open = fw_open, 74111815Sphk .d_close = fw_close, 75111815Sphk .d_read = fw_read, 76111815Sphk .d_write = fw_write, 77111815Sphk .d_ioctl = fw_ioctl, 78111815Sphk .d_poll = fw_poll, 79111815Sphk .d_mmap = fw_mmap, 80111815Sphk .d_name = "fw", 81111815Sphk .d_maj = CDEV_MAJOR, 82111815Sphk .d_flags = D_MEM 83111942Ssimokawa#else 84111942Ssimokawa fw_open, fw_close, fw_read, fw_write, fw_ioctl, 85111942Ssimokawa fw_poll, fw_mmap, nostrategy, "fw", CDEV_MAJOR, nodump, nopsize, D_MEM 86111942Ssimokawa#endif 87106813Ssimokawa}; 88106813Ssimokawa 89106813Ssimokawastatic int 90106813Ssimokawafw_open (dev_t dev, int flags, int fmt, fw_proc *td) 91106813Ssimokawa{ 92106813Ssimokawa struct firewire_softc *sc; 93106813Ssimokawa int unit = DEV2UNIT(dev); 94106813Ssimokawa int sub = DEV2DMACH(dev); 95106813Ssimokawa 96106813Ssimokawa int err = 0; 97106813Ssimokawa 98106813Ssimokawa if (DEV_FWMEM(dev)) 99106813Ssimokawa return fwmem_open(dev, flags, fmt, td); 100106813Ssimokawa 101106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 102106813Ssimokawa if(sc->fc->ir[sub]->flag & FWXFERQ_OPEN){ 103106813Ssimokawa err = EBUSY; 104106813Ssimokawa return err; 105106813Ssimokawa } 106106813Ssimokawa if(sc->fc->it[sub]->flag & FWXFERQ_OPEN){ 107106813Ssimokawa err = EBUSY; 108106813Ssimokawa return err; 109106813Ssimokawa } 110106813Ssimokawa if(sc->fc->ir[sub]->flag & FWXFERQ_MODEMASK){ 111106813Ssimokawa err = EBUSY; 112106813Ssimokawa return err; 113106813Ssimokawa } 114106813Ssimokawa/* Default is per packet mode */ 115106813Ssimokawa sc->fc->ir[sub]->flag |= FWXFERQ_OPEN; 116106813Ssimokawa sc->fc->it[sub]->flag |= FWXFERQ_OPEN; 117106813Ssimokawa return err; 118106813Ssimokawa} 119106813Ssimokawa 120106813Ssimokawastatic int 121106813Ssimokawafw_close (dev_t dev, int flags, int fmt, fw_proc *td) 122106813Ssimokawa{ 123106813Ssimokawa struct firewire_softc *sc; 124106813Ssimokawa int unit = DEV2UNIT(dev); 125106813Ssimokawa int sub = DEV2DMACH(dev); 126106813Ssimokawa struct fw_xfer *xfer; 127106813Ssimokawa struct fw_bind *fwb; 128106813Ssimokawa int err = 0; 129106813Ssimokawa 130106813Ssimokawa if (DEV_FWMEM(dev)) 131106813Ssimokawa return fwmem_close(dev, flags, fmt, td); 132106813Ssimokawa 133106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 134106813Ssimokawa if(!(sc->fc->ir[sub]->flag & FWXFERQ_OPEN)){ 135106813Ssimokawa err = EINVAL; 136106813Ssimokawa return err; 137106813Ssimokawa } 138106813Ssimokawa sc->fc->ir[sub]->flag &= ~FWXFERQ_OPEN; 139106813Ssimokawa if(!(sc->fc->it[sub]->flag & FWXFERQ_OPEN)){ 140106813Ssimokawa err = EINVAL; 141106813Ssimokawa return err; 142106813Ssimokawa } 143106813Ssimokawa sc->fc->it[sub]->flag &= ~FWXFERQ_OPEN; 144106813Ssimokawa 145106813Ssimokawa if(sc->fc->ir[sub]->flag & FWXFERQ_RUNNING){ 146106813Ssimokawa sc->fc->irx_disable(sc->fc, sub); 147106813Ssimokawa } 148106813Ssimokawa if(sc->fc->it[sub]->flag & FWXFERQ_RUNNING){ 149106813Ssimokawa sc->fc->it[sub]->flag &= ~FWXFERQ_RUNNING; 150106813Ssimokawa sc->fc->itx_disable(sc->fc, sub); 151106813Ssimokawa } 152106813Ssimokawa if(sc->fc->ir[sub]->flag & FWXFERQ_EXTBUF){ 153113584Ssimokawa if (sc->fc->ir[sub]->buf != NULL) 154113584Ssimokawa fwdma_free_multiseg(sc->fc->ir[sub]->buf); 155106813Ssimokawa sc->fc->ir[sub]->buf = NULL; 156110195Ssimokawa free(sc->fc->ir[sub]->bulkxfer, M_FW); 157106813Ssimokawa sc->fc->ir[sub]->bulkxfer = NULL; 158106813Ssimokawa sc->fc->ir[sub]->flag &= ~FWXFERQ_EXTBUF; 159109379Ssimokawa sc->fc->ir[sub]->psize = PAGE_SIZE; 160106813Ssimokawa sc->fc->ir[sub]->maxq = FWMAXQUEUE; 161106813Ssimokawa } 162106813Ssimokawa if(sc->fc->it[sub]->flag & FWXFERQ_EXTBUF){ 163113584Ssimokawa if (sc->fc->it[sub]->buf != NULL) 164113584Ssimokawa fwdma_free_multiseg(sc->fc->it[sub]->buf); 165106813Ssimokawa sc->fc->it[sub]->buf = NULL; 166110195Ssimokawa free(sc->fc->it[sub]->bulkxfer, M_FW); 167106813Ssimokawa sc->fc->it[sub]->bulkxfer = NULL; 168106813Ssimokawa sc->fc->it[sub]->flag &= ~FWXFERQ_EXTBUF; 169109379Ssimokawa sc->fc->it[sub]->psize = 0; 170106813Ssimokawa sc->fc->it[sub]->maxq = FWMAXQUEUE; 171106813Ssimokawa } 172106813Ssimokawa for(xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q); 173106813Ssimokawa xfer != NULL; xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q)){ 174106813Ssimokawa sc->fc->ir[sub]->queued--; 175106813Ssimokawa STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->q, link); 176106813Ssimokawa 177106813Ssimokawa xfer->resp = 0; 178113584Ssimokawa fw_xfer_done(xfer); 179106813Ssimokawa } 180106813Ssimokawa for(fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds); fwb != NULL; 181106813Ssimokawa fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds)){ 182106813Ssimokawa STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 183106813Ssimokawa STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->binds, chlist); 184110195Ssimokawa free(fwb, M_FW); 185106813Ssimokawa } 186113584Ssimokawa sc->fc->ir[sub]->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 187113584Ssimokawa sc->fc->it[sub]->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 188106813Ssimokawa return err; 189106813Ssimokawa} 190106813Ssimokawa 191106813Ssimokawa/* 192106813Ssimokawa * read request. 193106813Ssimokawa */ 194106813Ssimokawastatic int 195106813Ssimokawafw_read (dev_t dev, struct uio *uio, int ioflag) 196106813Ssimokawa{ 197106813Ssimokawa struct firewire_softc *sc; 198106813Ssimokawa struct fw_xferq *ir; 199106813Ssimokawa struct fw_xfer *xfer; 200106813Ssimokawa int err = 0, s, slept = 0; 201106813Ssimokawa int unit = DEV2UNIT(dev); 202106813Ssimokawa int sub = DEV2DMACH(dev); 203106813Ssimokawa struct fw_pkt *fp; 204106813Ssimokawa 205106813Ssimokawa if (DEV_FWMEM(dev)) 206106813Ssimokawa return fwmem_read(dev, uio, ioflag); 207106813Ssimokawa 208106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 209106813Ssimokawa 210106813Ssimokawa ir = sc->fc->ir[sub]; 211106813Ssimokawa 212106813Ssimokawareadloop: 213106813Ssimokawa xfer = STAILQ_FIRST(&ir->q); 214113584Ssimokawa if (ir->stproc == NULL) { 215109988Ssimokawa /* iso bulkxfer */ 216106813Ssimokawa ir->stproc = STAILQ_FIRST(&ir->stvalid); 217109988Ssimokawa if (ir->stproc != NULL) { 218106813Ssimokawa s = splfw(); 219106813Ssimokawa STAILQ_REMOVE_HEAD(&ir->stvalid, link); 220106813Ssimokawa splx(s); 221106813Ssimokawa ir->queued = 0; 222106813Ssimokawa } 223106813Ssimokawa } 224109988Ssimokawa if (xfer == NULL && ir->stproc == NULL) { 225109988Ssimokawa /* no data avaliable */ 226109988Ssimokawa if (slept == 0) { 227106813Ssimokawa slept = 1; 228106813Ssimokawa ir->flag |= FWXFERQ_WAKEUP; 229111748Sdes err = tsleep(ir, FWPRI, "fw_read", hz); 230109988Ssimokawa ir->flag &= ~FWXFERQ_WAKEUP; 231109988Ssimokawa if (err == 0) 232109988Ssimokawa goto readloop; 233109988Ssimokawa } else if (slept == 1) 234106813Ssimokawa err = EIO; 235109988Ssimokawa return err; 236109988Ssimokawa } else if(xfer != NULL) { 237113584Ssimokawa /* per packet mode or FWACT_CH bind?*/ 238106813Ssimokawa s = splfw(); 239106813Ssimokawa ir->queued --; 240106813Ssimokawa STAILQ_REMOVE_HEAD(&ir->q, link); 241106813Ssimokawa splx(s); 242113584Ssimokawa fp = (struct fw_pkt *)xfer->recv.buf; 243106813Ssimokawa if(sc->fc->irx_post != NULL) 244106813Ssimokawa sc->fc->irx_post(sc->fc, fp->mode.ld); 245113584Ssimokawa err = uiomove(xfer->recv.buf, xfer->recv.len, uio); 246113584Ssimokawa /* XXX we should recycle this xfer */ 247106813Ssimokawa fw_xfer_free( xfer); 248109988Ssimokawa } else if(ir->stproc != NULL) { 249109988Ssimokawa /* iso bulkxfer */ 250113584Ssimokawa fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 251113584Ssimokawa ir->stproc->poffset + ir->queued); 252106813Ssimokawa if(sc->fc->irx_post != NULL) 253106813Ssimokawa sc->fc->irx_post(sc->fc, fp->mode.ld); 254113584Ssimokawa if(fp->mode.stream.len == 0){ 255106813Ssimokawa err = EIO; 256106813Ssimokawa return err; 257106813Ssimokawa } 258109988Ssimokawa err = uiomove((caddr_t)fp, 259113584Ssimokawa fp->mode.stream.len + sizeof(u_int32_t), uio); 260106813Ssimokawa ir->queued ++; 261106813Ssimokawa if(ir->queued >= ir->bnpacket){ 262106813Ssimokawa s = splfw(); 263106813Ssimokawa STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 264106813Ssimokawa splx(s); 265109890Ssimokawa sc->fc->irx_enable(sc->fc, sub); 266106813Ssimokawa ir->stproc = NULL; 267106813Ssimokawa } 268109988Ssimokawa if (uio->uio_resid >= ir->psize) { 269109988Ssimokawa slept = -1; 270109988Ssimokawa goto readloop; 271109988Ssimokawa } 272106813Ssimokawa } 273106813Ssimokawa return err; 274106813Ssimokawa} 275106813Ssimokawa 276106813Ssimokawastatic int 277106813Ssimokawafw_write (dev_t dev, struct uio *uio, int ioflag) 278106813Ssimokawa{ 279106813Ssimokawa int err = 0; 280106813Ssimokawa struct firewire_softc *sc; 281106813Ssimokawa int unit = DEV2UNIT(dev); 282106813Ssimokawa int sub = DEV2DMACH(dev); 283106813Ssimokawa int s, slept = 0; 284106813Ssimokawa struct fw_pkt *fp; 285106813Ssimokawa struct firewire_comm *fc; 286106813Ssimokawa struct fw_xferq *it; 287106813Ssimokawa 288106813Ssimokawa if (DEV_FWMEM(dev)) 289106813Ssimokawa return fwmem_write(dev, uio, ioflag); 290106813Ssimokawa 291106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 292106813Ssimokawa fc = sc->fc; 293106813Ssimokawa it = sc->fc->it[sub]; 294106813Ssimokawaisoloop: 295113802Ssimokawa if (it->stproc == NULL) { 296113802Ssimokawa it->stproc = STAILQ_FIRST(&it->stfree); 297113802Ssimokawa if (it->stproc != NULL) { 298106813Ssimokawa s = splfw(); 299113802Ssimokawa STAILQ_REMOVE_HEAD(&it->stfree, link); 300106813Ssimokawa splx(s); 301113802Ssimokawa it->queued = 0; 302113802Ssimokawa } else if (slept == 0) { 303113802Ssimokawa slept = 1; 304106813Ssimokawa err = sc->fc->itx_enable(sc->fc, sub); 305113802Ssimokawa if (err) 306113802Ssimokawa return err; 307113802Ssimokawa err = tsleep(it, FWPRI, "fw_write", hz); 308113802Ssimokawa if (err) 309113802Ssimokawa return err; 310109988Ssimokawa goto isoloop; 311113802Ssimokawa } else { 312113802Ssimokawa err = EIO; 313106813Ssimokawa return err; 314106813Ssimokawa } 315106813Ssimokawa } 316113802Ssimokawa fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 317113802Ssimokawa it->stproc->poffset + it->queued); 318113802Ssimokawa err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 319113802Ssimokawa err = uiomove((caddr_t)fp->mode.stream.payload, 320113802Ssimokawa fp->mode.stream.len, uio); 321113802Ssimokawa it->queued ++; 322113802Ssimokawa if (it->queued >= it->bnpacket) { 323113802Ssimokawa s = splfw(); 324113802Ssimokawa STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 325113802Ssimokawa splx(s); 326113802Ssimokawa it->stproc = NULL; 327113802Ssimokawa err = sc->fc->itx_enable(sc->fc, sub); 328113802Ssimokawa } 329113802Ssimokawa if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 330113802Ssimokawa slept = 0; 331113802Ssimokawa goto isoloop; 332113802Ssimokawa } 333113802Ssimokawa return err; 334106813Ssimokawa} 335106813Ssimokawa 336106813Ssimokawa/* 337106813Ssimokawa * ioctl support. 338106813Ssimokawa */ 339106813Ssimokawaint 340106813Ssimokawafw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 341106813Ssimokawa{ 342106813Ssimokawa struct firewire_softc *sc; 343106813Ssimokawa int unit = DEV2UNIT(dev); 344106813Ssimokawa int sub = DEV2DMACH(dev); 345113584Ssimokawa int s, i, len, err = 0; 346106813Ssimokawa struct fw_device *fwdev; 347106813Ssimokawa struct fw_bind *fwb; 348106813Ssimokawa struct fw_xferq *ir, *it; 349106813Ssimokawa struct fw_xfer *xfer; 350106813Ssimokawa struct fw_pkt *fp; 351109814Ssimokawa struct fw_devinfo *devinfo; 352117473Ssimokawa void *ptr; 353106813Ssimokawa 354106813Ssimokawa struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 355106813Ssimokawa struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 356106813Ssimokawa struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 357106813Ssimokawa struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 358106813Ssimokawa struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 359106813Ssimokawa struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 360106813Ssimokawa 361106813Ssimokawa if (DEV_FWMEM(dev)) 362106813Ssimokawa return fwmem_ioctl(dev, cmd, data, flag, td); 363106813Ssimokawa 364106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 365106813Ssimokawa if (!data) 366106813Ssimokawa return(EINVAL); 367106813Ssimokawa 368106813Ssimokawa switch (cmd) { 369106813Ssimokawa case FW_STSTREAM: 370106813Ssimokawa sc->fc->it[sub]->flag &= ~0xff; 371106813Ssimokawa sc->fc->it[sub]->flag |= (0x3f & ichreq->ch); 372106813Ssimokawa sc->fc->it[sub]->flag |= ((0x3 & ichreq->tag) << 6); 373106813Ssimokawa err = 0; 374106813Ssimokawa break; 375106813Ssimokawa case FW_GTSTREAM: 376106813Ssimokawa ichreq->ch = sc->fc->it[sub]->flag & 0x3f; 377106813Ssimokawa ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3; 378106813Ssimokawa err = 0; 379106813Ssimokawa break; 380106813Ssimokawa case FW_SRSTREAM: 381106813Ssimokawa sc->fc->ir[sub]->flag &= ~0xff; 382106813Ssimokawa sc->fc->ir[sub]->flag |= (0x3f & ichreq->ch); 383106813Ssimokawa sc->fc->ir[sub]->flag |= ((0x3 & ichreq->tag) << 6); 384106813Ssimokawa err = sc->fc->irx_enable(sc->fc, sub); 385106813Ssimokawa break; 386106813Ssimokawa case FW_GRSTREAM: 387106813Ssimokawa ichreq->ch = sc->fc->ir[sub]->flag & 0x3f; 388106813Ssimokawa ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3; 389106813Ssimokawa err = 0; 390106813Ssimokawa break; 391106813Ssimokawa case FW_SSTBUF: 392106813Ssimokawa ir = sc->fc->ir[sub]; 393106813Ssimokawa it = sc->fc->it[sub]; 394106813Ssimokawa 395106813Ssimokawa if(ir->flag & FWXFERQ_RUNNING || it->flag & FWXFERQ_RUNNING){ 396106813Ssimokawa return(EBUSY); 397106813Ssimokawa } 398106813Ssimokawa if((ir->flag & FWXFERQ_EXTBUF) || (it->flag & FWXFERQ_EXTBUF)){ 399106813Ssimokawa return(EBUSY); 400106813Ssimokawa } 401106813Ssimokawa if((ibufreq->rx.nchunk * 402106813Ssimokawa ibufreq->rx.psize * ibufreq->rx.npacket) + 403106813Ssimokawa (ibufreq->tx.nchunk * 404106813Ssimokawa ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){ 405106813Ssimokawa return(EINVAL); 406106813Ssimokawa } 407106813Ssimokawa ir->bulkxfer 408113584Ssimokawa = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_FW, M_WAITOK); 409106813Ssimokawa if(ir->bulkxfer == NULL){ 410106813Ssimokawa return(ENOMEM); 411106813Ssimokawa } 412106813Ssimokawa it->bulkxfer 413113584Ssimokawa = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_FW, M_WAITOK); 414106813Ssimokawa if(it->bulkxfer == NULL){ 415106813Ssimokawa return(ENOMEM); 416106813Ssimokawa } 417113584Ssimokawa if (ibufreq->rx.psize > 0) { 418113584Ssimokawa ibufreq->rx.psize = roundup2(ibufreq->rx.psize, 419113584Ssimokawa sizeof(u_int32_t)); 420113584Ssimokawa ir->buf = fwdma_malloc_multiseg( 421113584Ssimokawa sc->fc, sizeof(u_int32_t), 422113584Ssimokawa ibufreq->rx.psize, 423113584Ssimokawa ibufreq->rx.nchunk * ibufreq->rx.npacket, 424113584Ssimokawa BUS_DMA_WAITOK); 425113584Ssimokawa 426113584Ssimokawa if(ir->buf == NULL){ 427113584Ssimokawa free(ir->bulkxfer, M_FW); 428113584Ssimokawa free(it->bulkxfer, M_FW); 429113584Ssimokawa ir->bulkxfer = NULL; 430113584Ssimokawa it->bulkxfer = NULL; 431113584Ssimokawa it->buf = NULL; 432113584Ssimokawa return(ENOMEM); 433113584Ssimokawa } 434106813Ssimokawa } 435113584Ssimokawa if (ibufreq->tx.psize > 0) { 436113584Ssimokawa ibufreq->tx.psize = roundup2(ibufreq->tx.psize, 437113584Ssimokawa sizeof(u_int32_t)); 438113584Ssimokawa it->buf = fwdma_malloc_multiseg( 439113584Ssimokawa sc->fc, sizeof(u_int32_t), 440113584Ssimokawa ibufreq->tx.psize, 441113584Ssimokawa ibufreq->tx.nchunk * ibufreq->tx.npacket, 442113584Ssimokawa BUS_DMA_WAITOK); 443113584Ssimokawa 444113584Ssimokawa if(it->buf == NULL){ 445113584Ssimokawa free(ir->bulkxfer, M_FW); 446113584Ssimokawa free(it->bulkxfer, M_FW); 447113584Ssimokawa fwdma_free_multiseg(ir->buf); 448113584Ssimokawa ir->bulkxfer = NULL; 449113584Ssimokawa it->bulkxfer = NULL; 450113584Ssimokawa it->buf = NULL; 451113584Ssimokawa return(ENOMEM); 452113584Ssimokawa } 453106813Ssimokawa } 454106813Ssimokawa 455106813Ssimokawa ir->bnchunk = ibufreq->rx.nchunk; 456106813Ssimokawa ir->bnpacket = ibufreq->rx.npacket; 457106813Ssimokawa ir->psize = (ibufreq->rx.psize + 3) & ~3; 458106813Ssimokawa ir->queued = 0; 459106813Ssimokawa 460106813Ssimokawa it->bnchunk = ibufreq->tx.nchunk; 461106813Ssimokawa it->bnpacket = ibufreq->tx.npacket; 462106813Ssimokawa it->psize = (ibufreq->tx.psize + 3) & ~3; 463109890Ssimokawa it->queued = 0; 464109890Ssimokawa 465106813Ssimokawa STAILQ_INIT(&ir->stvalid); 466106813Ssimokawa STAILQ_INIT(&ir->stfree); 467109890Ssimokawa STAILQ_INIT(&ir->stdma); 468106813Ssimokawa ir->stproc = NULL; 469106813Ssimokawa 470106813Ssimokawa STAILQ_INIT(&it->stvalid); 471106813Ssimokawa STAILQ_INIT(&it->stfree); 472109890Ssimokawa STAILQ_INIT(&it->stdma); 473106813Ssimokawa it->stproc = NULL; 474106813Ssimokawa 475106813Ssimokawa for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){ 476113584Ssimokawa ir->bulkxfer[i].poffset = i * ir->bnpacket; 477113584Ssimokawa ir->bulkxfer[i].mbuf = NULL; 478106813Ssimokawa STAILQ_INSERT_TAIL(&ir->stfree, 479106813Ssimokawa &ir->bulkxfer[i], link); 480106813Ssimokawa } 481106813Ssimokawa for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){ 482113584Ssimokawa it->bulkxfer[i].poffset = i * it->bnpacket; 483113584Ssimokawa it->bulkxfer[i].mbuf = NULL; 484106813Ssimokawa STAILQ_INSERT_TAIL(&it->stfree, 485106813Ssimokawa &it->bulkxfer[i], link); 486106813Ssimokawa } 487106813Ssimokawa ir->flag &= ~FWXFERQ_MODEMASK; 488106813Ssimokawa ir->flag |= FWXFERQ_STREAM; 489106813Ssimokawa ir->flag |= FWXFERQ_EXTBUF; 490106813Ssimokawa 491106813Ssimokawa it->flag &= ~FWXFERQ_MODEMASK; 492106813Ssimokawa it->flag |= FWXFERQ_STREAM; 493106813Ssimokawa it->flag |= FWXFERQ_EXTBUF; 494106813Ssimokawa err = 0; 495106813Ssimokawa break; 496106813Ssimokawa case FW_GSTBUF: 497106813Ssimokawa ibufreq->rx.nchunk = sc->fc->ir[sub]->bnchunk; 498106813Ssimokawa ibufreq->rx.npacket = sc->fc->ir[sub]->bnpacket; 499106813Ssimokawa ibufreq->rx.psize = sc->fc->ir[sub]->psize; 500106813Ssimokawa 501106813Ssimokawa ibufreq->tx.nchunk = sc->fc->it[sub]->bnchunk; 502106813Ssimokawa ibufreq->tx.npacket = sc->fc->it[sub]->bnpacket; 503106813Ssimokawa ibufreq->tx.psize = sc->fc->it[sub]->psize; 504106813Ssimokawa break; 505106813Ssimokawa case FW_ASYREQ: 506113584Ssimokawa xfer = fw_xfer_alloc_buf(M_FWXFER, asyreq->req.len, 507113584Ssimokawa PAGE_SIZE /* XXX */); 508106813Ssimokawa if(xfer == NULL){ 509106813Ssimokawa err = ENOMEM; 510106813Ssimokawa return err; 511106813Ssimokawa } 512106813Ssimokawa fp = &asyreq->pkt; 513106813Ssimokawa switch (asyreq->req.type) { 514106813Ssimokawa case FWASREQNODE: 515113584Ssimokawa xfer->dst = fp->mode.hdr.dst; 516106813Ssimokawa break; 517106813Ssimokawa case FWASREQEUI: 518110072Ssimokawa fwdev = fw_noderesolve_eui64(sc->fc, 519110582Ssimokawa &asyreq->req.dst.eui); 520106813Ssimokawa if (fwdev == NULL) { 521108782Ssimokawa device_printf(sc->fc->bdev, 522108782Ssimokawa "cannot find node\n"); 523106813Ssimokawa err = EINVAL; 524106813Ssimokawa goto error; 525106813Ssimokawa } 526113832Ssimokawa xfer->dst = FWLOCALBUS | fwdev->dst; 527113832Ssimokawa fp->mode.hdr.dst = xfer->dst; 528106813Ssimokawa break; 529106813Ssimokawa case FWASRESTL: 530106813Ssimokawa /* XXX what's this? */ 531106813Ssimokawa break; 532106813Ssimokawa case FWASREQSTREAM: 533106813Ssimokawa /* nothing to do */ 534106813Ssimokawa break; 535106813Ssimokawa } 536106813Ssimokawa xfer->spd = asyreq->req.sped; 537106813Ssimokawa bcopy(fp, xfer->send.buf, xfer->send.len); 538106813Ssimokawa xfer->act.hand = fw_asy_callback; 539106813Ssimokawa err = fw_asyreq(sc->fc, sub, xfer); 540106813Ssimokawa if(err){ 541106813Ssimokawa fw_xfer_free( xfer); 542106813Ssimokawa return err; 543106813Ssimokawa } 544111748Sdes err = tsleep(xfer, FWPRI, "asyreq", hz); 545106813Ssimokawa if(err == 0){ 546106813Ssimokawa if(asyreq->req.len >= xfer->recv.len){ 547106813Ssimokawa asyreq->req.len = xfer->recv.len; 548106813Ssimokawa }else{ 549106813Ssimokawa err = EINVAL; 550106813Ssimokawa } 551113584Ssimokawa bcopy(xfer->recv.buf, fp, asyreq->req.len); 552106813Ssimokawa } 553106813Ssimokawaerror: 554106813Ssimokawa fw_xfer_free( xfer); 555106813Ssimokawa break; 556106813Ssimokawa case FW_IBUSRST: 557106813Ssimokawa sc->fc->ibr(sc->fc); 558106813Ssimokawa break; 559106813Ssimokawa case FW_CBINDADDR: 560106813Ssimokawa fwb = fw_bindlookup(sc->fc, 561106813Ssimokawa bindreq->start.hi, bindreq->start.lo); 562106813Ssimokawa if(fwb == NULL){ 563106813Ssimokawa err = EINVAL; 564106813Ssimokawa break; 565106813Ssimokawa } 566106813Ssimokawa STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 567106813Ssimokawa STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist); 568110195Ssimokawa free(fwb, M_FW); 569106813Ssimokawa break; 570106813Ssimokawa case FW_SBINDADDR: 571106813Ssimokawa if(bindreq->len <= 0 ){ 572106813Ssimokawa err = EINVAL; 573106813Ssimokawa break; 574106813Ssimokawa } 575106813Ssimokawa if(bindreq->start.hi > 0xffff ){ 576106813Ssimokawa err = EINVAL; 577106813Ssimokawa break; 578106813Ssimokawa } 579110195Ssimokawa fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT); 580106813Ssimokawa if(fwb == NULL){ 581106813Ssimokawa err = ENOMEM; 582106813Ssimokawa break; 583106813Ssimokawa } 584106813Ssimokawa fwb->start_hi = bindreq->start.hi; 585106813Ssimokawa fwb->start_lo = bindreq->start.lo; 586106813Ssimokawa fwb->addrlen = bindreq->len; 587113584Ssimokawa fwb->sub = sub; 588113584Ssimokawa fwb->act_type = FWACT_CH; 589106813Ssimokawa 590110269Ssimokawa xfer = fw_xfer_alloc(M_FWXFER); 591106813Ssimokawa if(xfer == NULL){ 592106813Ssimokawa err = ENOMEM; 593106813Ssimokawa return err; 594106813Ssimokawa } 595106813Ssimokawa xfer->fc = sc->fc; 596106813Ssimokawa 597113584Ssimokawa s = splfw(); 598113584Ssimokawa /* XXX broken. need multiple xfer */ 599113584Ssimokawa STAILQ_INIT(&fwb->xferlist); 600113584Ssimokawa STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 601113584Ssimokawa splx(s); 602106813Ssimokawa err = fw_bindadd(sc->fc, fwb); 603106813Ssimokawa break; 604106813Ssimokawa case FW_GDEVLST: 605109814Ssimokawa i = len = 1; 606109814Ssimokawa /* myself */ 607109814Ssimokawa devinfo = &fwdevlst->dev[0]; 608109814Ssimokawa devinfo->dst = sc->fc->nodeid; 609109814Ssimokawa devinfo->status = 0; /* XXX */ 610109814Ssimokawa devinfo->eui.hi = sc->fc->eui.hi; 611109814Ssimokawa devinfo->eui.lo = sc->fc->eui.lo; 612110193Ssimokawa STAILQ_FOREACH(fwdev, &sc->fc->devices, link) { 613109814Ssimokawa if(len < FW_MAX_DEVLST){ 614109814Ssimokawa devinfo = &fwdevlst->dev[len++]; 615109814Ssimokawa devinfo->dst = fwdev->dst; 616109814Ssimokawa devinfo->status = 617109814Ssimokawa (fwdev->status == FWDEVINVAL)?0:1; 618109814Ssimokawa devinfo->eui.hi = fwdev->eui.hi; 619109814Ssimokawa devinfo->eui.lo = fwdev->eui.lo; 620106813Ssimokawa } 621106813Ssimokawa i++; 622106813Ssimokawa } 623106813Ssimokawa fwdevlst->n = i; 624109814Ssimokawa fwdevlst->info_len = len; 625106813Ssimokawa break; 626106813Ssimokawa case FW_GTPMAP: 627106813Ssimokawa bcopy(sc->fc->topology_map, data, 628106813Ssimokawa (sc->fc->topology_map->crc_len + 1) * 4); 629106813Ssimokawa break; 630106813Ssimokawa case FW_GCROM: 631110193Ssimokawa STAILQ_FOREACH(fwdev, &sc->fc->devices, link) 632110193Ssimokawa if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 633106813Ssimokawa break; 634106813Ssimokawa if (fwdev == NULL) { 635117473Ssimokawa if (!FW_EUI64_EQUAL(sc->fc->eui, crom_buf->eui)) { 636117473Ssimokawa err = FWNODE_INVAL; 637117473Ssimokawa break; 638117473Ssimokawa } 639117473Ssimokawa /* myself */ 640117473Ssimokawa ptr = malloc(CROMSIZE, M_FW, M_WAITOK); 641117473Ssimokawa len = CROMSIZE; 642117473Ssimokawa for (i = 0; i < CROMSIZE/4; i++) 643117473Ssimokawa ((u_int32_t *)ptr)[i] 644117473Ssimokawa = ntohl(sc->fc->config_rom[i]); 645117473Ssimokawa } else { 646117473Ssimokawa /* found */ 647117473Ssimokawa ptr = (void *)&fwdev->csrrom[0]; 648117473Ssimokawa if (fwdev->rommax < CSRROMOFF) 649117473Ssimokawa len = 0; 650117473Ssimokawa else 651117473Ssimokawa len = fwdev->rommax - CSRROMOFF + 4; 652106813Ssimokawa } 653106813Ssimokawa if (crom_buf->len < len) 654106813Ssimokawa len = crom_buf->len; 655106813Ssimokawa else 656106813Ssimokawa crom_buf->len = len; 657117473Ssimokawa err = copyout(ptr, crom_buf->ptr, len); 658117473Ssimokawa if (fwdev == NULL) 659117473Ssimokawa /* myself */ 660117473Ssimokawa free(ptr, M_FW); 661106813Ssimokawa break; 662106813Ssimokawa default: 663106813Ssimokawa sc->fc->ioctl (dev, cmd, data, flag, td); 664106813Ssimokawa break; 665106813Ssimokawa } 666106813Ssimokawa return err; 667106813Ssimokawa} 668106813Ssimokawaint 669106813Ssimokawafw_poll(dev_t dev, int events, fw_proc *td) 670106813Ssimokawa{ 671106813Ssimokawa int revents; 672106813Ssimokawa int tmp; 673106813Ssimokawa int unit = DEV2UNIT(dev); 674106813Ssimokawa int sub = DEV2DMACH(dev); 675106813Ssimokawa struct firewire_softc *sc; 676106813Ssimokawa 677106813Ssimokawa if (DEV_FWMEM(dev)) 678106813Ssimokawa return fwmem_poll(dev, events, td); 679106813Ssimokawa 680106813Ssimokawa sc = devclass_get_softc(firewire_devclass, unit); 681106813Ssimokawa revents = 0; 682106813Ssimokawa tmp = POLLIN | POLLRDNORM; 683106813Ssimokawa if (events & tmp) { 684106813Ssimokawa if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL) 685106813Ssimokawa revents |= tmp; 686106813Ssimokawa else 687106813Ssimokawa selrecord(td, &sc->fc->ir[sub]->rsel); 688106813Ssimokawa } 689106813Ssimokawa tmp = POLLOUT | POLLWRNORM; 690106813Ssimokawa if (events & tmp) { 691106813Ssimokawa /* XXX should be fixed */ 692106813Ssimokawa revents |= tmp; 693106813Ssimokawa } 694106813Ssimokawa 695106813Ssimokawa return revents; 696106813Ssimokawa} 697106813Ssimokawa 698106813Ssimokawastatic int 699113584Ssimokawa#if __FreeBSD_version < 500102 700111615Ssimokawafw_mmap (dev_t dev, vm_offset_t offset, int nproto) 701111615Ssimokawa#else 702113584Ssimokawafw_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto) 703111615Ssimokawa#endif 704106813Ssimokawa{ 705106813Ssimokawa struct firewire_softc *fc; 706106813Ssimokawa int unit = DEV2UNIT(dev); 707106813Ssimokawa 708106813Ssimokawa if (DEV_FWMEM(dev)) 709113584Ssimokawa#if __FreeBSD_version < 500102 710111615Ssimokawa return fwmem_mmap(dev, offset, nproto); 711111615Ssimokawa#else 712111462Smux return fwmem_mmap(dev, offset, paddr, nproto); 713111615Ssimokawa#endif 714106813Ssimokawa 715106813Ssimokawa fc = devclass_get_softc(firewire_devclass, unit); 716106813Ssimokawa 717106813Ssimokawa return EINVAL; 718106813Ssimokawa} 719