The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/firewire/fwdev.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-4-Clause
    3  *
    4  * Copyright (c) 2003 Hidetoshi Shimokawa
    5  * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the acknowledgement as bellow:
   18  *
   19  *    This product includes software developed by K. Kobayashi and H. Shimokawa
   20  *
   21  * 4. The name of the author may not be used to endorse or promote products
   22  *    derived from this software without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   26  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   27  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
   28  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   29  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   30  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   32  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   34  * POSSIBILITY OF SUCH DAMAGE.
   35  *
   36  * $FreeBSD$
   37  *
   38  */
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/types.h>
   43 #include <sys/mbuf.h>
   44 #include <sys/bio.h>
   45 
   46 #include <sys/kernel.h>
   47 #include <sys/malloc.h>
   48 #include <sys/conf.h>
   49 #include <sys/poll.h>
   50 
   51 #include <sys/bus.h>
   52 #include <sys/ctype.h>
   53 #include <machine/bus.h>
   54 
   55 #include <sys/ioccom.h>
   56 
   57 #include <dev/firewire/firewire.h>
   58 #include <dev/firewire/firewirereg.h>
   59 #include <dev/firewire/fwdma.h>
   60 #include <dev/firewire/fwmem.h>
   61 #include <dev/firewire/iec68113.h>
   62 
   63 #define FWNODE_INVAL 0xffff
   64 
   65 static  d_open_t        fw_open;
   66 static  d_close_t       fw_close;
   67 static  d_ioctl_t       fw_ioctl;
   68 static  d_poll_t        fw_poll;
   69 static  d_read_t        fw_read;        /* for Isochronous packet */
   70 static  d_write_t       fw_write;
   71 static  d_mmap_t        fw_mmap;
   72 static  d_strategy_t    fw_strategy;
   73 
   74 struct cdevsw firewire_cdevsw = {
   75         .d_version =    D_VERSION,
   76         .d_open =       fw_open,
   77         .d_close =      fw_close,
   78         .d_read =       fw_read,
   79         .d_write =      fw_write,
   80         .d_ioctl =      fw_ioctl,
   81         .d_poll =       fw_poll,
   82         .d_mmap =       fw_mmap,
   83         .d_strategy =   fw_strategy,
   84         .d_name =       "fw",
   85 };
   86 
   87 struct fw_drv1 {
   88         struct firewire_comm *fc;
   89         struct fw_xferq *ir;
   90         struct fw_xferq *it;
   91         struct fw_isobufreq bufreq;
   92         STAILQ_HEAD(, fw_bind) binds;
   93         STAILQ_HEAD(, fw_xfer) rq;
   94 };
   95 
   96 static int
   97 fwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q,
   98         struct fw_bufspec *b)
   99 {
  100         int i;
  101 
  102         if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF))
  103                 return (EBUSY);
  104 
  105         q->bulkxfer = malloc(sizeof(struct fw_bulkxfer) * b->nchunk,
  106             M_FW, M_WAITOK);
  107 
  108         b->psize = roundup2(b->psize, sizeof(uint32_t));
  109         q->buf = fwdma_malloc_multiseg(fc, sizeof(uint32_t),
  110             b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK);
  111 
  112         if (q->buf == NULL) {
  113                 free(q->bulkxfer, M_FW);
  114                 q->bulkxfer = NULL;
  115                 return (ENOMEM);
  116         }
  117         q->bnchunk = b->nchunk;
  118         q->bnpacket = b->npacket;
  119         q->psize = (b->psize + 3) & ~3;
  120         q->queued = 0;
  121 
  122         STAILQ_INIT(&q->stvalid);
  123         STAILQ_INIT(&q->stfree);
  124         STAILQ_INIT(&q->stdma);
  125         q->stproc = NULL;
  126 
  127         for (i = 0; i < q->bnchunk; i++) {
  128                 q->bulkxfer[i].poffset = i * q->bnpacket;
  129                 q->bulkxfer[i].mbuf = NULL;
  130                 STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link);
  131         }
  132 
  133         q->flag &= ~FWXFERQ_MODEMASK;
  134         q->flag |= FWXFERQ_STREAM;
  135         q->flag |= FWXFERQ_EXTBUF;
  136 
  137         return (0);
  138 }
  139 
  140 static int
  141 fwdev_freebuf(struct fw_xferq *q)
  142 {
  143         if (q->flag & FWXFERQ_EXTBUF) {
  144                 if (q->buf != NULL)
  145                         fwdma_free_multiseg(q->buf);
  146                 q->buf = NULL;
  147                 free(q->bulkxfer, M_FW);
  148                 q->bulkxfer = NULL;
  149                 q->flag &= ~FWXFERQ_EXTBUF;
  150                 q->psize = 0;
  151                 q->maxq = FWMAXQUEUE;
  152         }
  153         return (0);
  154 }
  155 
  156 
  157 static int
  158 fw_open(struct cdev *dev, int flags, int fmt, fw_proc *td)
  159 {
  160         int err = 0;
  161         int unit = DEV2UNIT(dev);
  162         struct fw_drv1 *d;
  163         struct firewire_softc *sc;
  164 
  165         if (DEV_FWMEM(dev))
  166                 return fwmem_open(dev, flags, fmt, td);
  167 
  168         sc = devclass_get_softc(firewire_devclass, unit);
  169         if (sc == NULL)
  170                 return (ENXIO);
  171 
  172         FW_GLOCK(sc->fc);
  173         if (dev->si_drv1 != NULL) {
  174                 FW_GUNLOCK(sc->fc);
  175                 return (EBUSY);
  176         }
  177         /* set dummy value for allocation */
  178         dev->si_drv1 = (void *)-1;
  179         FW_GUNLOCK(sc->fc);
  180 
  181         dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO);
  182 
  183         if ((dev->si_flags & SI_NAMED) == 0) {
  184                 int unit = DEV2UNIT(dev);
  185                 int sub = DEV2SUB(dev);
  186 
  187                 make_dev(&firewire_cdevsw, dev2unit(dev),
  188                     UID_ROOT, GID_OPERATOR, 0660, "fw%d.%d", unit, sub);
  189         }
  190 
  191         d = dev->si_drv1;
  192         d->fc = sc->fc;
  193         STAILQ_INIT(&d->binds);
  194         STAILQ_INIT(&d->rq);
  195 
  196         return err;
  197 }
  198 
  199 static int
  200 fw_close(struct cdev *dev, int flags, int fmt, fw_proc *td)
  201 {
  202         struct firewire_comm *fc;
  203         struct fw_drv1 *d;
  204         struct fw_xfer *xfer;
  205         struct fw_bind *fwb;
  206         int err = 0;
  207 
  208         if (DEV_FWMEM(dev))
  209                 return fwmem_close(dev, flags, fmt, td);
  210 
  211         d = dev->si_drv1;
  212         fc = d->fc;
  213 
  214         /* remove binding */
  215         for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL;
  216             fwb = STAILQ_FIRST(&d->binds)) {
  217                 fw_bindremove(fc, fwb);
  218                 STAILQ_REMOVE_HEAD(&d->binds, chlist);
  219                 fw_xferlist_remove(&fwb->xferlist);
  220                 free(fwb, M_FW);
  221         }
  222         if (d->ir != NULL) {
  223                 struct fw_xferq *ir = d->ir;
  224 
  225                 if ((ir->flag & FWXFERQ_OPEN) == 0)
  226                         return (EINVAL);
  227                 if (ir->flag & FWXFERQ_RUNNING) {
  228                         ir->flag &= ~FWXFERQ_RUNNING;
  229                         fc->irx_disable(fc, ir->dmach);
  230                 }
  231                 /* free extbuf */
  232                 fwdev_freebuf(ir);
  233                 /* drain receiving buffer */
  234                 for (xfer = STAILQ_FIRST(&ir->q);
  235                     xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) {
  236                         ir->queued--;
  237                         STAILQ_REMOVE_HEAD(&ir->q, link);
  238 
  239                         xfer->resp = 0;
  240                         fw_xfer_done(xfer);
  241                 }
  242                 ir->flag &= ~(FWXFERQ_OPEN | FWXFERQ_MODEMASK |
  243                     FWXFERQ_CHTAGMASK);
  244                 d->ir = NULL;
  245 
  246         }
  247         if (d->it != NULL) {
  248                 struct fw_xferq *it = d->it;
  249 
  250                 if ((it->flag & FWXFERQ_OPEN) == 0)
  251                         return (EINVAL);
  252                 if (it->flag & FWXFERQ_RUNNING) {
  253                         it->flag &= ~FWXFERQ_RUNNING;
  254                         fc->itx_disable(fc, it->dmach);
  255                 }
  256                 /* free extbuf */
  257                 fwdev_freebuf(it);
  258                 it->flag &= ~(FWXFERQ_OPEN |
  259                     FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
  260                 d->it = NULL;
  261         }
  262         free(dev->si_drv1, M_FW);
  263         dev->si_drv1 = NULL;
  264 
  265         return err;
  266 }
  267 
  268 static int
  269 fw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag)
  270 {
  271         int err = 0, s;
  272         struct fw_xfer *xfer;
  273         struct fw_bind *fwb;
  274         struct fw_pkt *fp;
  275         struct tcode_info *tinfo;
  276 
  277         FW_GLOCK(d->fc);
  278         while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == 0)
  279                 err = msleep(&d->rq, FW_GMTX(d->fc), FWPRI, "fwra", 0);
  280 
  281         if (err != 0) {
  282                 FW_GUNLOCK(d->fc);
  283                 return (err);
  284         }
  285 
  286         s = splfw();
  287         STAILQ_REMOVE_HEAD(&d->rq, link);
  288         FW_GUNLOCK(xfer->fc);
  289         splx(s);
  290         fp = &xfer->recv.hdr;
  291 #if 0 /* for GASP ?? */
  292         if (fc->irx_post != NULL)
  293                 fc->irx_post(fc, fp->mode.ld);
  294 #endif
  295         tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode];
  296         err = uiomove(fp, tinfo->hdr_len, uio);
  297         if (err)
  298                 goto out;
  299         err = uiomove(xfer->recv.payload, xfer->recv.pay_len, uio);
  300 
  301 out:
  302         /* recycle this xfer */
  303         fwb = (struct fw_bind *)xfer->sc;
  304         fw_xfer_unload(xfer);
  305         xfer->recv.pay_len = PAGE_SIZE;
  306         FW_GLOCK(xfer->fc);
  307         STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link);
  308         FW_GUNLOCK(xfer->fc);
  309         return (err);
  310 }
  311 
  312 /*
  313  * read request.
  314  */
  315 static int
  316 fw_read(struct cdev *dev, struct uio *uio, int ioflag)
  317 {
  318         struct fw_drv1 *d;
  319         struct fw_xferq *ir;
  320         struct firewire_comm *fc;
  321         int err = 0, s, slept = 0;
  322         struct fw_pkt *fp;
  323 
  324         if (DEV_FWMEM(dev))
  325                 return (physio(dev, uio, ioflag));
  326 
  327         d = dev->si_drv1;
  328         fc = d->fc;
  329         ir = d->ir;
  330 
  331         if (ir == NULL)
  332                 return (fw_read_async(d, uio, ioflag));
  333 
  334         if (ir->buf == NULL)
  335                 return (EIO);
  336 
  337         FW_GLOCK(fc);
  338 readloop:
  339         if (ir->stproc == NULL) {
  340                 /* iso bulkxfer */
  341                 ir->stproc = STAILQ_FIRST(&ir->stvalid);
  342                 if (ir->stproc != NULL) {
  343                         s = splfw();
  344                         STAILQ_REMOVE_HEAD(&ir->stvalid, link);
  345                         splx(s);
  346                         ir->queued = 0;
  347                 }
  348         }
  349         if (ir->stproc == NULL) {
  350                 /* no data available */
  351                 if (slept == 0) {
  352                         slept = 1;
  353                         ir->flag |= FWXFERQ_WAKEUP;
  354                         err = msleep(ir, FW_GMTX(fc), FWPRI, "fw_read", hz);
  355                         ir->flag &= ~FWXFERQ_WAKEUP;
  356                         if (err == 0)
  357                                 goto readloop;
  358                 } else if (slept == 1)
  359                         err = EIO;
  360                 FW_GUNLOCK(fc);
  361                 return err;
  362         } else if (ir->stproc != NULL) {
  363                 /* iso bulkxfer */
  364                 FW_GUNLOCK(fc);
  365                 fp = (struct fw_pkt *)fwdma_v_addr(ir->buf,
  366                     ir->stproc->poffset + ir->queued);
  367                 if (fc->irx_post != NULL)
  368                         fc->irx_post(fc, fp->mode.ld);
  369                 if (fp->mode.stream.len == 0) {
  370                         err = EIO;
  371                         return err;
  372                 }
  373                 err = uiomove((caddr_t)fp,
  374                         fp->mode.stream.len + sizeof(uint32_t), uio);
  375                 ir->queued++;
  376                 if (ir->queued >= ir->bnpacket) {
  377                         s = splfw();
  378                         STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link);
  379                         splx(s);
  380                         fc->irx_enable(fc, ir->dmach);
  381                         ir->stproc = NULL;
  382                 }
  383                 if (uio->uio_resid >= ir->psize) {
  384                         slept = -1;
  385                         FW_GLOCK(fc);
  386                         goto readloop;
  387                 }
  388         }
  389         return err;
  390 }
  391 
  392 static int
  393 fw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag)
  394 {
  395         struct fw_xfer *xfer;
  396         struct fw_pkt pkt;
  397         struct tcode_info *tinfo;
  398         int err;
  399 
  400         bzero(&pkt, sizeof(struct fw_pkt));
  401         if ((err = uiomove((caddr_t)&pkt, sizeof(uint32_t), uio)))
  402                 return (err);
  403         tinfo = &d->fc->tcode[pkt.mode.hdr.tcode];
  404         if ((err = uiomove((caddr_t)&pkt + sizeof(uint32_t),
  405             tinfo->hdr_len - sizeof(uint32_t), uio)))
  406                 return (err);
  407 
  408         if ((xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid,
  409             PAGE_SIZE/*XXX*/)) == NULL)
  410                 return (ENOMEM);
  411 
  412         bcopy(&pkt, &xfer->send.hdr, sizeof(struct fw_pkt));
  413         xfer->send.pay_len = uio->uio_resid;
  414         if (uio->uio_resid > 0) {
  415                 if ((err = uiomove((caddr_t)&xfer->send.payload[0],
  416                     uio->uio_resid, uio)))
  417                         goto out;
  418         }
  419 
  420         xfer->fc = d->fc;
  421         xfer->sc = NULL;
  422         xfer->hand = fw_xferwake;
  423         xfer->send.spd = 2 /* XXX */;
  424 
  425         if ((err = fw_asyreq(xfer->fc, -1, xfer)))
  426                 goto out;
  427 
  428         if ((err = fw_xferwait(xfer)))
  429                 goto out;
  430 
  431         if (xfer->resp != 0) {
  432                 err = xfer->resp;
  433                 goto out;
  434         }
  435 
  436         if (xfer->flag & FWXF_RCVD) {
  437                 FW_GLOCK(xfer->fc);
  438                 STAILQ_INSERT_TAIL(&d->rq, xfer, link);
  439                 FW_GUNLOCK(xfer->fc);
  440                 return (0);
  441         }
  442 
  443 out:
  444         fw_xfer_free(xfer);
  445         return (err);
  446 }
  447 
  448 static int
  449 fw_write(struct cdev *dev, struct uio *uio, int ioflag)
  450 {
  451         int err = 0;
  452         int s, slept = 0;
  453         struct fw_drv1 *d;
  454         struct fw_pkt *fp;
  455         struct firewire_comm *fc;
  456         struct fw_xferq *it;
  457 
  458         if (DEV_FWMEM(dev))
  459                 return (physio(dev, uio, ioflag));
  460 
  461         d = dev->si_drv1;
  462         fc = d->fc;
  463         it = d->it;
  464 
  465         if (it == NULL)
  466                 return (fw_write_async(d, uio, ioflag));
  467 
  468         if (it->buf == NULL)
  469                 return (EIO);
  470 
  471         FW_GLOCK(fc);
  472 isoloop:
  473         if (it->stproc == NULL) {
  474                 it->stproc = STAILQ_FIRST(&it->stfree);
  475                 if (it->stproc != NULL) {
  476                         s = splfw();
  477                         STAILQ_REMOVE_HEAD(&it->stfree, link);
  478                         splx(s);
  479                         it->queued = 0;
  480                 } else if (slept == 0) {
  481                         slept = 1;
  482 #if 0   /* XXX to avoid lock recursion */
  483                         err = fc->itx_enable(fc, it->dmach);
  484                         if (err)
  485                                 goto out;
  486 #endif
  487                         err = msleep(it, FW_GMTX(fc), FWPRI, "fw_write", hz);
  488                         if (err)
  489                                 goto out;
  490                         goto isoloop;
  491                 } else {
  492                         err = EIO;
  493                         goto out;
  494                 }
  495         }
  496         FW_GUNLOCK(fc);
  497         fp = (struct fw_pkt *)fwdma_v_addr(it->buf,
  498                         it->stproc->poffset + it->queued);
  499         err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio);
  500         err = uiomove((caddr_t)fp->mode.stream.payload,
  501                                 fp->mode.stream.len, uio);
  502         it->queued++;
  503         if (it->queued >= it->bnpacket) {
  504                 s = splfw();
  505                 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
  506                 splx(s);
  507                 it->stproc = NULL;
  508                 err = fc->itx_enable(fc, it->dmach);
  509         }
  510         if (uio->uio_resid >= sizeof(struct fw_isohdr)) {
  511                 slept = 0;
  512                 FW_GLOCK(fc);
  513                 goto isoloop;
  514         }
  515         return err;
  516 
  517 out:
  518         FW_GUNLOCK(fc);
  519         return err;
  520 }
  521 
  522 static void
  523 fw_hand(struct fw_xfer *xfer)
  524 {
  525         struct fw_bind *fwb;
  526         struct fw_drv1 *d;
  527 
  528         fwb = (struct fw_bind *)xfer->sc;
  529         d = fwb->sc;
  530         FW_GLOCK(xfer->fc);
  531         STAILQ_INSERT_TAIL(&d->rq, xfer, link);
  532         FW_GUNLOCK(xfer->fc);
  533         wakeup(&d->rq);
  534 }
  535 
  536 /*
  537  * ioctl support.
  538  */
  539 int
  540 fw_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
  541 {
  542         struct firewire_comm *fc;
  543         struct fw_drv1 *d;
  544         int i, len, err = 0;
  545         struct fw_device *fwdev;
  546         struct fw_bind *fwb;
  547         struct fw_xferq *ir, *it;
  548         struct fw_xfer *xfer;
  549         struct fw_pkt *fp;
  550         struct fw_devinfo *devinfo;
  551         void *ptr;
  552 
  553         struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data;
  554         struct fw_asyreq *asyreq = (struct fw_asyreq *)data;
  555         struct fw_isochreq *ichreq = (struct fw_isochreq *)data;
  556         struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data;
  557         struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data;
  558         struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data;
  559 
  560         if (DEV_FWMEM(dev))
  561                 return fwmem_ioctl(dev, cmd, data, flag, td);
  562 
  563         if (!data)
  564                 return (EINVAL);
  565 
  566         d = dev->si_drv1;
  567         fc = d->fc;
  568         ir = d->ir;
  569         it = d->it;
  570 
  571         switch (cmd) {
  572         case FW_STSTREAM:
  573                 if (it == NULL) {
  574                         i = fw_open_isodma(fc, /* tx */1);
  575                         if (i < 0) {
  576                                 err = EBUSY;
  577                                 break;
  578                         }
  579                         it = fc->it[i];
  580                         err = fwdev_allocbuf(fc, it, &d->bufreq.tx);
  581                         if (err) {
  582                                 it->flag &= ~FWXFERQ_OPEN;
  583                                 break;
  584                         }
  585                 }
  586                 it->flag &= ~0xff;
  587                 it->flag |= (0x3f & ichreq->ch);
  588                 it->flag |= ((0x3 & ichreq->tag) << 6);
  589                 d->it = it;
  590                 break;
  591         case FW_GTSTREAM:
  592                 if (it != NULL) {
  593                         ichreq->ch = it->flag & 0x3f;
  594                         ichreq->tag = it->flag >> 2 & 0x3;
  595                 } else
  596                         err = EINVAL;
  597                 break;
  598         case FW_SRSTREAM:
  599                 if (ir == NULL) {
  600                         i = fw_open_isodma(fc, /* tx */0);
  601                         if (i < 0) {
  602                                 err = EBUSY;
  603                                 break;
  604                         }
  605                         ir = fc->ir[i];
  606                         err = fwdev_allocbuf(fc, ir, &d->bufreq.rx);
  607                         if (err) {
  608                                 ir->flag &= ~FWXFERQ_OPEN;
  609                                 break;
  610                         }
  611                 }
  612                 ir->flag &= ~0xff;
  613                 ir->flag |= (0x3f & ichreq->ch);
  614                 ir->flag |= ((0x3 & ichreq->tag) << 6);
  615                 d->ir = ir;
  616                 err = fc->irx_enable(fc, ir->dmach);
  617                 break;
  618         case FW_GRSTREAM:
  619                 if (d->ir != NULL) {
  620                         ichreq->ch = ir->flag & 0x3f;
  621                         ichreq->tag = ir->flag >> 2 & 0x3;
  622                 } else
  623                         err = EINVAL;
  624                 break;
  625         case FW_SSTBUF:
  626                 bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq));
  627                 break;
  628         case FW_GSTBUF:
  629                 bzero(&ibufreq->rx, sizeof(ibufreq->rx));
  630                 if (ir != NULL) {
  631                         ibufreq->rx.nchunk = ir->bnchunk;
  632                         ibufreq->rx.npacket = ir->bnpacket;
  633                         ibufreq->rx.psize = ir->psize;
  634                 }
  635                 bzero(&ibufreq->tx, sizeof(ibufreq->tx));
  636                 if (it != NULL) {
  637                         ibufreq->tx.nchunk = it->bnchunk;
  638                         ibufreq->tx.npacket = it->bnpacket;
  639                         ibufreq->tx.psize = it->psize;
  640                 }
  641                 break;
  642         case FW_ASYREQ:
  643         {
  644                 struct tcode_info *tinfo;
  645                 int pay_len = 0;
  646 
  647                 fp = &asyreq->pkt;
  648                 tinfo = &fc->tcode[fp->mode.hdr.tcode];
  649 
  650                 if ((tinfo->flag & FWTI_BLOCK_ASY) != 0)
  651                         pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len);
  652 
  653                 xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/);
  654                 if (xfer == NULL)
  655                         return (ENOMEM);
  656 
  657                 switch (asyreq->req.type) {
  658                 case FWASREQNODE:
  659                         break;
  660                 case FWASREQEUI:
  661                         fwdev = fw_noderesolve_eui64(fc,
  662                                                 &asyreq->req.dst.eui);
  663                         if (fwdev == NULL) {
  664                                 device_printf(fc->bdev,
  665                                         "cannot find node\n");
  666                                 err = EINVAL;
  667                                 goto out;
  668                         }
  669                         fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst;
  670                         break;
  671                 case FWASRESTL:
  672                         /* XXX what's this? */
  673                         break;
  674                 case FWASREQSTREAM:
  675                         /* nothing to do */
  676                         break;
  677                 }
  678 
  679                 bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len);
  680                 if (pay_len > 0)
  681                         bcopy((char *)fp + tinfo->hdr_len,
  682                             xfer->send.payload, pay_len);
  683                 xfer->send.spd = asyreq->req.sped;
  684                 xfer->hand = fw_xferwake;
  685 
  686                 if ((err = fw_asyreq(fc, -1, xfer)) != 0)
  687                         goto out;
  688                 if ((err = fw_xferwait(xfer)) != 0)
  689                         goto out;
  690                 if (xfer->resp != 0) {
  691                         err = EIO;
  692                         goto out;
  693                 }
  694                 if ((tinfo->flag & FWTI_TLABEL) == 0)
  695                         goto out;
  696 
  697                 /* copy response */
  698                 tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode];
  699                 if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB ||
  700                     xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) {
  701                         pay_len = xfer->recv.pay_len;
  702                         if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) {
  703                                 asyreq->req.len = xfer->recv.pay_len +
  704                                     tinfo->hdr_len;
  705                         } else {
  706                                 err = EINVAL;
  707                                 pay_len = 0;
  708                         }
  709                 } else {
  710                         pay_len = 0;
  711                 }
  712                 bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len);
  713                 bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, pay_len);
  714 out:
  715                 fw_xfer_free_buf(xfer);
  716                 break;
  717         }
  718         case FW_IBUSRST:
  719                 fc->ibr(fc);
  720                 break;
  721         case FW_CBINDADDR:
  722                 fwb = fw_bindlookup(fc,
  723                                 bindreq->start.hi, bindreq->start.lo);
  724                 if (fwb == NULL) {
  725                         err = EINVAL;
  726                         break;
  727                 }
  728                 fw_bindremove(fc, fwb);
  729                 STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist);
  730                 fw_xferlist_remove(&fwb->xferlist);
  731                 free(fwb, M_FW);
  732                 break;
  733         case FW_SBINDADDR:
  734                 if (bindreq->len <= 0) {
  735                         err = EINVAL;
  736                         break;
  737                 }
  738                 if (bindreq->start.hi > 0xffff) {
  739                         err = EINVAL;
  740                         break;
  741                 }
  742                 fwb = malloc(sizeof(struct fw_bind), M_FW, M_WAITOK);
  743                 fwb->start = ((u_int64_t)bindreq->start.hi << 32) |
  744                     bindreq->start.lo;
  745                 fwb->end = fwb->start +  bindreq->len;
  746                 fwb->sc = d;
  747                 STAILQ_INIT(&fwb->xferlist);
  748                 err = fw_bindadd(fc, fwb);
  749                 if (err == 0) {
  750                         fw_xferlist_add(&fwb->xferlist, M_FWXFER,
  751                             /* XXX */
  752                             PAGE_SIZE, PAGE_SIZE, 5,
  753                             fc, fwb, fw_hand);
  754                         STAILQ_INSERT_TAIL(&d->binds, fwb, chlist);
  755                 }
  756                 break;
  757         case FW_GDEVLST:
  758                 i = len = 1;
  759                 /* myself */
  760                 devinfo = &fwdevlst->dev[0];
  761                 devinfo->dst = fc->nodeid;
  762                 devinfo->status = 0;    /* XXX */
  763                 devinfo->eui.hi = fc->eui.hi;
  764                 devinfo->eui.lo = fc->eui.lo;
  765                 STAILQ_FOREACH(fwdev, &fc->devices, link) {
  766                         if (len < FW_MAX_DEVLST) {
  767                                 devinfo = &fwdevlst->dev[len++];
  768                                 devinfo->dst = fwdev->dst;
  769                                 devinfo->status =
  770                                         (fwdev->status == FWDEVINVAL) ? 0 : 1;
  771                                 devinfo->eui.hi = fwdev->eui.hi;
  772                                 devinfo->eui.lo = fwdev->eui.lo;
  773                         }
  774                         i++;
  775                 }
  776                 fwdevlst->n = i;
  777                 fwdevlst->info_len = len;
  778                 break;
  779         case FW_GTPMAP:
  780                 bcopy(fc->topology_map, data,
  781                     (fc->topology_map->crc_len + 1) * 4);
  782                 break;
  783         case FW_GCROM:
  784                 STAILQ_FOREACH(fwdev, &fc->devices, link)
  785                         if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui))
  786                                 break;
  787                 if (fwdev == NULL) {
  788                         if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) {
  789                                 err = FWNODE_INVAL;
  790                                 break;
  791                         }
  792                         /* myself */
  793                         ptr = malloc(CROMSIZE, M_FW, M_WAITOK);
  794                         len = CROMSIZE;
  795                         for (i = 0; i < CROMSIZE/4; i++)
  796                                 ((uint32_t *)ptr)[i]
  797                                         = ntohl(fc->config_rom[i]);
  798                 } else {
  799                         /* found */
  800                         ptr = (void *)&fwdev->csrrom[0];
  801                         if (fwdev->rommax < CSRROMOFF)
  802                                 len = 0;
  803                         else
  804                                 len = fwdev->rommax - CSRROMOFF + 4;
  805                 }
  806                 if (crom_buf->len < len)
  807                         len = crom_buf->len;
  808                 else
  809                         crom_buf->len = len;
  810                 err = copyout(ptr, crom_buf->ptr, len);
  811                 if (fwdev == NULL)
  812                         /* myself */
  813                         free(ptr, M_FW);
  814                 break;
  815         default:
  816                 fc->ioctl(dev, cmd, data, flag, td);
  817                 break;
  818         }
  819         return err;
  820 }
  821 int
  822 fw_poll(struct cdev *dev, int events, fw_proc *td)
  823 {
  824         struct fw_xferq *ir;
  825         int revents;
  826         int tmp;
  827 
  828         if (DEV_FWMEM(dev))
  829                 return fwmem_poll(dev, events, td);
  830 
  831         ir = ((struct fw_drv1 *)dev->si_drv1)->ir;
  832         revents = 0;
  833         tmp = POLLIN | POLLRDNORM;
  834         if (events & tmp) {
  835                 if (STAILQ_FIRST(&ir->q) != NULL)
  836                         revents |= tmp;
  837                 else
  838                         selrecord(td, &ir->rsel);
  839         }
  840         tmp = POLLOUT | POLLWRNORM;
  841         if (events & tmp) {
  842                 /* XXX should be fixed */
  843                 revents |= tmp;
  844         }
  845 
  846         return revents;
  847 }
  848 
  849 static int
  850 fw_mmap (struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
  851     int nproto, vm_memattr_t *memattr)
  852 {
  853 
  854         if (DEV_FWMEM(dev))
  855                 return fwmem_mmap(dev, offset, paddr, nproto, memattr);
  856 
  857         return EINVAL;
  858 }
  859 
  860 static void
  861 fw_strategy(struct bio *bp)
  862 {
  863         struct cdev *dev;
  864 
  865         dev = bp->bio_dev;
  866         if (DEV_FWMEM(dev)) {
  867                 fwmem_strategy(bp);
  868                 return;
  869         }
  870 
  871         bp->bio_error = EOPNOTSUPP;
  872         bp->bio_flags |= BIO_ERROR;
  873         bp->bio_resid = bp->bio_bcount;
  874         biodone(bp);
  875 }
  876 
  877 int
  878 fwdev_makedev(struct firewire_softc *sc)
  879 {
  880         int err = 0;
  881 
  882         struct cdev *d;
  883         int unit;
  884 
  885         unit = device_get_unit(sc->fc->bdev);
  886         sc->dev = make_dev(&firewire_cdevsw, MAKEMINOR(0, unit, 0),
  887             UID_ROOT, GID_OPERATOR, 0660, "fw%d.%d", unit, 0);
  888         d = make_dev(&firewire_cdevsw, MAKEMINOR(FWMEM_FLAG, unit, 0),
  889             UID_ROOT, GID_OPERATOR, 0660, "fwmem%d.%d", unit, 0);
  890         dev_depends(sc->dev, d);
  891         make_dev_alias(sc->dev, "fw%d", unit);
  892         make_dev_alias(d, "fwmem%d", unit);
  893 
  894         return (err);
  895 }
  896 
  897 int
  898 fwdev_destroydev(struct firewire_softc *sc)
  899 {
  900         int err = 0;
  901 
  902         destroy_dev(sc->dev);
  903         return (err);
  904 }
  905 
  906 #define NDEVTYPE 2
  907 void
  908 fwdev_clone(void *arg, struct ucred *cred, char *name, int namelen,
  909     struct cdev **dev)
  910 {
  911         struct firewire_softc *sc;
  912         char *devnames[NDEVTYPE] = {"fw", "fwmem"};
  913         char *subp = NULL;
  914         int devflag[NDEVTYPE] = {0, FWMEM_FLAG};
  915         int i, unit = 0, sub = 0;
  916 
  917         if (*dev != NULL)
  918                 return;
  919 
  920         for (i = 0; i < NDEVTYPE; i++)
  921                 if (dev_stdclone(name, &subp, devnames[i], &unit) == 2)
  922                         goto found;
  923         /* not match */
  924         return;
  925 found:
  926 
  927         if (subp == NULL || *subp++ != '.')
  928                 return;
  929 
  930         /* /dev/fwU.S */
  931         while (isdigit(*subp)) {
  932                 sub *= 10;
  933                 sub += *subp++ - '';
  934         }
  935         if (*subp != '\0')
  936                 return;
  937 
  938         sc = devclass_get_softc(firewire_devclass, unit);
  939         if (sc == NULL)
  940                 return;
  941         *dev = make_dev_credf(MAKEDEV_REF, &firewire_cdevsw,
  942             MAKEMINOR(devflag[i], unit, sub), cred, UID_ROOT, GID_OPERATOR,
  943             0660, "%s%d.%d", devnames[i], unit, sub);
  944         dev_depends(sc->dev, *dev);
  945         return;
  946 }

Cache object: 0238c042d01cb531673570047d6cf9de


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.