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

Cache object: 126022f928a20e9eb83d2c3a4dc1d2be


[ 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.