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/ata/ata-cbus.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 - 2008 Søren Schmidt <sos@FreeBSD.org>
    3  * 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  *    without modification, immediately at the beginning of the file.
   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  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/8.4/sys/dev/ata/ata-cbus.c 233718 2012-03-30 23:56:19Z marius $");
   29 
   30 #include "opt_ata.h"
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/kernel.h>
   34 #include <sys/ata.h>
   35 #include <sys/bus.h>
   36 #include <sys/malloc.h>
   37 #include <sys/module.h>
   38 #include <sys/conf.h>
   39 #include <sys/sema.h>
   40 #include <sys/taskqueue.h>
   41 #include <vm/uma.h>
   42 #include <machine/resource.h>
   43 #include <machine/bus.h>
   44 #include <sys/rman.h>
   45 #include <isa/isavar.h>
   46 #include <dev/ata/ata-all.h>
   47 #include <ata_if.h>
   48 
   49 /* local vars */
   50 struct ata_cbus_controller {
   51     struct resource *io;
   52     struct resource *ctlio;
   53     struct resource *bankio;
   54     struct resource *irq;
   55     void *ih;
   56     struct mtx bank_mtx;
   57     int locked_bank;
   58     int restart_bank;
   59     int hardware_bank;
   60     struct {
   61         void (*function)(void *);
   62         void *argument;
   63     } interrupt[2];
   64 };
   65 
   66 /* local prototypes */
   67 static void ata_cbus_intr(void *);
   68 static int ata_cbuschannel_banking(device_t dev, int flags);
   69 
   70 static int
   71 ata_cbus_probe(device_t dev)
   72 {
   73     struct resource *io;
   74     int rid;
   75     u_long tmp;
   76 
   77     /* dont probe PnP devices */
   78     if (isa_get_vendorid(dev))
   79         return (ENXIO);
   80 
   81     /* allocate the ioport range */
   82     rid = ATA_IOADDR_RID;
   83     if (!(io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
   84                                   ATA_PC98_IOSIZE, RF_ACTIVE)))
   85         return ENOMEM;
   86 
   87     /* calculate & set the altport range */
   88     rid = ATA_PC98_CTLADDR_RID;
   89     if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &tmp, &tmp)) {
   90         bus_set_resource(dev, SYS_RES_IOPORT, rid,
   91                          rman_get_start(io)+ATA_PC98_CTLOFFSET, ATA_CTLIOSIZE);
   92     }
   93 
   94     /* calculate & set the bank range */
   95     rid = ATA_PC98_BANKADDR_RID;
   96     if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &tmp, &tmp)) {
   97         bus_set_resource(dev, SYS_RES_IOPORT, rid,
   98                          ATA_PC98_BANK, ATA_PC98_BANKIOSIZE);
   99     }
  100 
  101     bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io);
  102     return 0;
  103 }
  104 
  105 static int
  106 ata_cbus_attach(device_t dev)
  107 {
  108     struct ata_cbus_controller *ctlr = device_get_softc(dev);
  109     device_t child;
  110     int rid, unit;
  111 
  112     /* allocate resources */
  113     rid = ATA_IOADDR_RID;
  114     if (!(ctlr->io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
  115                                         ATA_PC98_IOSIZE, RF_ACTIVE)))
  116        return ENOMEM;
  117 
  118     rid = ATA_PC98_CTLADDR_RID;
  119     if (!(ctlr->ctlio = 
  120           bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
  121                              rman_get_start(ctlr->io) + ATA_PC98_CTLOFFSET, ~0,
  122                              ATA_CTLIOSIZE, RF_ACTIVE))) {
  123         bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, ctlr->io);
  124         return ENOMEM;
  125     }
  126 
  127     rid = ATA_PC98_BANKADDR_RID;
  128     if (!(ctlr->bankio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
  129                                             ATA_PC98_BANK, ~0,
  130                                             ATA_PC98_BANKIOSIZE, RF_ACTIVE))) {
  131         bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, ctlr->io);
  132         bus_release_resource(dev, SYS_RES_IOPORT, ATA_CTLADDR_RID, ctlr->ctlio);
  133         return ENOMEM;
  134     }
  135 
  136     rid = ATA_IRQ_RID;
  137     if (!(ctlr->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  138                                              RF_ACTIVE | RF_SHAREABLE))) {
  139         device_printf(dev, "unable to alloc interrupt\n");
  140         bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, ctlr->io);
  141         bus_release_resource(dev, SYS_RES_IOPORT, ATA_CTLADDR_RID, ctlr->ctlio);
  142         bus_release_resource(dev, SYS_RES_IOPORT, 
  143                              ATA_PC98_BANKADDR_RID, ctlr->bankio);
  144         return ENXIO;
  145     }
  146 
  147     if ((bus_setup_intr(dev, ctlr->irq, ATA_INTR_FLAGS,
  148                         NULL, ata_cbus_intr, ctlr, &ctlr->ih))) {
  149         device_printf(dev, "unable to setup interrupt\n");
  150         bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, ctlr->io);
  151         bus_release_resource(dev, SYS_RES_IOPORT, ATA_CTLADDR_RID, ctlr->ctlio);
  152         bus_release_resource(dev, SYS_RES_IOPORT, 
  153                              ATA_PC98_BANKADDR_RID, ctlr->bankio);
  154         bus_release_resource(dev, SYS_RES_IOPORT, ATA_IRQ_RID, ctlr->irq);
  155         return ENXIO;
  156     }
  157 
  158     mtx_init(&ctlr->bank_mtx, "ATA cbus bank lock", NULL, MTX_DEF);
  159     ctlr->hardware_bank = -1;
  160     ctlr->locked_bank = -1;
  161     ctlr->restart_bank = -1;
  162 
  163     for (unit = 0; unit < 2; unit++) {
  164         child = device_add_child(dev, "ata", unit);
  165         if (child == NULL)
  166             device_printf(dev, "failed to add ata child device\n");
  167         else
  168             device_set_ivars(child, (void *)(intptr_t)unit);
  169     }
  170 
  171     bus_generic_attach(dev);
  172     return (0);
  173 }
  174 
  175 static struct resource *
  176 ata_cbus_alloc_resource(device_t dev, device_t child, int type, int *rid,
  177                         u_long start, u_long end, u_long count, u_int flags)
  178 {
  179     struct ata_cbus_controller *ctlr = device_get_softc(dev);
  180 
  181     if (type == SYS_RES_IOPORT) {
  182         switch (*rid) {
  183         case ATA_IOADDR_RID:
  184             return ctlr->io;
  185         case ATA_CTLADDR_RID:
  186             return ctlr->ctlio;
  187         }
  188     }
  189     if (type == SYS_RES_IRQ)
  190         return ctlr->irq;
  191     return 0;
  192 }
  193 
  194 static int
  195 ata_cbus_setup_intr(device_t dev, device_t child, struct resource *irq,
  196                int flags, driver_filter_t *filter, driver_intr_t *intr, 
  197                void *arg, void **cookiep)
  198 {
  199     struct ata_cbus_controller *controller = device_get_softc(dev);
  200     int unit = ((struct ata_channel *)device_get_softc(child))->unit;
  201 
  202     if (filter != NULL) {
  203             printf("ata-cbus.c: we cannot use a filter here\n");
  204             return (EINVAL);
  205     }
  206     controller->interrupt[unit].function = intr;
  207     controller->interrupt[unit].argument = arg;
  208     *cookiep = controller;
  209 
  210     return 0;
  211 }
  212 
  213 static int
  214 ata_cbus_print_child(device_t dev, device_t child)
  215 {
  216     struct ata_channel *ch = device_get_softc(child);
  217     int retval = 0;
  218 
  219     retval += bus_print_child_header(dev, child);
  220     retval += printf(" at bank %d", ch->unit);
  221     retval += bus_print_child_footer(dev, child);
  222     return retval;
  223 }
  224 
  225 static void
  226 ata_cbus_intr(void *data)
  227 {  
  228     struct ata_cbus_controller *ctlr = data;
  229     struct ata_channel *ch;
  230     int unit;
  231 
  232     for (unit = 0; unit < 2; unit++) {
  233         if (!(ch = ctlr->interrupt[unit].argument))
  234             continue;
  235         if (ata_cbuschannel_banking(ch->dev, ATA_LF_WHICH) == unit)
  236             ctlr->interrupt[unit].function(ch);
  237     }
  238 }
  239 
  240 static device_method_t ata_cbus_methods[] = {
  241     /* device interface */
  242     DEVMETHOD(device_probe,             ata_cbus_probe),
  243     DEVMETHOD(device_attach,            ata_cbus_attach),
  244 //  DEVMETHOD(device_detach,            ata_cbus_detach),
  245 
  246     /* bus methods */
  247     DEVMETHOD(bus_alloc_resource,       ata_cbus_alloc_resource),
  248     DEVMETHOD(bus_setup_intr,           ata_cbus_setup_intr),
  249     DEVMETHOD(bus_print_child,          ata_cbus_print_child),
  250 
  251     DEVMETHOD_END
  252 };
  253 
  254 static driver_t ata_cbus_driver = {
  255     "atacbus",
  256     ata_cbus_methods,
  257     sizeof(struct ata_cbus_controller),
  258 };
  259 
  260 static devclass_t ata_cbus_devclass;
  261 
  262 DRIVER_MODULE(atacbus, isa, ata_cbus_driver, ata_cbus_devclass, 0, 0);
  263 
  264 static int
  265 ata_cbuschannel_probe(device_t dev)
  266 {
  267     char buffer[32];
  268 
  269     sprintf(buffer, "ATA channel %d", (int)(intptr_t)device_get_ivars(dev));
  270     device_set_desc_copy(dev, buffer);
  271 
  272     return ata_probe(dev);
  273 }
  274 
  275 static int
  276 ata_cbuschannel_attach(device_t dev)
  277 {
  278     struct ata_cbus_controller *ctlr = device_get_softc(device_get_parent(dev));
  279     struct ata_channel *ch = device_get_softc(dev);
  280     int i;
  281 
  282     if (ch->attached)
  283         return (0);
  284     ch->attached = 1;
  285 
  286     ch->unit = (intptr_t)device_get_ivars(dev);
  287     /* setup the resource vectors */
  288     for (i = ATA_DATA; i <= ATA_COMMAND; i ++) {
  289         ch->r_io[i].res = ctlr->io;
  290         ch->r_io[i].offset = i << 1;
  291     }
  292     ch->r_io[ATA_CONTROL].res = ctlr->ctlio;
  293     ch->r_io[ATA_CONTROL].offset = 0;
  294     ch->r_io[ATA_IDX_ADDR].res = ctlr->io;
  295     ata_default_registers(dev);
  296 
  297     /* initialize softc for this channel */
  298     ch->flags |= ATA_USE_16BIT;
  299     ata_generic_hw(dev);
  300 
  301     return ata_attach(dev);
  302 }
  303 
  304 static int
  305 ata_cbuschannel_detach(device_t dev)
  306 {
  307     struct ata_channel *ch = device_get_softc(dev);
  308 
  309     if (!ch->attached)
  310         return (0);
  311     ch->attached = 0;
  312 
  313     return ata_detach(dev);
  314 }
  315 
  316 static int
  317 ata_cbuschannel_suspend(device_t dev)
  318 {
  319     struct ata_channel *ch = device_get_softc(dev);
  320 
  321     if (!ch->attached)
  322         return (0);
  323 
  324     return ata_suspend(dev);
  325 }
  326 
  327 static int
  328 ata_cbuschannel_resume(device_t dev)
  329 {
  330     struct ata_channel *ch = device_get_softc(dev);
  331 
  332     if (!ch->attached)
  333         return (0);
  334 
  335     return ata_resume(dev);
  336 }
  337 
  338 static int
  339 ata_cbuschannel_banking(device_t dev, int flags)
  340 {
  341     struct ata_cbus_controller *ctlr = device_get_softc(device_get_parent(dev));
  342 #ifndef ATA_CAM
  343     struct ata_channel *ch = device_get_softc(dev);
  344 #endif
  345     int res;
  346 
  347     mtx_lock(&ctlr->bank_mtx);
  348     switch (flags) {
  349 #ifndef ATA_CAM
  350     case ATA_LF_LOCK:
  351         if (ctlr->locked_bank == -1)
  352             ctlr->locked_bank = ch->unit;
  353         if (ctlr->locked_bank == ch->unit) {
  354             ctlr->hardware_bank = ch->unit;
  355             ATA_OUTB(ctlr->bankio, 0, ch->unit);
  356         }
  357         else
  358             ctlr->restart_bank = ch->unit;
  359         break;
  360 
  361     case ATA_LF_UNLOCK:
  362         if (ctlr->locked_bank == ch->unit) {
  363             ctlr->locked_bank = -1;
  364             if (ctlr->restart_bank != -1) {
  365                 if ((ch = ctlr->interrupt[ctlr->restart_bank].argument)) {
  366                     ctlr->restart_bank = -1;
  367                     mtx_unlock(&ctlr->bank_mtx);
  368                     ata_start(ch->dev);
  369                     return -1;
  370                 }
  371             }
  372         }
  373         break;
  374 #endif
  375 
  376     case ATA_LF_WHICH:
  377         break;
  378     }
  379     res = ctlr->locked_bank;
  380     mtx_unlock(&ctlr->bank_mtx);
  381     return res;
  382 }
  383 
  384 static device_method_t ata_cbuschannel_methods[] = {
  385     /* device interface */
  386     DEVMETHOD(device_probe,     ata_cbuschannel_probe),
  387     DEVMETHOD(device_attach,    ata_cbuschannel_attach),
  388     DEVMETHOD(device_detach,    ata_cbuschannel_detach),
  389     DEVMETHOD(device_suspend,   ata_cbuschannel_suspend),
  390     DEVMETHOD(device_resume,    ata_cbuschannel_resume),
  391 
  392 #ifndef ATA_CAM
  393     /* ATA methods */
  394     DEVMETHOD(ata_locking,      ata_cbuschannel_banking),
  395 #endif
  396     DEVMETHOD_END
  397 };
  398 
  399 static driver_t ata_cbuschannel_driver = {
  400     "ata",
  401     ata_cbuschannel_methods,
  402     sizeof(struct ata_channel),
  403 };
  404 
  405 DRIVER_MODULE(ata, atacbus, ata_cbuschannel_driver, ata_devclass, NULL, NULL);
  406 MODULE_DEPEND(ata, ata, 1, 1, 1);

Cache object: 56c6c9f05d18cca890313d29fec025c2


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