fwdev.c revision 144389
1139749Simp/*- 28471Sache * Copyright (c) 2003 Hidetoshi Shimokawa 38471Sache * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 4367457Sdim * All rights reserved. 5105806Sjhb * 68471Sache * Redistribution and use in source and binary forms, with or without 78471Sache * modification, are permitted provided that the following conditions 88471Sache * are met: 98471Sache * 1. Redistributions of source code must retain the above copyright 108471Sache * notice, this list of conditions and the following disclaimer. 118471Sache * 2. Redistributions in binary form must reproduce the above copyright 128471Sache * notice, this list of conditions and the following disclaimer in the 138471Sache * documentation and/or other materials provided with the distribution. 148471Sache * 3. All advertising materials mentioning features or use of this software 158471Sache * must display the acknowledgement as bellow: 168471Sache * 178471Sache * This product includes software developed by K. Kobayashi and H. Shimokawa 188471Sache * 198471Sache * 4. The name of the author may not be used to endorse or promote products 208471Sache * derived from this software without specific prior written permission. 218471Sache * 228471Sache * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 238471Sache * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 248471Sache * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 258471Sache * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 268471Sache * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2751654Sphk * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2851654Sphk * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 298471Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 308471Sache * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 318471Sache * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 328471Sache * POSSIBILITY OF SUCH DAMAGE. 338471Sache * 348471Sache * $FreeBSD: head/sys/dev/firewire/fwdev.c 144389 2005-03-31 12:19:44Z phk $ 358471Sache * 369232Sache */ 378471Sache 38111899Sdas#include <sys/param.h> 39111899Sdas#include <sys/systm.h> 408471Sache#include <sys/types.h> 418471Sache#include <sys/mbuf.h> 42105806Sjhb#if defined(__DragonFly__) || __FreeBSD_version < 500000 438471Sache#include <sys/buf.h> 4424131Sbde#else 4538246Sbde#include <sys/bio.h> 46105806Sjhb#endif 47105806Sjhb 48129879Sphk#include <sys/kernel.h> 49131096Sphk#include <sys/malloc.h> 50105806Sjhb#include <sys/conf.h> 51105806Sjhb#include <sys/poll.h> 52105806Sjhb 53105806Sjhb#include <sys/bus.h> 5466824Sbde#include <sys/ctype.h> 55105806Sjhb#include <machine/bus.h> 56105806Sjhb 57105806Sjhb#include <sys/ioccom.h> 588471Sache 59105806Sjhb#ifdef __DragonFly__ 608471Sache#include "firewire.h" 61105806Sjhb#include "firewirereg.h" 62105806Sjhb#include "fwdma.h" 638471Sache#include "fwmem.h" 64105806Sjhb#include "iec68113.h" 658471Sache#else 66105806Sjhb#include <dev/firewire/firewire.h> 67105806Sjhb#include <dev/firewire/firewirereg.h> 68105806Sjhb#include <dev/firewire/fwdma.h> 69105806Sjhb#include <dev/firewire/fwmem.h> 708471Sache#include <dev/firewire/iec68113.h> 719232Sache#endif 729232Sache 739232Sache#define FWNODE_INVAL 0xffff 748471Sache 758471Sachestatic d_open_t fw_open; 768471Sachestatic d_close_t fw_close; 778471Sachestatic d_ioctl_t fw_ioctl; 788471Sachestatic d_poll_t fw_poll; 798471Sachestatic d_read_t fw_read; /* for Isochronous packet */ 80105806Sjhbstatic d_write_t fw_write; 81105806Sjhbstatic d_mmap_t fw_mmap; 82105806Sjhbstatic d_strategy_t fw_strategy; 83105806Sjhb 84105806Sjhbstruct cdevsw firewire_cdevsw = { 85105806Sjhb#ifdef __DragonFly__ 86105806Sjhb#define CDEV_MAJOR 127 87105806Sjhb "fw", CDEV_MAJOR, D_MEM, NULL, 0, 88105806Sjhb fw_open, fw_close, fw_read, fw_write, fw_ioctl, 89105806Sjhb fw_poll, fw_mmap, fw_strategy, nodump, nopsize, 90136210Sphk#elif __FreeBSD_version >= 500104 91105806Sjhb .d_version = D_VERSION, 92105806Sjhb .d_open = fw_open, 93105806Sjhb .d_close = fw_close, 94105806Sjhb .d_read = fw_read, 95105806Sjhb .d_write = fw_write, 96105806Sjhb .d_ioctl = fw_ioctl, 97105806Sjhb .d_poll = fw_poll, 98105806Sjhb .d_mmap = fw_mmap, 99105806Sjhb .d_strategy = fw_strategy, 1008471Sache .d_name = "fw", 101105806Sjhb .d_flags = D_MEM | D_NEEDGIANT 102105806Sjhb#else 103105806Sjhb#define CDEV_MAJOR 127 104105806Sjhb fw_open, fw_close, fw_read, fw_write, fw_ioctl, 105105806Sjhb fw_poll, fw_mmap, fw_strategy, "fw", CDEV_MAJOR, 106105806Sjhb nodump, nopsize, D_MEM, -1 107105806Sjhb#endif 108105806Sjhb}; 109105806Sjhb 110105806Sjhbstruct fw_drv1 { 111105806Sjhb struct fw_xferq *ir; 112105806Sjhb struct fw_xferq *it; 113105806Sjhb struct fw_isobufreq bufreq; 114105806Sjhb}; 1158471Sache 1168471Sachestatic int 117105806Sjhbfwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q, 118136210Sphk struct fw_bufspec *b) 119131373Sphk{ 120105806Sjhb int i; 121105806Sjhb 122105806Sjhb if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF)) 123105806Sjhb return(EBUSY); 124105806Sjhb 125131096Sphk q->bulkxfer = (struct fw_bulkxfer *) malloc( 126105806Sjhb sizeof(struct fw_bulkxfer) * b->nchunk, 127105806Sjhb M_FW, M_WAITOK); 128105806Sjhb if (q->bulkxfer == NULL) 129105806Sjhb return(ENOMEM); 130105806Sjhb 131105806Sjhb b->psize = roundup2(b->psize, sizeof(uint32_t)); 132105806Sjhb q->buf = fwdma_malloc_multiseg(fc, sizeof(uint32_t), 133105806Sjhb b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK); 134105806Sjhb 135105806Sjhb if (q->buf == NULL) { 136105806Sjhb free(q->bulkxfer, M_FW); 1378471Sache q->bulkxfer = NULL; 1388471Sache return(ENOMEM); 1399232Sache } 1409232Sache q->bnchunk = b->nchunk; 1419232Sache q->bnpacket = b->npacket; 1429232Sache q->psize = (b->psize + 3) & ~3; 1439232Sache q->queued = 0; 1449232Sache 1459232Sache STAILQ_INIT(&q->stvalid); 1469232Sache STAILQ_INIT(&q->stfree); 1479232Sache STAILQ_INIT(&q->stdma); 1489232Sache q->stproc = NULL; 1499232Sache 1509232Sache for(i = 0 ; i < q->bnchunk; i++){ 1518471Sache q->bulkxfer[i].poffset = i * q->bnpacket; 1528471Sache q->bulkxfer[i].mbuf = NULL; 1538471Sache STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link); 1548471Sache } 1558471Sache 1568471Sache q->flag &= ~FWXFERQ_MODEMASK; 1578471Sache q->flag |= FWXFERQ_STREAM; 1588471Sache q->flag |= FWXFERQ_EXTBUF; 1598471Sache 1608471Sache return (0); 1618471Sache} 162105806Sjhb 163105806Sjhbstatic int 164105806Sjhbfwdev_freebuf(struct fw_xferq *q) 165105806Sjhb{ 166105806Sjhb if (q->flag & FWXFERQ_EXTBUF) { 16767551Sjhb if (q->buf != NULL) 1688471Sache fwdma_free_multiseg(q->buf); 1698471Sache q->buf = NULL; 17012724Sphk free(q->bulkxfer, M_FW); 171105806Sjhb q->bulkxfer = NULL; 1728471Sache q->flag &= ~FWXFERQ_EXTBUF; 173105806Sjhb q->psize = 0; 174105806Sjhb q->maxq = FWMAXQUEUE; 1758471Sache } 176105806Sjhb return (0); 177105806Sjhb} 178105806Sjhb 179105806Sjhb 180105806Sjhbstatic int 1819232Sachefw_open (struct cdev *dev, int flags, int fmt, fw_proc *td) 182105806Sjhb{ 183105806Sjhb int err = 0; 184105806Sjhb 185105806Sjhb if (DEV_FWMEM(dev)) 186105806Sjhb return fwmem_open(dev, flags, fmt, td); 187105806Sjhb 188105806Sjhb if (dev->si_drv1 != NULL) 189298307Spfg return (EBUSY); 190105806Sjhb 191105806Sjhb#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 192105806Sjhb if ((dev->si_flags & SI_NAMED) == 0) { 193105806Sjhb int unit = DEV2UNIT(dev); 194105806Sjhb int sub = DEV2SUB(dev); 195105806Sjhb 196105806Sjhb make_dev(&firewire_cdevsw, minor(dev), 197105806Sjhb UID_ROOT, GID_OPERATOR, 0660, 198105806Sjhb "fw%d.%d", unit, sub); 199105806Sjhb } 200105806Sjhb#endif 201105806Sjhb 202105806Sjhb dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); 203105806Sjhb 204105806Sjhb return err; 2058471Sache} 2068471Sache 20712724Sphkstatic int 208105806Sjhbfw_close (struct cdev *dev, int flags, int fmt, fw_proc *td) 2098471Sache{ 210105806Sjhb struct firewire_softc *sc; 211105806Sjhb struct firewire_comm *fc; 212105806Sjhb struct fw_drv1 *d; 213105806Sjhb int unit = DEV2UNIT(dev); 214105806Sjhb struct fw_xfer *xfer; 2158471Sache struct fw_bind *fwb; 216105806Sjhb int err = 0; 217105806Sjhb 21840565Sbde if (DEV_FWMEM(dev)) 219105806Sjhb return fwmem_close(dev, flags, fmt, td); 220105806Sjhb 221105806Sjhb sc = devclass_get_softc(firewire_devclass, unit); 222105806Sjhb fc = sc->fc; 223105806Sjhb d = (struct fw_drv1 *)dev->si_drv1; 224105806Sjhb 225105806Sjhb if (d->ir != NULL) { 226105806Sjhb struct fw_xferq *ir = d->ir; 227105806Sjhb 228105806Sjhb if ((ir->flag & FWXFERQ_OPEN) == 0) 229105806Sjhb return (EINVAL); 230105806Sjhb if (ir->flag & FWXFERQ_RUNNING) { 231105806Sjhb ir->flag &= ~FWXFERQ_RUNNING; 232105806Sjhb fc->irx_disable(fc, ir->dmach); 233105806Sjhb } 234105806Sjhb /* free extbuf */ 235105806Sjhb fwdev_freebuf(ir); 236105806Sjhb /* drain receiving buffer */ 237105806Sjhb for (xfer = STAILQ_FIRST(&ir->q); 238105806Sjhb xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) { 239105806Sjhb ir->queued --; 240105806Sjhb STAILQ_REMOVE_HEAD(&ir->q, link); 241105806Sjhb 242105806Sjhb xfer->resp = 0; 243105806Sjhb fw_xfer_done(xfer); 244105806Sjhb } 245296137Sjhibbits /* remove binding */ 246296137Sjhibbits for (fwb = STAILQ_FIRST(&ir->binds); fwb != NULL; 247105806Sjhb fwb = STAILQ_FIRST(&ir->binds)) { 248105806Sjhb STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist); 249105806Sjhb STAILQ_REMOVE_HEAD(&ir->binds, chlist); 250105806Sjhb free(fwb, M_FW); 251105806Sjhb } 252105806Sjhb ir->flag &= ~(FWXFERQ_OPEN | 253105806Sjhb FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 254105806Sjhb d->ir = NULL; 255105806Sjhb 256105806Sjhb } 257105806Sjhb if (d->it != NULL) { 258105806Sjhb struct fw_xferq *it = d->it; 259105806Sjhb 2608471Sache if ((it->flag & FWXFERQ_OPEN) == 0) 261127135Snjl return (EINVAL); 262127135Snjl if (it->flag & FWXFERQ_RUNNING) { 263105806Sjhb it->flag &= ~FWXFERQ_RUNNING; 264105806Sjhb fc->itx_disable(fc, it->dmach); 265105806Sjhb } 266105806Sjhb /* free extbuf */ 267105806Sjhb fwdev_freebuf(it); 268105806Sjhb it->flag &= ~(FWXFERQ_OPEN | 269105806Sjhb FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 270105806Sjhb d->it = NULL; 271105806Sjhb } 272105806Sjhb free(dev->si_drv1, M_FW); 273105806Sjhb dev->si_drv1 = NULL; 274105806Sjhb 275105806Sjhb return err; 276105806Sjhb} 277105806Sjhb 278105806Sjhb/* 279105806Sjhb * read request. 280105806Sjhb */ 281105806Sjhbstatic int 282105806Sjhbfw_read (struct cdev *dev, struct uio *uio, int ioflag) 283105806Sjhb{ 284105806Sjhb struct firewire_softc *sc; 285105806Sjhb struct fw_xferq *ir; 286105806Sjhb struct fw_xfer *xfer; 287105806Sjhb int err = 0, s, slept = 0; 2888471Sache int unit = DEV2UNIT(dev); 289105806Sjhb struct fw_pkt *fp; 2908471Sache 2918471Sache if (DEV_FWMEM(dev)) 2928471Sache return physio(dev, uio, ioflag); 2938471Sache 2948471Sache sc = devclass_get_softc(firewire_devclass, unit); 295105806Sjhb 296136210Sphk ir = ((struct fw_drv1 *)dev->si_drv1)->ir; 297136210Sphk if (ir == NULL || ir->buf == NULL) 298136210Sphk return (EIO); 299136210Sphk 300136210Sphkreadloop: 301136210Sphk xfer = STAILQ_FIRST(&ir->q); 302136210Sphk if (ir->stproc == NULL) { 303136210Sphk /* iso bulkxfer */ 304151383Sphk ir->stproc = STAILQ_FIRST(&ir->stvalid); 3058471Sache if (ir->stproc != NULL) { 306105806Sjhb s = splfw(); 307166901Spiso STAILQ_REMOVE_HEAD(&ir->stvalid, link); 308166901Spiso splx(s); 309105806Sjhb ir->queued = 0; 310105806Sjhb } 311105806Sjhb } 3128471Sache if (xfer == NULL && ir->stproc == NULL) { 313105806Sjhb /* no data avaliable */ 314151700Sjhb if (slept == 0) { 315105806Sjhb slept = 1; 316105806Sjhb ir->flag |= FWXFERQ_WAKEUP; 317105806Sjhb err = tsleep(ir, FWPRI, "fw_read", hz); 318105806Sjhb ir->flag &= ~FWXFERQ_WAKEUP; 319105806Sjhb if (err == 0) 320105806Sjhb goto readloop; 3218471Sache } else if (slept == 1) 3228471Sache err = EIO; 323105806Sjhb return err; 324105806Sjhb } else if(xfer != NULL) { 325105806Sjhb#if 0 /* XXX broken */ 326105806Sjhb /* per packet mode or FWACT_CH bind?*/ 327105806Sjhb s = splfw(); 328131981Sphk ir->queued --; 329105806Sjhb STAILQ_REMOVE_HEAD(&ir->q, link); 330105806Sjhb splx(s); 331105806Sjhb fp = &xfer->recv.hdr; 332105806Sjhb if (sc->fc->irx_post != NULL) 333136210Sphk sc->fc->irx_post(sc->fc, fp->mode.ld); 334136210Sphk err = uiomove((void *)fp, 1 /* XXX header size */, uio); 335105806Sjhb /* XXX copy payload too */ 336105806Sjhb /* XXX we should recycle this xfer */ 337105806Sjhb#endif 338105806Sjhb fw_xfer_free( xfer); 339151700Sjhb } else if(ir->stproc != NULL) { 340105806Sjhb /* iso bulkxfer */ 341105806Sjhb fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 342105806Sjhb ir->stproc->poffset + ir->queued); 343105806Sjhb if(sc->fc->irx_post != NULL) 344105806Sjhb sc->fc->irx_post(sc->fc, fp->mode.ld); 34540565Sbde if(fp->mode.stream.len == 0){ 346105806Sjhb err = EIO; 3478471Sache return err; 348105806Sjhb } 349105806Sjhb err = uiomove((caddr_t)fp, 3508471Sache fp->mode.stream.len + sizeof(uint32_t), uio); 351105806Sjhb ir->queued ++; 352105806Sjhb if(ir->queued >= ir->bnpacket){ 353105806Sjhb s = splfw(); 354105806Sjhb STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 355105806Sjhb splx(s); 3569232Sache sc->fc->irx_enable(sc->fc, ir->dmach); 357105806Sjhb ir->stproc = NULL; 358105806Sjhb } 359105806Sjhb if (uio->uio_resid >= ir->psize) { 360105806Sjhb slept = -1; 361105806Sjhb goto readloop; 362105806Sjhb } 363105806Sjhb } 3648471Sache return err; 365105806Sjhb} 366105806Sjhb 367105806Sjhbstatic int 368105806Sjhbfw_write (struct cdev *dev, struct uio *uio, int ioflag) 369105806Sjhb{ 370105806Sjhb int err = 0; 371105806Sjhb struct firewire_softc *sc; 372105806Sjhb int unit = DEV2UNIT(dev); 373105806Sjhb int s, slept = 0; 3748471Sache struct fw_pkt *fp; 375105806Sjhb struct firewire_comm *fc; 376105806Sjhb struct fw_xferq *it; 3779232Sache 378105806Sjhb if (DEV_FWMEM(dev)) 379105806Sjhb return physio(dev, uio, ioflag); 3809232Sache 3819232Sache sc = devclass_get_softc(firewire_devclass, unit); 3829232Sache fc = sc->fc; 3839232Sache it = ((struct fw_drv1 *)dev->si_drv1)->it; 3849232Sache if (it == NULL || it->buf == NULL) 385105806Sjhb return (EIO); 3869232Sacheisoloop: 3879232Sache if (it->stproc == NULL) { 3889232Sache it->stproc = STAILQ_FIRST(&it->stfree); 3899232Sache if (it->stproc != NULL) { 3908471Sache s = splfw(); 3919232Sache STAILQ_REMOVE_HEAD(&it->stfree, link); 392105806Sjhb splx(s); 393105806Sjhb it->queued = 0; 394105806Sjhb } else if (slept == 0) { 395105806Sjhb slept = 1; 3969232Sache err = sc->fc->itx_enable(sc->fc, it->dmach); 3978471Sache if (err) 3989232Sache return err; 399105806Sjhb err = tsleep(it, FWPRI, "fw_write", hz); 4009232Sache if (err) 4019232Sache return err; 402105806Sjhb goto isoloop; 403105806Sjhb } else { 4049232Sache err = EIO; 4059232Sache return err; 406105806Sjhb } 407105806Sjhb } 408136210Sphk fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 4099232Sache it->stproc->poffset + it->queued); 4109232Sache err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 4119232Sache err = uiomove((caddr_t)fp->mode.stream.payload, 4129232Sache fp->mode.stream.len, uio); 4139232Sache it->queued ++; 4149232Sache if (it->queued >= it->bnpacket) { 4159232Sache s = splfw(); 4169232Sache STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 4179232Sache splx(s); 418105806Sjhb it->stproc = NULL; 4199232Sache err = sc->fc->itx_enable(sc->fc, it->dmach); 4209232Sache } 421105806Sjhb if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 4229232Sache slept = 0; 4239232Sache goto isoloop; 424105806Sjhb } 4259232Sache return err; 4268471Sache} 4279232Sache/* 4289232Sache * ioctl support. 4299232Sache */ 4309232Sacheint 4319232Sachefw_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 4329232Sache{ 4339232Sache struct firewire_softc *sc; 4349232Sache struct firewire_comm *fc; 435105806Sjhb struct fw_drv1 *d; 4369232Sache int unit = DEV2UNIT(dev); 4378471Sache int s, i, len, err = 0; 4389232Sache struct fw_device *fwdev; 4399232Sache struct fw_bind *fwb; 4409232Sache struct fw_xferq *ir, *it; 4419232Sache struct fw_xfer *xfer; 442105806Sjhb struct fw_pkt *fp; 4439232Sache struct fw_devinfo *devinfo; 4449232Sache void *ptr; 4459232Sache 446105806Sjhb struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 447136210Sphk struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 448105806Sjhb struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 4498471Sache struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 4509232Sache struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 4519232Sache struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 4529232Sache 453105806Sjhb if (DEV_FWMEM(dev)) 4549232Sache return fwmem_ioctl(dev, cmd, data, flag, td); 4559232Sache 4569232Sache if (!data) 4579232Sache return(EINVAL); 4589232Sache 459105806Sjhb sc = devclass_get_softc(firewire_devclass, unit); 4609232Sache fc = sc->fc; 461105806Sjhb d = (struct fw_drv1 *)dev->si_drv1; 4629232Sache ir = d->ir; 4639232Sache it = d->it; 4649232Sache 4659232Sache switch (cmd) { 4669232Sache case FW_STSTREAM: 4679232Sache if (it == NULL) { 46846704Speter for (i = 0; i < fc->nisodma; i ++) { 469136210Sphk it = fc->it[i]; 4709232Sache if ((it->flag & FWXFERQ_OPEN) == 0) 471136210Sphk break; 4729232Sache } 4739232Sache if (i >= fc->nisodma) { 4749232Sache err = EBUSY; 47546704Speter break; 476136210Sphk } 4779232Sache err = fwdev_allocbuf(fc, it, &d->bufreq.tx); 478136210Sphk if (err) 479105806Sjhb break; 4809232Sache it->flag |= FWXFERQ_OPEN; 4819232Sache } 4829232Sache it->flag &= ~0xff; 483105806Sjhb it->flag |= (0x3f & ichreq->ch); 4849232Sache it->flag |= ((0x3 & ichreq->tag) << 6); 4859232Sache d->it = it; 4868471Sache break; 4879232Sache case FW_GTSTREAM: 4889232Sache if (it != NULL) { 4899232Sache ichreq->ch = it->flag & 0x3f; 4909232Sache ichreq->tag = it->flag >> 2 & 0x3; 4919232Sache } else 4929232Sache err = EINVAL; 4939232Sache break; 494105806Sjhb case FW_SRSTREAM: 4959232Sache if (ir == NULL) { 4969232Sache for (i = 0; i < fc->nisodma; i ++) { 4979232Sache ir = fc->ir[i]; 4989232Sache if ((ir->flag & FWXFERQ_OPEN) == 0) 499105806Sjhb break; 5008471Sache } 5019232Sache if (i >= fc->nisodma) { 5028471Sache err = EBUSY; 5039232Sache break; 504105806Sjhb } 5059232Sache err = fwdev_allocbuf(fc, ir, &d->bufreq.rx); 506105806Sjhb if (err) 507105806Sjhb break; 5089232Sache ir->flag |= FWXFERQ_OPEN; 5099232Sache } 510105806Sjhb ir->flag &= ~0xff; 511105806Sjhb ir->flag |= (0x3f & ichreq->ch); 512105806Sjhb ir->flag |= ((0x3 & ichreq->tag) << 6); 513105806Sjhb d->ir = ir; 514105806Sjhb err = fc->irx_enable(fc, ir->dmach); 5158471Sache break; 5169232Sache case FW_GRSTREAM: 5178471Sache if (d->ir != NULL) { 5189232Sache ichreq->ch = ir->flag & 0x3f; 5199232Sache ichreq->tag = ir->flag >> 2 & 0x3; 5209232Sache } else 5219232Sache err = EINVAL; 5229232Sache break; 5239232Sache case FW_SSTBUF: 5248471Sache bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq)); 5259232Sache break; 526105806Sjhb case FW_GSTBUF: 5279232Sache bzero(&ibufreq->rx, sizeof(ibufreq->rx)); 528105806Sjhb if (ir != NULL) { 5299232Sache ibufreq->rx.nchunk = ir->bnchunk; 5309232Sache ibufreq->rx.npacket = ir->bnpacket; 5318471Sache ibufreq->rx.psize = ir->psize; 5329232Sache } 533105806Sjhb bzero(&ibufreq->tx, sizeof(ibufreq->tx)); 5349232Sache if (it != NULL) { 535105806Sjhb ibufreq->tx.nchunk = it->bnchunk; 536105806Sjhb ibufreq->tx.npacket = it->bnpacket; 5379232Sache ibufreq->tx.psize = it->psize; 5389232Sache } 539105806Sjhb break; 540105806Sjhb case FW_ASYREQ: 5419232Sache { 5429232Sache struct tcode_info *tinfo; 5439232Sache int pay_len = 0; 5449232Sache 5459232Sache fp = &asyreq->pkt; 5469232Sache tinfo = &sc->fc->tcode[fp->mode.hdr.tcode]; 547105806Sjhb 548105806Sjhb if ((tinfo->flag & FWTI_BLOCK_ASY) != 0) 549105806Sjhb pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len); 550105806Sjhb 5519232Sache xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/); 5529232Sache if (xfer == NULL) 5539232Sache return (ENOMEM); 5549232Sache 5559232Sache switch (asyreq->req.type) { 5569232Sache case FWASREQNODE: 5579232Sache break; 5589232Sache case FWASREQEUI: 559105806Sjhb fwdev = fw_noderesolve_eui64(sc->fc, 5609232Sache &asyreq->req.dst.eui); 5618471Sache if (fwdev == NULL) { 5629232Sache device_printf(sc->fc->bdev, 5639232Sache "cannot find node\n"); 564105806Sjhb err = EINVAL; 5658471Sache goto out; 566105806Sjhb } 567105806Sjhb fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst; 568105806Sjhb break; 5698471Sache case FWASRESTL: 5709232Sache /* XXX what's this? */ 571105806Sjhb break; 5729232Sache case FWASREQSTREAM: 573105806Sjhb /* nothing to do */ 5749232Sache break; 5759232Sache } 5768471Sache 5779232Sache bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len); 578105806Sjhb if (pay_len > 0) 579105806Sjhb bcopy((char *)fp + tinfo->hdr_len, 580105806Sjhb (void *)xfer->send.payload, pay_len); 5818471Sache xfer->send.spd = asyreq->req.sped; 5828471Sache xfer->act.hand = fw_asy_callback; 5838471Sache 5848471Sache if ((err = fw_asyreq(sc->fc, -1, xfer)) != 0) 585105806Sjhb goto out; 586105806Sjhb if ((err = tsleep(xfer, FWPRI, "asyreq", hz)) != 0) 5878471Sache goto out; 588105806Sjhb if (xfer->resp != 0) { 589105806Sjhb err = EIO; 590105806Sjhb goto out; 5918471Sache } 592136210Sphk if ((tinfo->flag & FWTI_TLABEL) == 0) 5938471Sache goto out; 5948471Sache 595105806Sjhb /* copy response */ 5968471Sache tinfo = &sc->fc->tcode[xfer->recv.hdr.mode.hdr.tcode]; 5978471Sache if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB || 598106653Sjhb xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) { 5998471Sache pay_len = xfer->recv.pay_len; 6008471Sache if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) { 6018471Sache asyreq->req.len = xfer->recv.pay_len + 6028471Sache tinfo->hdr_len; 6038471Sache } else { 6049232Sache err = EINVAL; 6059232Sache pay_len = 0; 6069232Sache } 6079232Sache } else { 608105806Sjhb pay_len = 0; 609105806Sjhb } 6109232Sache bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len); 611105806Sjhb bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, pay_len); 612105806Sjhbout: 6138471Sache fw_xfer_free_buf(xfer); 614106653Sjhb break; 6158471Sache } 6168471Sache case FW_IBUSRST: 6178471Sache sc->fc->ibr(sc->fc); 6188471Sache break; 6198471Sache case FW_CBINDADDR: 6209626Sbde fwb = fw_bindlookup(sc->fc, 6218471Sache bindreq->start.hi, bindreq->start.lo); 6229232Sache if(fwb == NULL){ 6238471Sache err = EINVAL; 6248471Sache break; 6259232Sache } 626105806Sjhb STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 6278471Sache STAILQ_REMOVE(&ir->binds, fwb, fw_bind, chlist); 6288471Sache free(fwb, M_FW); 6298471Sache break; 6308471Sache case FW_SBINDADDR: 6318471Sache if(bindreq->len <= 0 ){ 6328471Sache err = EINVAL; 633106653Sjhb break; 6348471Sache } 6359232Sache if(bindreq->start.hi > 0xffff ){ 636106653Sjhb err = EINVAL; 6379232Sache break; 6388471Sache } 639105806Sjhb fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT); 640105806Sjhb if(fwb == NULL){ 6418471Sache err = ENOMEM; 642105806Sjhb break; 643105806Sjhb } 6448471Sache fwb->start = ((u_int64_t)bindreq->start.hi << 32) | 6458471Sache bindreq->start.lo; 6468471Sache fwb->end = fwb->start + bindreq->len; 6478471Sache /* XXX */ 6488471Sache fwb->sub = ir->dmach; 6498471Sache fwb->act_type = FWACT_CH; 6508471Sache 6518471Sache /* XXX alloc buf */ 652105806Sjhb xfer = fw_xfer_alloc(M_FWXFER); 653105806Sjhb if(xfer == NULL){ 6548471Sache free(fwb, M_FW); 655105806Sjhb return (ENOMEM); 656105806Sjhb } 657105806Sjhb xfer->fc = sc->fc; 658105806Sjhb 659105806Sjhb s = splfw(); 6608471Sache /* XXX broken. need multiple xfer */ 661105806Sjhb STAILQ_INIT(&fwb->xferlist); 662105806Sjhb STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 6638471Sache splx(s); 664105806Sjhb err = fw_bindadd(sc->fc, fwb); 665105806Sjhb break; 6668471Sache case FW_GDEVLST: 667136210Sphk i = len = 1; 6688471Sache /* myself */ 6698471Sache devinfo = &fwdevlst->dev[0]; 6708471Sache devinfo->dst = sc->fc->nodeid; 6718471Sache devinfo->status = 0; /* XXX */ 6728471Sache devinfo->eui.hi = sc->fc->eui.hi; 6738471Sache devinfo->eui.lo = sc->fc->eui.lo; 674106653Sjhb STAILQ_FOREACH(fwdev, &sc->fc->devices, link) { 6758471Sache if(len < FW_MAX_DEVLST){ 676105806Sjhb devinfo = &fwdevlst->dev[len++]; 677106653Sjhb devinfo->dst = fwdev->dst; 678105806Sjhb devinfo->status = 679105806Sjhb (fwdev->status == FWDEVINVAL)?0:1; 680105806Sjhb devinfo->eui.hi = fwdev->eui.hi; 6818471Sache devinfo->eui.lo = fwdev->eui.lo; 6828471Sache } 683106653Sjhb i++; 6848471Sache } 685105806Sjhb fwdevlst->n = i; 686106653Sjhb fwdevlst->info_len = len; 687105806Sjhb break; 688105806Sjhb case FW_GTPMAP: 6898471Sache bcopy(sc->fc->topology_map, data, 6908471Sache (sc->fc->topology_map->crc_len + 1) * 4); 691106653Sjhb break; 6928471Sache case FW_GCROM: 693105806Sjhb STAILQ_FOREACH(fwdev, &sc->fc->devices, link) 694106653Sjhb if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 695130077Sphk break; 6968471Sache if (fwdev == NULL) { 6978471Sache if (!FW_EUI64_EQUAL(sc->fc->eui, crom_buf->eui)) { 698106653Sjhb err = FWNODE_INVAL; 6998471Sache break; 7008471Sache } 7018471Sache /* myself */ 7028471Sache ptr = malloc(CROMSIZE, M_FW, M_WAITOK); 7038471Sache len = CROMSIZE; 7048471Sache for (i = 0; i < CROMSIZE/4; i++) 7058471Sache ((uint32_t *)ptr)[i] 7068471Sache = ntohl(sc->fc->config_rom[i]); 7078471Sache } else { 7088471Sache /* found */ 7098471Sache ptr = (void *)&fwdev->csrrom[0]; 7108471Sache if (fwdev->rommax < CSRROMOFF) 7118471Sache len = 0; 7128471Sache else 7138471Sache len = fwdev->rommax - CSRROMOFF + 4; 7148471Sache } 7158471Sache if (crom_buf->len < len) 7168471Sache len = crom_buf->len; 7179232Sache else 7189232Sache crom_buf->len = len; 7199232Sache err = copyout(ptr, crom_buf->ptr, len); 7208471Sache if (fwdev == NULL) 7219232Sache /* myself */ 722105806Sjhb free(ptr, M_FW); 723105806Sjhb break; 7248471Sache default: 7258471Sache sc->fc->ioctl (dev, cmd, data, flag, td); 726105806Sjhb break; 7278471Sache } 728106653Sjhb return err; 7298471Sache} 7309232Sacheint 7318471Sachefw_poll(struct cdev *dev, int events, fw_proc *td) 7328471Sache{ 7338471Sache struct firewire_softc *sc; 7348471Sache struct fw_xferq *ir; 7359822Sbde int revents; 7369822Sbde int tmp; 7379822Sbde int unit = DEV2UNIT(dev); 7389822Sbde 7398471Sache if (DEV_FWMEM(dev)) 7408471Sache return fwmem_poll(dev, events, td); 7418471Sache 7428471Sache sc = devclass_get_softc(firewire_devclass, unit); 743105806Sjhb ir = ((struct fw_drv1 *)dev->si_drv1)->ir; 744105806Sjhb revents = 0; 745105806Sjhb tmp = POLLIN | POLLRDNORM; 7468471Sache if (events & tmp) { 7478471Sache if (STAILQ_FIRST(&ir->q) != NULL) 7488471Sache revents |= tmp; 7498471Sache else 7508471Sache selrecord(td, &ir->rsel); 7519754Sbde } 7528471Sache tmp = POLLOUT | POLLWRNORM; 7538471Sache if (events & tmp) { 7548471Sache /* XXX should be fixed */ 755130095Sphk revents |= tmp; 7568471Sache } 757130095Sphk 7588471Sache return revents; 75927125Sbde} 7608471Sache 7618471Sachestatic int 762106653Sjhb#if defined(__DragonFly__) || __FreeBSD_version < 500102 763105806Sjhbfw_mmap (struct cdev *dev, vm_offset_t offset, int nproto) 7649232Sache#else 765136210Sphkfw_mmap (struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto) 766106653Sjhb#endif 767130077Sphk{ 7688471Sache struct firewire_softc *sc; 769111564Sjhb int unit = DEV2UNIT(dev); 770111564Sjhb 7718471Sache if (DEV_FWMEM(dev)) 772111564Sjhb#if defined(__DragonFly__) || __FreeBSD_version < 500102 7738471Sache return fwmem_mmap(dev, offset, nproto); 7748471Sache#else 775105806Sjhb return fwmem_mmap(dev, offset, paddr, nproto); 776105806Sjhb#endif 7778471Sache 778105806Sjhb sc = devclass_get_softc(firewire_devclass, unit); 779105806Sjhb 7808471Sache return EINVAL; 7818471Sache} 782136210Sphk 783105806Sjhbstatic void 7848471Sachefw_strategy(struct bio *bp) 785105806Sjhb{ 786105806Sjhb struct cdev *dev; 7878471Sache 7888471Sache dev = bp->bio_dev; 7898471Sache if (DEV_FWMEM(dev)) { 790106653Sjhb fwmem_strategy(bp); 7918471Sache return; 7929232Sache } 7938471Sache 7948471Sache bp->bio_error = EOPNOTSUPP; 7958471Sache bp->bio_flags |= BIO_ERROR; 7968471Sache bp->bio_resid = bp->bio_bcount; 7978471Sache biodone(bp); 7988471Sache} 7998471Sache 8008471Sacheint 801105806Sjhbfwdev_makedev(struct firewire_softc *sc) 8028471Sache{ 8038471Sache int err = 0; 8048471Sache 8058471Sache#if defined(__DragonFly__) || __FreeBSD_version < 500000 8068471Sache cdevsw_add(&firewire_cdevsw); 807106653Sjhb#else 8088471Sache struct cdev *d; 8098471Sache int unit; 810136210Sphk 811136210Sphk unit = device_get_unit(sc->fc->bdev); 8128471Sache sc->dev = make_dev(&firewire_cdevsw, MAKEMINOR(0, unit, 0), 813105806Sjhb UID_ROOT, GID_OPERATOR, 0660, 814105806Sjhb "fw%d.%d", unit, 0); 815105806Sjhb d = make_dev(&firewire_cdevsw, 8168471Sache MAKEMINOR(FWMEM_FLAG, unit, 0), 817136210Sphk UID_ROOT, GID_OPERATOR, 0660, 818105806Sjhb "fwmem%d.%d", unit, 0); 8198471Sache dev_depends(sc->dev, d); 820105806Sjhb make_dev_alias(sc->dev, "fw%d", unit); 8218471Sache make_dev_alias(d, "fwmem%d", unit); 8229232Sache#endif 823105806Sjhb 8249232Sache return (err); 82546704Speter} 8268471Sache 82746704Speterint 8289232Sachefwdev_destroydev(struct firewire_softc *sc) 8299232Sache{ 830105806Sjhb int err = 0; 831105806Sjhb 832131096Sphk#if defined(__DragonFly__) || __FreeBSD_version < 500000 833131981Sphk cdevsw_remove(&firewire_cdevsw); 8348471Sache#else 8358471Sache destroy_dev(sc->dev); 836111748Sdes#endif 8379639Sbde return (err); 8388471Sache} 8398471Sache 8408471Sache#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 8418471Sache#define NDEVTYPE 2 842105806Sjhbvoid 843118607Sjhbfwdev_clone(void *arg, char *name, int namelen, struct cdev **dev) 8448471Sache{ 845105806Sjhb struct firewire_softc *sc; 8468471Sache char *devnames[NDEVTYPE] = {"fw", "fwmem"}; 847105806Sjhb char *subp = NULL; 8489232Sache int devflag[NDEVTYPE] = {0, FWMEM_FLAG}; 849105806Sjhb int i, unit = 0, sub = 0; 850105806Sjhb 851105806Sjhb if (*dev != NULL) 8528471Sache return; 8538471Sache 854105806Sjhb for (i = 0; i < NDEVTYPE; i++) 855105806Sjhb if (dev_stdclone(name, &subp, devnames[i], &unit) == 2) 8568471Sache goto found; 8578471Sache /* not match */ 858105806Sjhb return; 859105806Sjhbfound: 860105806Sjhb 8618471Sache if (subp == NULL || *subp++ != '.') 8628471Sache return; 863105806Sjhb 8648471Sache /* /dev/fwU.S */ 8658471Sache while (isdigit(*subp)) { 8668471Sache sub *= 10; 867105806Sjhb sub += *subp++ - '0'; 868105806Sjhb } 8698471Sache if (*subp != '\0') 870105806Sjhb return; 871105806Sjhb 872105806Sjhb sc = devclass_get_softc(firewire_devclass, unit); 8738471Sache if (sc == NULL) 8749855Sache return; 8759855Sache *dev = make_dev(&firewire_cdevsw, MAKEMINOR(devflag[i], unit, sub), 8769855Sache UID_ROOT, GID_OPERATOR, 0660, 8779855Sache "%s%d.%d", devnames[i], unit, sub); 8788471Sache dev_ref(*dev); 8798471Sache (*dev)->si_flags |= SI_CHEAPCLONE; 8809855Sache dev_depends(sc->dev, *dev); 8819855Sache return; 8828471Sache} 883136210Sphk#endif 884105806Sjhb