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

Cache object: eba25be3f9ed8b8e38d88eeb267766a3


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