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/fwmem.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) 2002-2003
    3  *      Hidetoshi Shimokawa. All rights reserved.
    4  * 
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *
   16  *      This product includes software developed by Hidetoshi Shimokawa.
   17  *
   18  * 4. Neither the name of the author nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  * 
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  * 
   34  */
   35 
   36 #ifdef __FreeBSD__
   37 #include <sys/cdefs.h>
   38 __FBSDID("$FreeBSD: releng/8.4/sys/dev/firewire/fwmem.c 170374 2007-06-06 14:31:36Z simokawa $");
   39 #endif
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/types.h>
   44 
   45 #include <sys/kernel.h>
   46 #include <sys/malloc.h>
   47 #include <sys/conf.h>
   48 #include <sys/sysctl.h>
   49 #if defined(__DragonFly__) || __FreeBSD_version < 500000
   50 #include <sys/buf.h>
   51 #else
   52 #include <sys/bio.h>
   53 #endif
   54 
   55 #include <sys/bus.h>
   56 #include <machine/bus.h>
   57 
   58 #include <sys/signal.h>
   59 #include <sys/mman.h>
   60 #include <sys/ioccom.h>
   61 #include <sys/fcntl.h>
   62 
   63 #ifdef __DragonFly__
   64 #include "firewire.h"
   65 #include "firewirereg.h"
   66 #include "fwmem.h"
   67 #else
   68 #include <dev/firewire/firewire.h>
   69 #include <dev/firewire/firewirereg.h>
   70 #include <dev/firewire/fwmem.h>
   71 #endif
   72 
   73 static int fwmem_speed=2, fwmem_debug=0;
   74 static struct fw_eui64 fwmem_eui64;
   75 SYSCTL_DECL(_hw_firewire);
   76 SYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0,
   77         "FireWire Memory Access");
   78 SYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW,
   79         &fwmem_eui64.hi, 0, "Fwmem target EUI64 high");
   80 SYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_lo, CTLFLAG_RW,
   81         &fwmem_eui64.lo, 0, "Fwmem target EUI64 low");
   82 SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0,
   83         "Fwmem link speed");
   84 SYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0,
   85         "Fwmem driver debug flag");
   86 
   87 MALLOC_DEFINE(M_FWMEM, "fwmem", "fwmem/FireWire");
   88 
   89 #define MAXLEN (512 << fwmem_speed)
   90 
   91 struct fwmem_softc {
   92         struct fw_eui64 eui;
   93         struct firewire_softc *sc;
   94         int refcount;
   95 };
   96 
   97 static struct fw_xfer *
   98 fwmem_xfer_req(
   99         struct fw_device *fwdev,
  100         caddr_t sc,
  101         int spd,
  102         int slen,
  103         int rlen,
  104         void *hand)
  105 {
  106         struct fw_xfer *xfer;
  107 
  108         xfer = fw_xfer_alloc(M_FWMEM);
  109         if (xfer == NULL)
  110                 return NULL;
  111 
  112         xfer->fc = fwdev->fc;
  113         xfer->send.hdr.mode.hdr.dst = FWLOCALBUS | fwdev->dst;
  114         if (spd < 0)
  115                 xfer->send.spd = fwdev->speed;
  116         else
  117                 xfer->send.spd = min(spd, fwdev->speed);
  118         xfer->hand = hand;
  119         xfer->sc = sc;
  120         xfer->send.pay_len = slen;
  121         xfer->recv.pay_len = rlen;
  122 
  123         return xfer;
  124 }
  125 
  126 struct fw_xfer *
  127 fwmem_read_quad(
  128         struct fw_device *fwdev,
  129         caddr_t sc,
  130         uint8_t spd,
  131         uint16_t dst_hi,
  132         uint32_t dst_lo,
  133         void *data,
  134         void (*hand)(struct fw_xfer *))
  135 {
  136         struct fw_xfer *xfer;
  137         struct fw_pkt *fp;
  138 
  139         xfer = fwmem_xfer_req(fwdev, (void *)sc, spd, 0, 4, hand);
  140         if (xfer == NULL) {
  141                 return NULL;
  142         }
  143 
  144         fp = &xfer->send.hdr;
  145         fp->mode.rreqq.tcode = FWTCODE_RREQQ;
  146         fp->mode.rreqq.dest_hi = dst_hi;
  147         fp->mode.rreqq.dest_lo = dst_lo;
  148 
  149         xfer->send.payload = NULL;
  150         xfer->recv.payload = (uint32_t *)data;
  151 
  152         if (fwmem_debug)
  153                 printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst,
  154                                 dst_hi, dst_lo);
  155 
  156         if (fw_asyreq(xfer->fc, -1, xfer) == 0)
  157                 return xfer;
  158 
  159         fw_xfer_free(xfer);
  160         return NULL;
  161 }
  162 
  163 struct fw_xfer *
  164 fwmem_write_quad(
  165         struct fw_device *fwdev,
  166         caddr_t sc,
  167         uint8_t spd,
  168         uint16_t dst_hi,
  169         uint32_t dst_lo,
  170         void *data,
  171         void (*hand)(struct fw_xfer *))
  172 {
  173         struct fw_xfer *xfer;
  174         struct fw_pkt *fp;
  175 
  176         xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 0, hand);
  177         if (xfer == NULL)
  178                 return NULL;
  179 
  180         fp = &xfer->send.hdr;
  181         fp->mode.wreqq.tcode = FWTCODE_WREQQ;
  182         fp->mode.wreqq.dest_hi = dst_hi;
  183         fp->mode.wreqq.dest_lo = dst_lo;
  184         fp->mode.wreqq.data = *(uint32_t *)data;
  185 
  186         xfer->send.payload = xfer->recv.payload = NULL;
  187 
  188         if (fwmem_debug)
  189                 printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst,
  190                         dst_hi, dst_lo, *(uint32_t *)data);
  191 
  192         if (fw_asyreq(xfer->fc, -1, xfer) == 0)
  193                 return xfer;
  194 
  195         fw_xfer_free(xfer);
  196         return NULL;
  197 }
  198 
  199 struct fw_xfer *
  200 fwmem_read_block(
  201         struct fw_device *fwdev,
  202         caddr_t sc,
  203         uint8_t spd,
  204         uint16_t dst_hi,
  205         uint32_t dst_lo,
  206         int len,
  207         void *data,
  208         void (*hand)(struct fw_xfer *))
  209 {
  210         struct fw_xfer *xfer;
  211         struct fw_pkt *fp;
  212         
  213         xfer = fwmem_xfer_req(fwdev, sc, spd, 0, roundup2(len, 4), hand);
  214         if (xfer == NULL)
  215                 return NULL;
  216 
  217         fp = &xfer->send.hdr;
  218         fp->mode.rreqb.tcode = FWTCODE_RREQB;
  219         fp->mode.rreqb.dest_hi = dst_hi;
  220         fp->mode.rreqb.dest_lo = dst_lo;
  221         fp->mode.rreqb.len = len;
  222         fp->mode.rreqb.extcode = 0;
  223 
  224         xfer->send.payload = NULL;
  225         xfer->recv.payload = data;
  226 
  227         if (fwmem_debug)
  228                 printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst,
  229                                 dst_hi, dst_lo, len);
  230         if (fw_asyreq(xfer->fc, -1, xfer) == 0)
  231                 return xfer;
  232 
  233         fw_xfer_free(xfer);
  234         return NULL;
  235 }
  236 
  237 struct fw_xfer *
  238 fwmem_write_block(
  239         struct fw_device *fwdev,
  240         caddr_t sc,
  241         uint8_t spd,
  242         uint16_t dst_hi,
  243         uint32_t dst_lo,
  244         int len,
  245         void *data,
  246         void (*hand)(struct fw_xfer *))
  247 {
  248         struct fw_xfer *xfer;
  249         struct fw_pkt *fp;
  250 
  251         xfer = fwmem_xfer_req(fwdev, sc, spd, len, 0, hand);
  252         if (xfer == NULL)
  253                 return NULL;
  254 
  255         fp = &xfer->send.hdr;
  256         fp->mode.wreqb.tcode = FWTCODE_WREQB;
  257         fp->mode.wreqb.dest_hi = dst_hi;
  258         fp->mode.wreqb.dest_lo = dst_lo;
  259         fp->mode.wreqb.len = len;
  260         fp->mode.wreqb.extcode = 0;
  261 
  262         xfer->send.payload = data;
  263         xfer->recv.payload = NULL;
  264 
  265         if (fwmem_debug)
  266                 printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev->dst,
  267                                 dst_hi, dst_lo, len);
  268         if (fw_asyreq(xfer->fc, -1, xfer) == 0)
  269                 return xfer;
  270 
  271         fw_xfer_free(xfer);
  272         return NULL;
  273 }
  274 
  275 
  276 int
  277 fwmem_open (struct cdev *dev, int flags, int fmt, fw_proc *td)
  278 {
  279         struct fwmem_softc *fms;
  280         struct firewire_softc *sc;
  281         int unit = DEV2UNIT(dev);
  282 
  283         sc = devclass_get_softc(firewire_devclass, unit);
  284         if (sc == NULL)
  285                 return (ENXIO);
  286 
  287         FW_GLOCK(sc->fc);
  288         if (dev->si_drv1 != NULL) {
  289                 if ((flags & FWRITE) != 0) {
  290                         FW_GUNLOCK(sc->fc);
  291                         return(EBUSY);
  292                 }
  293                 FW_GUNLOCK(sc->fc);
  294                 fms = (struct fwmem_softc *)dev->si_drv1;
  295                 fms->refcount ++;
  296         } else {
  297                 dev->si_drv1 = (void *)-1;
  298                 FW_GUNLOCK(sc->fc);
  299                 dev->si_drv1 = malloc(sizeof(struct fwmem_softc),
  300                                                  M_FWMEM, M_WAITOK);
  301                 if (dev->si_drv1 == NULL)
  302                         return(ENOMEM);
  303                 dev->si_iosize_max = DFLTPHYS;
  304                 fms = (struct fwmem_softc *)dev->si_drv1;
  305                 bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64));
  306                 fms->sc = sc;
  307                 fms->refcount = 1;
  308         }
  309         if (fwmem_debug)
  310                 printf("%s: refcount=%d\n", __func__, fms->refcount);
  311 
  312         return (0);
  313 }
  314 
  315 int
  316 fwmem_close (struct cdev *dev, int flags, int fmt, fw_proc *td)
  317 {
  318         struct fwmem_softc *fms;
  319 
  320         fms = (struct fwmem_softc *)dev->si_drv1;
  321 
  322         FW_GLOCK(fms->sc->fc);
  323         fms->refcount --;
  324         FW_GUNLOCK(fms->sc->fc);
  325         if (fwmem_debug)
  326                 printf("%s: refcount=%d\n", __func__, fms->refcount);
  327         if (fms->refcount < 1) {
  328                 free(dev->si_drv1, M_FWMEM);
  329                 dev->si_drv1 = NULL;
  330         }
  331 
  332         return (0);
  333 }
  334 
  335 
  336 static void
  337 fwmem_biodone(struct fw_xfer *xfer)
  338 {
  339         struct bio *bp;
  340 
  341         bp = (struct bio *)xfer->sc;
  342         bp->bio_error = xfer->resp;
  343 
  344         if (bp->bio_error != 0) {
  345                 if (fwmem_debug)
  346                         printf("%s: err=%d\n", __func__, bp->bio_error);
  347                 bp->bio_flags |= BIO_ERROR;
  348                 bp->bio_resid = bp->bio_bcount;
  349         }
  350 
  351         fw_xfer_free(xfer);
  352         biodone(bp);
  353 }
  354 
  355 void
  356 fwmem_strategy(struct bio *bp)
  357 {
  358         struct fwmem_softc *fms;
  359         struct fw_device *fwdev;
  360         struct fw_xfer *xfer;
  361         struct cdev *dev;
  362         int err=0, s, iolen;
  363 
  364         dev = bp->bio_dev;
  365         /* XXX check request length */
  366 
  367         s = splfw();
  368         fms = (struct fwmem_softc *)dev->si_drv1;
  369         fwdev = fw_noderesolve_eui64(fms->sc->fc, &fms->eui);
  370         if (fwdev == NULL) {
  371                 if (fwmem_debug)
  372                         printf("fwmem: no such device ID:%08x%08x\n",
  373                                         fms->eui.hi, fms->eui.lo);
  374                 err = EINVAL;
  375                 goto error;
  376         }
  377 
  378         iolen = MIN(bp->bio_bcount, MAXLEN);
  379         if ((bp->bio_cmd & BIO_READ) == BIO_READ) {
  380                 if (iolen == 4 && (bp->bio_offset & 3) == 0)
  381                         xfer = fwmem_read_quad(fwdev,
  382                             (void *) bp, fwmem_speed,
  383                             bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
  384                             bp->bio_data, fwmem_biodone);
  385                 else
  386                         xfer = fwmem_read_block(fwdev,
  387                             (void *) bp, fwmem_speed,
  388                             bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
  389                             iolen, bp->bio_data, fwmem_biodone);
  390         } else {
  391                 if (iolen == 4 && (bp->bio_offset & 3) == 0)
  392                         xfer = fwmem_write_quad(fwdev,
  393                             (void *)bp, fwmem_speed,
  394                             bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
  395                             bp->bio_data, fwmem_biodone);
  396                 else
  397                         xfer = fwmem_write_block(fwdev,
  398                             (void *)bp, fwmem_speed,
  399                             bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
  400                             iolen, bp->bio_data, fwmem_biodone);
  401         }
  402         if (xfer == NULL) {
  403                 err = EIO;
  404                 goto error;
  405         }
  406         /* XXX */
  407         bp->bio_resid = bp->bio_bcount - iolen;
  408 error:
  409         splx(s);
  410         if (err != 0) {
  411                 if (fwmem_debug)
  412                         printf("%s: err=%d\n", __func__, err);
  413                 bp->bio_error = err;
  414                 bp->bio_flags |= BIO_ERROR;
  415                 bp->bio_resid = bp->bio_bcount;
  416                 biodone(bp);
  417         }
  418 }
  419 
  420 int
  421 fwmem_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
  422 {
  423         struct fwmem_softc *fms;
  424         int err = 0;
  425 
  426         fms = (struct fwmem_softc *)dev->si_drv1;
  427         switch (cmd) {
  428         case FW_SDEUI64:
  429                 bcopy(data, &fms->eui, sizeof(struct fw_eui64));
  430                 break;
  431         case FW_GDEUI64:
  432                 bcopy(&fms->eui, data, sizeof(struct fw_eui64));
  433                 break;
  434         default:
  435                 err = EINVAL;
  436         }
  437         return(err);
  438 }
  439 int
  440 fwmem_poll (struct cdev *dev, int events, fw_proc *td)
  441 {  
  442         return EINVAL;
  443 }
  444 int
  445 #if defined(__DragonFly__) || __FreeBSD_version < 500102
  446 fwmem_mmap (struct cdev *dev, vm_offset_t offset, int nproto)
  447 #else
  448 fwmem_mmap (struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto)
  449 #endif
  450 {  
  451         return EINVAL;
  452 }

Cache object: 85769aa666cb0f6c8a0671f36020bb66


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