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/ida/ida_eisa.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) 2000 Jonathan Lemon
    3  * Copyright (c) 1999 by Matthew N. Dodd <winter@jurai.net>
    4  * All Rights Reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions, and the following disclaimer,
   11  *    without modification, immediately at the beginning of the file.
   12  * 2. The name of the author may not be used to endorse or promote products
   13  *    derived from this software without specific prior written permission.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD: releng/9.0/sys/dev/ida/ida_eisa.c 166901 2007-02-23 12:19:07Z piso $");
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/kernel.h>
   34 #include <sys/module.h>
   35 #include <sys/bus.h>
   36 
   37 #include <sys/bio.h>
   38 #include <sys/conf.h>
   39 
   40 #include <machine/bus.h>
   41 #include <machine/resource.h>
   42 #include <sys/rman.h>
   43 
   44 #include <geom/geom_disk.h>
   45 
   46 #include <dev/ida/idavar.h>
   47 #include <dev/ida/idareg.h>
   48 
   49 #include <dev/eisa/eisaconf.h>
   50 
   51 #define IDA_EISA_IOPORT_START   0x0c88
   52 #define IDA_EISA_IOPORT_LEN     0x0017
   53 
   54 #define IDA_EISA_IRQ_REG        0x0cc0
   55 #define IDA_EISA_IRQ_MASK       0xf0
   56 #define IDA_EISA_IRQ_15         0x80
   57 #define IDA_EISA_IRQ_14         0x40
   58 #define IDA_EISA_IRQ_11         0x10
   59 #define IDA_EISA_IRQ_10         0x20
   60 
   61 static int
   62 ida_v1_fifo_full(struct ida_softc *ida)
   63 {
   64         u_int8_t status;
   65 
   66         status = ida_inb(ida, R_EISA_SYSTEM_DOORBELL);
   67         return ((status & EISA_CHANNEL_CLEAR) == 0);
   68 }
   69 
   70 static void
   71 ida_v1_submit(struct ida_softc *ida, struct ida_qcb *qcb)
   72 {
   73         u_int16_t size;
   74 
   75         /*
   76          * On these cards, this location is actually for control flags.
   77          * Set them to zero and pass in structure size via an I/O port.
   78          */
   79         size = qcb->hwqcb->hdr.size << 2;
   80         qcb->hwqcb->hdr.size = 0;
   81 
   82         ida_outb(ida, R_EISA_SYSTEM_DOORBELL, EISA_CHANNEL_CLEAR);
   83         ida_outl(ida, R_EISA_LIST_ADDR, qcb->hwqcb_busaddr);
   84         ida_outw(ida, R_EISA_LIST_LEN, size);
   85         ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_BUSY);
   86 }
   87 
   88 static bus_addr_t
   89 ida_v1_done(struct ida_softc *ida)
   90 {
   91         struct ida_hardware_qcb *hwqcb;
   92         bus_addr_t completed;
   93         u_int8_t status;
   94 
   95         if ((ida_inb(ida, R_EISA_SYSTEM_DOORBELL) & EISA_CHANNEL_BUSY) == 0)
   96                 return (0);
   97 
   98         ida_outb(ida, R_EISA_SYSTEM_DOORBELL, EISA_CHANNEL_BUSY);
   99         completed = ida_inl(ida, R_EISA_COMPLETE_ADDR);
  100         status = ida_inb(ida, R_EISA_LIST_STATUS);
  101         ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_CLEAR);
  102 
  103         if (completed != 0) {
  104                 hwqcb = (struct ida_hardware_qcb *)
  105                     ((bus_addr_t)ida->hwqcbs +
  106                     ((completed & ~3) - ida->hwqcb_busaddr));
  107                 hwqcb->req.error = status;
  108         }
  109 
  110         return (completed);
  111 }
  112 
  113 static int
  114 ida_v1_int_pending(struct ida_softc *ida)
  115 {
  116         return (ida_inb(ida, R_EISA_SYSTEM_DOORBELL) & EISA_CHANNEL_BUSY);
  117 }
  118 
  119 static void
  120 ida_v1_int_enable(struct ida_softc *ida, int enable)
  121 {
  122         if (enable) {
  123                 ida_outb(ida, R_EISA_SYSTEM_DOORBELL, ~EISA_CHANNEL_CLEAR);
  124                 ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_BUSY);
  125                 ida_outb(ida, R_EISA_INT_MASK, INT_ENABLE);
  126                 ida_outb(ida, R_EISA_SYSTEM_MASK, INT_ENABLE);
  127                 ida->flags |= IDA_INTERRUPTS;
  128         } else {
  129                 ida_outb(ida, R_EISA_SYSTEM_MASK, INT_DISABLE);
  130                 ida->flags &= ~IDA_INTERRUPTS;
  131         }
  132 }
  133 
  134 static int
  135 ida_v2_fifo_full(struct ida_softc *ida)
  136 {
  137         return (ida_inl(ida, R_CMD_FIFO) == 0);
  138 }
  139 
  140 static void
  141 ida_v2_submit(struct ida_softc *ida, struct ida_qcb *qcb)
  142 {
  143         ida_outl(ida, R_CMD_FIFO, qcb->hwqcb_busaddr);
  144 }
  145 
  146 static bus_addr_t
  147 ida_v2_done(struct ida_softc *ida)
  148 {
  149         return (ida_inl(ida, R_DONE_FIFO));
  150 }
  151 
  152 static int
  153 ida_v2_int_pending(struct ida_softc *ida)
  154 {
  155         return (ida_inl(ida, R_INT_PENDING));
  156 }
  157 
  158 static void
  159 ida_v2_int_enable(struct ida_softc *ida, int enable)
  160 {
  161         if (enable)
  162                 ida->flags |= IDA_INTERRUPTS;
  163         else
  164                 ida->flags &= ~IDA_INTERRUPTS;
  165         ida_outl(ida, R_INT_MASK, enable ? INT_ENABLE : INT_DISABLE);
  166 }
  167 
  168 static struct ida_access ida_v1_access = {
  169         ida_v1_fifo_full,
  170         ida_v1_submit,
  171         ida_v1_done,
  172         ida_v1_int_pending,
  173         ida_v1_int_enable,
  174 };
  175 
  176 static struct ida_access ida_v2_access = {
  177         ida_v2_fifo_full,
  178         ida_v2_submit,
  179         ida_v2_done,
  180         ida_v2_int_pending,
  181         ida_v2_int_enable,
  182 };
  183 
  184 static struct ida_board board_id[] = {
  185         { 0x0e114001, "Compaq IDA controller",
  186             &ida_v1_access, 0 },
  187         { 0x0e114002, "Compaq IDA-2 controller",
  188             &ida_v1_access, 0 },        
  189         { 0x0e114010, "Compaq IAES controller",
  190             &ida_v1_access, 0 },
  191         { 0x0e114020, "Compaq SMART array controller",
  192             &ida_v1_access, 0 },
  193         { 0x0e114030, "Compaq SMART-2/E array controller",
  194             &ida_v2_access, 0 },
  195 
  196         { 0, "", 0, 0 }
  197 };
  198 
  199 static struct   ida_board *ida_eisa_match(eisa_id_t);
  200 static int      ida_eisa_probe(device_t);
  201 static int      ida_eisa_attach(device_t);
  202 
  203 static device_method_t ida_eisa_methods[] = {
  204         DEVMETHOD(device_probe,         ida_eisa_probe),
  205         DEVMETHOD(device_attach,        ida_eisa_attach),
  206         DEVMETHOD(device_detach,        ida_detach),
  207 
  208         { 0, 0 }
  209 };
  210 
  211 static driver_t ida_eisa_driver = {
  212         "ida",
  213         ida_eisa_methods,
  214         sizeof(struct ida_softc)
  215 };
  216 
  217 static devclass_t ida_devclass;
  218 
  219 static struct ida_board *
  220 ida_eisa_match(eisa_id_t id)
  221 {
  222         int i;
  223 
  224         for (i = 0; board_id[i].board; i++)
  225                 if (board_id[i].board == id)
  226                         return (&board_id[i]);
  227         return (NULL);
  228 }
  229 
  230 static int
  231 ida_eisa_probe(device_t dev)
  232 {
  233         struct ida_board        *board;
  234         u_int32_t               io_base;
  235         u_int                   irq = 0;
  236 
  237         board = ida_eisa_match(eisa_get_id(dev));
  238         if (board == NULL)
  239                 return (ENXIO);
  240         device_set_desc(dev, board->desc);
  241 
  242         io_base = (eisa_get_slot(dev) * EISA_SLOT_SIZE);
  243 
  244         switch (IDA_EISA_IRQ_MASK & (inb(IDA_EISA_IRQ_REG + io_base))) {
  245         case IDA_EISA_IRQ_15:
  246                 irq = 15;
  247                 break;
  248         case IDA_EISA_IRQ_14:
  249                 irq = 14;
  250                 break;
  251         case IDA_EISA_IRQ_11:
  252                 irq = 11;
  253                 break;
  254         case IDA_EISA_IRQ_10:
  255                 irq = 10;
  256                 break;
  257         default:
  258                 device_printf(dev, "slot %d, illegal irq setting.\n",
  259                     eisa_get_slot(dev));
  260                 return (ENXIO);
  261         }
  262 
  263         eisa_add_iospace(dev, (io_base + IDA_EISA_IOPORT_START),
  264                          IDA_EISA_IOPORT_LEN, RESVADDR_NONE);
  265 
  266         eisa_add_intr(dev, irq, EISA_TRIGGER_LEVEL);            /* XXX ??? */
  267 
  268         return (0);
  269 }
  270 
  271 static int
  272 ida_eisa_attach(device_t dev)
  273 {
  274         struct ida_softc        *ida;
  275         struct ida_board        *board;
  276         int                     error;
  277         int                     rid;
  278 
  279         ida = device_get_softc(dev);
  280         ida->dev = dev;
  281 
  282         board = ida_eisa_match(eisa_get_id(dev));
  283         ida->cmd = *board->accessor;
  284         ida->flags = board->flags;
  285 
  286         ida->regs_res_type = SYS_RES_IOPORT;
  287         ida->regs_res_id = 0;
  288         ida->regs = bus_alloc_resource_any(dev, ida->regs_res_type,
  289             &ida->regs_res_id, RF_ACTIVE);
  290         if (ida->regs == NULL) {
  291                 device_printf(dev, "can't allocate register resources\n");
  292                 return (ENOMEM);
  293         }
  294 
  295         error = bus_dma_tag_create(
  296                 /* parent       */      NULL,
  297                 /* alignment    */      0,
  298                 /* boundary     */      0,
  299                 /* lowaddr      */      BUS_SPACE_MAXADDR_32BIT,
  300                 /* highaddr     */      BUS_SPACE_MAXADDR,
  301                 /* filter       */      NULL,
  302                 /* filterarg    */      NULL,
  303                 /* maxsize      */      MAXBSIZE,
  304                 /* nsegments    */      IDA_NSEG,
  305                 /* maxsegsize   */      BUS_SPACE_MAXSIZE_32BIT,
  306                 /* flags        */      BUS_DMA_ALLOCNOW,
  307                 /* lockfunc     */      NULL,
  308                 /* lockarg      */      NULL,
  309                 &ida->parent_dmat);
  310 
  311         if (error != 0) {
  312                 device_printf(dev, "can't allocate DMA tag\n");
  313                 ida_free(ida);
  314                 return (ENOMEM);
  315         }
  316 
  317         rid = 0;
  318         ida->irq_res_type = SYS_RES_IRQ;
  319         ida->irq = bus_alloc_resource_any(dev, ida->irq_res_type, &rid,
  320             RF_ACTIVE | RF_SHAREABLE);
  321         if (ida->irq == NULL) {
  322                 ida_free(ida);
  323                 return (ENOMEM);
  324         }
  325 
  326         error = bus_setup_intr(dev, ida->irq, INTR_TYPE_BIO | INTR_ENTROPY,
  327             NULL, ida_intr, ida, &ida->ih);
  328         if (error) {
  329                 device_printf(dev, "can't setup interrupt\n");
  330                 ida_free(ida);
  331                 return (ENOMEM);
  332         }
  333 
  334         error = ida_init(ida);
  335         if (error) {
  336                 ida_free(ida);
  337                 return (error);
  338         }
  339 
  340         ida_attach(ida);
  341         ida->flags |= IDA_ATTACHED;
  342 
  343         return (0);
  344 }
  345 
  346 DRIVER_MODULE(ida, eisa, ida_eisa_driver, ida_devclass, 0, 0);

Cache object: 9ab30ae846cb29e613c7d03c07becaa0


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