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 - 2004 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  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include "opt_ata.h"
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/kernel.h>
   36 #include <sys/ata.h>
   37 #include <sys/bus.h>
   38 #include <sys/malloc.h>
   39 #include <sys/module.h>
   40 #include <sys/conf.h>
   41 #include <sys/sema.h>
   42 #include <sys/taskqueue.h>
   43 #include <vm/uma.h>
   44 #include <machine/resource.h>
   45 #include <machine/bus.h>
   46 #include <sys/rman.h>
   47 #include <isa/isavar.h>
   48 #include <dev/ata/ata-all.h>
   49 
   50 /* local vars */
   51 struct ata_cbus_controller {
   52     struct resource *io;
   53     struct resource *altio;
   54     struct resource *bankio;
   55     struct resource *irq;
   56     void *ih;
   57     void (*setmode)(struct ata_device *, int);
   58     int (*locking)(struct ata_channel *, int);
   59     struct mtx bank_mtx;
   60     int current_bank;
   61     int restart_bank;
   62     struct {
   63         void (*function)(void *);
   64         void *argument;
   65     } interrupt[2];
   66 };
   67 
   68 /* local prototypes */
   69 static void ata_cbus_intr(void *);
   70 static int ata_cbus_banking(struct ata_channel *, int);
   71 static void ata_cbus_setmode(struct ata_device *, int);
   72 
   73 static int
   74 ata_cbus_probe(device_t dev)
   75 {
   76     struct resource *io;
   77     int rid;
   78     u_long tmp;
   79 
   80     /* dont probe PnP devices */
   81     if (isa_get_vendorid(dev))
   82         return (ENXIO);
   83 
   84     /* allocate the ioport range */
   85     rid = ATA_IOADDR_RID;
   86     io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
   87                             ATA_PC98_IOSIZE, RF_ACTIVE);
   88     if (!io)
   89         return ENOMEM;
   90 
   91     /* calculate & set the altport range */
   92     rid = ATA_PC98_ALTADDR_RID;
   93     if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &tmp, &tmp)) {
   94         bus_set_resource(dev, SYS_RES_IOPORT, rid,
   95                          rman_get_start(io)+ATA_PC98_ALTOFFSET, ATA_ALTIOSIZE);
   96     }
   97 
   98     /* calculate & set the bank range */
   99     rid = ATA_PC98_BANKADDR_RID;
  100     if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &tmp, &tmp)) {
  101         bus_set_resource(dev, SYS_RES_IOPORT, rid,
  102                          ATA_PC98_BANK, ATA_PC98_BANKIOSIZE);
  103     }
  104 
  105     bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io);
  106     return 0;
  107 }
  108 
  109 static int
  110 ata_cbus_attach(device_t dev)
  111 {
  112     struct ata_cbus_controller *ctlr = device_get_softc(dev);
  113     int rid;
  114 
  115     /* allocate resources */
  116     rid = ATA_IOADDR_RID;
  117     ctlr->io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
  118                                   ATA_PC98_IOSIZE, RF_ACTIVE);
  119     if (!ctlr->io)
  120        return ENOMEM;
  121 
  122     rid = ATA_PC98_ALTADDR_RID;
  123     ctlr->altio = 
  124         bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
  125                            rman_get_start(ctlr->io) + ATA_PC98_ALTOFFSET, ~0,
  126                            ATA_ALTIOSIZE, RF_ACTIVE);
  127     if (!ctlr->altio) {
  128         bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, ctlr->io);
  129         return ENOMEM;
  130     }
  131 
  132     rid = ATA_PC98_BANKADDR_RID;
  133     ctlr->bankio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
  134                                       ATA_PC98_BANK, ~0,
  135                                       ATA_PC98_BANKIOSIZE, RF_ACTIVE);
  136     if (!ctlr->bankio) {
  137         bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, ctlr->io);
  138         bus_release_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID, ctlr->altio);
  139         return ENOMEM;
  140     }
  141 
  142     rid = ATA_IRQ_RID;
  143     if (!(ctlr->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  144                                              RF_ACTIVE | RF_SHAREABLE))) {
  145         device_printf(dev, "unable to alloc interrupt\n");
  146         bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, ctlr->io);
  147         bus_release_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID, ctlr->altio);
  148         bus_release_resource(dev, SYS_RES_IOPORT, 
  149                              ATA_PC98_BANKADDR_RID, ctlr->bankio);
  150         return ENXIO;
  151     }
  152 
  153     if ((bus_setup_intr(dev, ctlr->irq, ATA_INTR_FLAGS,
  154                         ata_cbus_intr, ctlr, &ctlr->ih))) {
  155         device_printf(dev, "unable to setup interrupt\n");
  156         bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, ctlr->io);
  157         bus_release_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID, ctlr->altio);
  158         bus_release_resource(dev, SYS_RES_IOPORT, 
  159                              ATA_PC98_BANKADDR_RID, ctlr->bankio);
  160         bus_release_resource(dev, SYS_RES_IOPORT, ATA_IRQ_RID, ctlr->irq);
  161         return ENXIO;
  162     }
  163 
  164     mtx_init(&ctlr->bank_mtx, "ATA cbus bank lock", NULL, MTX_DEF);
  165     ctlr->current_bank = -1;
  166     ctlr->restart_bank = -1;
  167     ctlr->locking = ata_cbus_banking;
  168     ctlr->setmode = ata_cbus_setmode;;
  169 
  170     if (!device_add_child(dev, "ata", 0))
  171         return ENOMEM;
  172     if (!device_add_child(dev, "ata", 1))
  173         return ENOMEM;
  174 
  175     return bus_generic_attach(dev);
  176 }
  177 
  178 static struct resource *
  179 ata_cbus_alloc_resource(device_t dev, device_t child, int type, int *rid,
  180                         u_long start, u_long end, u_long count, u_int flags)
  181 {
  182     struct ata_cbus_controller *ctlr = device_get_softc(dev);
  183 
  184     if (type == SYS_RES_IOPORT) {
  185         switch (*rid) {
  186         case ATA_IOADDR_RID:
  187             return ctlr->io;
  188         case ATA_ALTADDR_RID:
  189             return ctlr->altio;
  190         }
  191     }
  192     if (type == SYS_RES_IRQ)
  193         return ctlr->irq;
  194     return 0;
  195 }
  196 
  197 static int
  198 ata_cbus_setup_intr(device_t dev, device_t child, struct resource *irq,
  199                int flags, driver_intr_t *intr, void *arg,
  200                void **cookiep)
  201 {
  202     struct ata_cbus_controller *controller = device_get_softc(dev);
  203     int unit = ((struct ata_channel *)device_get_softc(child))->unit;
  204 
  205     controller->interrupt[unit].function = intr;
  206     controller->interrupt[unit].argument = arg;
  207     *cookiep = controller;
  208 
  209     return 0;
  210 }
  211 
  212 static int
  213 ata_cbus_print_child(device_t dev, device_t child)
  214 {
  215     struct ata_channel *ch = device_get_softc(child);
  216     int retval = 0;
  217 
  218     retval += bus_print_child_header(dev, child);
  219     retval += printf(" at bank %d", ch->unit);
  220     retval += bus_print_child_footer(dev, child);
  221     return retval;
  222 }
  223 
  224 static void
  225 ata_cbus_intr(void *data)
  226 {  
  227     struct ata_cbus_controller *ctlr = data;
  228     struct ata_channel *ch;
  229     int unit;
  230 
  231     for (unit = 0; unit < 2; unit++) {
  232         if (!(ch = ctlr->interrupt[unit].argument))
  233             continue;
  234         if (ch->locking(ch, ATA_LF_WHICH) == unit)
  235             ctlr->interrupt[unit].function(ch);
  236     }
  237 }
  238 
  239 static int
  240 ata_cbus_banking(struct ata_channel *ch, int flags)
  241 {
  242     struct ata_cbus_controller *ctlr =
  243         device_get_softc(device_get_parent(ch->dev));
  244     int res;
  245 
  246     mtx_lock(&ctlr->bank_mtx);
  247     switch (flags) {
  248     case ATA_LF_LOCK:
  249         if (ctlr->current_bank == -1)
  250             ctlr->current_bank = ch->unit;
  251         if (ctlr->current_bank == ch->unit)
  252             ATA_OUTB(ctlr->bankio, 0, ch->unit);
  253         else
  254             ctlr->restart_bank = ch->unit;
  255         break;
  256 
  257     case ATA_LF_UNLOCK:
  258         if (ctlr->current_bank == ch->unit) {
  259             ctlr->current_bank = -1;
  260             if (ctlr->restart_bank != -1) {
  261                 if (ctlr->interrupt[ctlr->restart_bank].argument) {
  262                     mtx_unlock(&ctlr->bank_mtx);
  263                     ata_start(ctlr->interrupt[ctlr->restart_bank].argument);
  264                     mtx_lock(&ctlr->bank_mtx);
  265                 }
  266                 ctlr->restart_bank = -1;
  267             }
  268         }
  269         break;
  270 
  271     case ATA_LF_WHICH:
  272         break;
  273     }
  274     res = ctlr->current_bank;
  275     mtx_unlock(&ctlr->bank_mtx);
  276     return res;
  277 }
  278 
  279 static void
  280 ata_cbus_setmode(struct ata_device *atadev, int mode)
  281 {
  282     atadev->mode = ata_limit_mode(atadev, mode, ATA_PIO_MAX);
  283 }
  284 
  285 static device_method_t ata_cbus_methods[] = {
  286     /* device_interface */
  287     DEVMETHOD(device_probe,     ata_cbus_probe),
  288     DEVMETHOD(device_attach,    ata_cbus_attach),
  289 
  290     /* bus methods */
  291     DEVMETHOD(bus_alloc_resource,       ata_cbus_alloc_resource),
  292     DEVMETHOD(bus_setup_intr,           ata_cbus_setup_intr),
  293     DEVMETHOD(bus_print_child,          ata_cbus_print_child),
  294     { 0, 0 }
  295 };
  296 
  297 static driver_t ata_cbus_driver = {
  298     "atacbus",
  299     ata_cbus_methods,
  300     sizeof(struct ata_cbus_controller),
  301 };
  302 
  303 static devclass_t ata_cbus_devclass;
  304 
  305 DRIVER_MODULE(atacbus, isa, ata_cbus_driver, ata_cbus_devclass, 0, 0);
  306 
  307 static int
  308 ata_cbussub_probe(device_t dev)
  309 {
  310     struct ata_cbus_controller *ctlr = device_get_softc(device_get_parent(dev));
  311     struct ata_channel *ch = device_get_softc(dev);
  312     device_t *children;
  313     int count, i;
  314 
  315     /* find channel number on this controller */
  316     device_get_children(device_get_parent(dev), &children, &count);
  317     for (i = 0; i < count; i++) {
  318         if (children[i] == dev) 
  319             ch->unit = i;
  320     }
  321     free(children, M_TEMP);
  322 
  323     /* setup the resource vectors */
  324     for (i = ATA_DATA; i <= ATA_STATUS; i ++) {
  325         ch->r_io[i].res = ctlr->io;
  326         ch->r_io[i].offset = i << 1;
  327     }
  328     ch->r_io[ATA_ALTSTAT].res = ctlr->altio;
  329     ch->r_io[ATA_ALTSTAT].offset = 0;
  330 
  331     /* initialize softc for this channel */
  332     ch->flags |= ATA_USE_16BIT | ATA_USE_PC98GEOM;
  333     ch->locking = ctlr->locking;
  334     ch->device[MASTER].setmode = ctlr->setmode;
  335     ch->device[SLAVE].setmode = ctlr->setmode;
  336     ata_generic_hw(ch);
  337     return ata_probe(dev);
  338 }
  339 
  340 static device_method_t ata_cbussub_methods[] = {
  341     /* device interface */
  342     DEVMETHOD(device_probe,     ata_cbussub_probe),
  343     DEVMETHOD(device_attach,    ata_attach),
  344     DEVMETHOD(device_detach,    ata_detach),
  345     DEVMETHOD(device_resume,    ata_resume),
  346     { 0, 0 }
  347 };
  348 
  349 static driver_t ata_cbussub_driver = {
  350     "ata",
  351     ata_cbussub_methods,
  352     sizeof(struct ata_channel),
  353 };
  354 
  355 DRIVER_MODULE(ata, atacbus, ata_cbussub_driver, ata_devclass, 0, 0);

Cache object: 7d86b3efbd2ea631462a5b8ff337c3a4


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