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

Cache object: e3f401b11b4135847542563ef8ce000f


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