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/fdc/fdc_isa.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) 2004 M. Warner Losh.
    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
   13  *    the documentation and/or other materials provided with the
   14  *    distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/5.3/sys/dev/fdc/fdc_isa.c 137024 2004-10-28 19:40:40Z imp $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/bio.h>
   34 #include <sys/bus.h>
   35 #include <sys/kernel.h>
   36 #include <sys/lock.h>
   37 #include <sys/module.h>
   38 #include <sys/mutex.h>
   39 #include <sys/rman.h>
   40 #include <sys/systm.h>
   41 
   42 #include <machine/bus.h>
   43 
   44 #include <dev/fdc/fdcvar.h>
   45 
   46 #include <isa/isavar.h>
   47 #include <isa/isareg.h>
   48 
   49 static int fdc_isa_probe(device_t);
   50 
   51 static struct isa_pnp_id fdc_ids[] = {
   52         {0x0007d041, "PC standard floppy disk controller"}, /* PNP0700 */
   53         {0x0107d041, "Standard floppy controller supporting MS Device Bay Spec"}, /* PNP0701 */
   54         {0}
   55 };
   56 
   57 int
   58 fdc_isa_alloc_resources(device_t dev, struct fdc_data *fdc)
   59 {
   60         int nports = 6;
   61 
   62         fdc->fdc_dev = dev;
   63         fdc->rid_ioport = 0;
   64         fdc->rid_irq = 0;
   65         fdc->rid_drq = 0;
   66         fdc->rid_ctl = 1;
   67 
   68         /*
   69          * On standard ISA, we don't just use an 8 port range
   70          * (e.g. 0x3f0-0x3f7) since that covers an IDE control
   71          * register at 0x3f6.  So, on older hardware, we use
   72          * 0x3f0-0x3f5 and 0x3f7.  However, some BIOSs omit the
   73          * control port, while others start at 0x3f2.  Of the latter,
   74          * sometimes we have two resources, other times we have one.
   75          * We have to deal with the following cases:
   76          *
   77          * 1:   0x3f0-0x3f5                     # very rare
   78          * 2:   0x3f0                           # hints -> 0x3f0-0x3f5,0x3f7
   79          * 3:   0x3f0-0x3f5,0x3f7               # Most common
   80          * 4:   0x3f2-0x3f5,0x3f7               # Second most common
   81          * 5:   0x3f2-0x3f5                     # implies 0x3f7 too.
   82          * 6:   0x3f2-0x3f3,0x3f4-0x3f5,0x3f7   # becoming common
   83          * 7:   0x3f2-0x3f3,0x3f4-0x3f5         # rare
   84          * 8:   0x3f0-0x3f1,0x3f2-0x3f3,0x3f4-0x3f5,0x3f7
   85          * 9:   0x3f0-0x3f3,0x3f4-0x3f5,0x3f7
   86          *
   87          * The following code is generic for any value of 0x3fx :-)
   88          */
   89 
   90         /*
   91          * First, allocated the main range of ports.  In the best of
   92          * worlds, this is 4 or 6 ports.  In others, well, that's
   93          * why this function is so complicated.
   94          */
   95 again_ioport:
   96         fdc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT,
   97             &fdc->rid_ioport, 0ul, ~0ul, nports, RF_ACTIVE);
   98         if (fdc->res_ioport == 0) {
   99                 device_printf(dev, "cannot allocate I/O port (%d ports)\n",
  100                     nports);
  101                 return (ENXIO);
  102         }
  103         if ((rman_get_end(fdc->res_ioport) & 0x7) == 1) {
  104                 /* Case 8 */
  105                 bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ioport,
  106                     fdc->res_ioport);
  107                 fdc->rid_ioport++;
  108                 goto again_ioport;
  109         }
  110         fdc->portt = rman_get_bustag(fdc->res_ioport);
  111         fdc->porth = rman_get_bushandle(fdc->res_ioport);
  112 
  113         /*
  114          * Handle cases 4-8 above
  115          */
  116         fdc->port_off = -(fdc->porth & 0x7);
  117 
  118         /*
  119          * Deal with case 6-9: FDSTS and FDDATA.
  120          */
  121         if ((rman_get_end(fdc->res_ioport) & 0x7) == 3) {
  122                 fdc->rid_sts = fdc->rid_ioport + 1;
  123                 fdc->res_sts = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
  124                     &fdc->rid_sts, RF_ACTIVE);
  125                 if (fdc->res_sts == NULL) {
  126                         device_printf(dev, "Can't alloc rid 1");
  127                         fdc_release_resources(fdc);
  128                         return (ENXIO);
  129                 }
  130                 fdc->sts_off = -4;
  131                 fdc->stst = rman_get_bustag(fdc->res_sts);
  132                 fdc->stsh = rman_get_bushandle(fdc->res_sts);
  133         } else {
  134                 fdc->res_sts = NULL;
  135                 fdc->sts_off = fdc->port_off;
  136                 fdc->stst = fdc->portt;
  137                 fdc->stsh = fdc->porth;
  138         }
  139 
  140         /*
  141          * allocate the control port.  For cases 1, 2, 5 and 7, we
  142          * fake it from the ioports resource.  XXX IS THIS THE RIGHT THING
  143          * TO DO, OR SHOULD WE CREATE A NEW RID? (I think we need a new rid)
  144          */
  145         fdc->rid_ctl = fdc->rid_sts + 1;
  146         fdc->res_ctl = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
  147             &fdc->rid_ctl, RF_ACTIVE);
  148         if (fdc->res_ctl == NULL) {
  149                 fdc->ctl_off = 7 + fdc->port_off;
  150                 fdc->res_ctl = NULL;
  151                 fdc->ctlt = fdc->portt;
  152                 fdc->ctlh = fdc->porth;
  153         } else {
  154                 fdc->ctl_off = 0;
  155                 fdc->ctlt = rman_get_bustag(fdc->res_ctl);
  156                 fdc->ctlh = rman_get_bushandle(fdc->res_ctl);
  157         }
  158 
  159         fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq,
  160             RF_ACTIVE | RF_SHAREABLE);
  161         if (fdc->res_irq == 0) {
  162                 device_printf(dev, "cannot reserve interrupt line\n");
  163                 return (ENXIO);
  164         }
  165 
  166         if ((fdc->flags & FDC_NODMA) == 0) {
  167                 fdc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ,
  168                     &fdc->rid_drq, RF_ACTIVE | RF_SHAREABLE);
  169                 if (fdc->res_drq == 0) {
  170                         device_printf(dev, "cannot reserve DMA request line\n");
  171                         /* This is broken and doesn't work for ISA case */
  172                         fdc->flags |= FDC_NODMA;
  173                 } else
  174                         fdc->dmachan = rman_get_start(fdc->res_drq);
  175         }
  176 
  177         return (0);
  178 }
  179 
  180 static int
  181 fdc_isa_probe(device_t dev)
  182 {
  183         int     error;
  184         struct  fdc_data *fdc;
  185 
  186         fdc = device_get_softc(dev);
  187         fdc->fdc_dev = dev;
  188 
  189         /* Check pnp ids */
  190         error = ISA_PNP_PROBE(device_get_parent(dev), dev, fdc_ids);
  191         if (error == ENXIO)
  192                 return (ENXIO);
  193 
  194         /* Attempt to allocate our resources for the duration of the probe */
  195         error = fdc_isa_alloc_resources(dev, fdc);
  196         if (error == 0)
  197                 error = fdc_initial_reset(dev, fdc);
  198 
  199         fdc_release_resources(fdc);
  200         return (error);
  201 }
  202 
  203 static int
  204 fdc_isa_attach(device_t dev)
  205 {
  206         struct  fdc_data *fdc;
  207         int error;
  208 
  209         fdc = device_get_softc(dev);
  210         error = fdc_isa_alloc_resources(dev, fdc);
  211         if (error == 0)
  212                 error = fdc_attach(dev);
  213         if (error == 0)
  214                 error = fdc_hints_probe(dev);
  215         if (error)
  216                 fdc_release_resources(fdc);
  217         return (error);
  218 }
  219 
  220 static device_method_t fdc_methods[] = {
  221         /* Device interface */
  222         DEVMETHOD(device_probe,         fdc_isa_probe),
  223         DEVMETHOD(device_attach,        fdc_isa_attach),
  224         DEVMETHOD(device_detach,        fdc_detach),
  225         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  226         DEVMETHOD(device_suspend,       bus_generic_suspend),
  227         DEVMETHOD(device_resume,        bus_generic_resume),
  228 
  229         /* Bus interface */
  230         DEVMETHOD(bus_print_child,      fdc_print_child),
  231         DEVMETHOD(bus_read_ivar,        fdc_read_ivar),
  232         DEVMETHOD(bus_write_ivar,       fdc_write_ivar),
  233         /* Our children never use any other bus interface methods. */
  234 
  235         { 0, 0 }
  236 };
  237 
  238 static driver_t fdc_driver = {
  239         "fdc",
  240         fdc_methods,
  241         sizeof(struct fdc_data)
  242 };
  243 
  244 DRIVER_MODULE(fdc, isa, fdc_driver, fdc_devclass, 0, 0);

Cache object: 501964e233b8ac001f98a8f5b9733a0a


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