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/pccard/pccard.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  *      pccard.c - Interface code for PC-CARD controllers.
    3  *
    4  *      June 1995, Andrew McRae (andrew@mega.com.au)
    5  *-------------------------------------------------------------------------
    6  *
    7  * Copyright (c) 1995 Andrew McRae.  All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. The name of the author may not be used to endorse or promote products
   18  *    derived from this software without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/kernel.h>
   35 #include <sys/fcntl.h>
   36 #include <sys/proc.h>
   37 #include <sys/malloc.h>
   38 #include <sys/sysctl.h>
   39 #include <sys/conf.h>
   40 #ifdef DEVFS
   41 #include <sys/devfsext.h>
   42 #endif /*DEVFS*/
   43 #include <sys/uio.h>
   44 
   45 #include <i386/isa/isa_device.h>
   46 #include <i386/isa/icu.h>
   47 
   48 #include "apm.h"
   49 #if     NAPM > 0
   50 #include <machine/apm_bios.h>
   51 #endif  /* NAPM > 0 */
   52 
   53 #include <pccard/cardinfo.h>
   54 #include <pccard/driver.h>
   55 #include <pccard/slot.h>
   56 
   57 #include <machine/md_var.h>
   58 
   59 /*
   60  * XXX We shouldn't be using processor-specific/bus-specific code in
   61  * here, but we need the start of the ISA hole (IOM_BEGIN).
   62  */
   63 #include <i386/isa/isa.h>
   64 
   65 SYSCTL_NODE(_machdep, OID_AUTO, pccard, CTLFLAG_RW, 0, "pccard");
   66 
   67 static int pcic_resume_reset =
   68 #ifdef PCIC_RESUME_RESET
   69         1;
   70 #else
   71         0;
   72 #endif
   73 
   74 SYSCTL_INT(_machdep_pccard, OID_AUTO, pcic_resume_reset, CTLFLAG_RW, 
   75         &pcic_resume_reset, 0, "");
   76 
   77 #define PCCARD_MEMSIZE  (4*1024)
   78 
   79 #define MIN(a,b)        ((a)<(b)?(a):(b))
   80 
   81 static int              allocate_driver(struct slot *, struct dev_desc *);
   82 static void             inserted(void *);
   83 static void             unregister_device_interrupt(struct pccard_devinfo *);
   84 static void             disable_slot(struct slot *);
   85 static int              invalid_io_memory(unsigned long, int);
   86 static struct pccard_device *find_driver(char *);
   87 static void             remove_device(struct pccard_devinfo *);
   88 static void             slot_irq_handler(int);
   89 static void             power_off_slot(void *);
   90 
   91 #if     NAPM > 0
   92 /*
   93  *    For the APM stuff, the apmhook structure is kept
   94  *    separate from the slot structure so that the slot
   95  *    drivers do not need to know about the hooks (or the
   96  *    data structures).
   97  */
   98 static int      slot_suspend(void *arg);
   99 static int      slot_resume(void *arg);
  100 static struct   apmhook s_hook[MAXSLOT];        /* APM suspend */
  101 static struct   apmhook r_hook[MAXSLOT];        /* APM resume */
  102 #endif  /* NAPM > 0 */
  103 
  104 static struct slot      *pccard_slots[MAXSLOT]; /* slot entries */
  105 static struct slot      *slot_list;
  106 static struct slot_ctrl *cont_list;
  107 static struct pccard_device *drivers;           /* Card drivers */
  108 
  109 /*
  110  *      The driver interface for read/write uses a block
  111  *      of memory in the ISA I/O memory space allocated via
  112  *      an ioctl setting.
  113  */
  114 static unsigned long pccard_mem;        /* Physical memory */
  115 static unsigned char *pccard_kmem;      /* Kernel virtual address */
  116 
  117 static  d_open_t        crdopen;
  118 static  d_close_t       crdclose;
  119 static  d_read_t        crdread;
  120 static  d_write_t       crdwrite;
  121 static  d_ioctl_t       crdioctl;
  122 static  d_select_t      crdselect;
  123 
  124 #define CDEV_MAJOR 50
  125 static struct cdevsw crd_cdevsw = 
  126         { crdopen,      crdclose,       crdread,        crdwrite,       /*50*/
  127           crdioctl,     nostop,         nullreset,      nodevtotty,/* pcmcia */
  128           crdselect,    nommap,         NULL,   "crd",  NULL,   -1 };
  129 
  130 
  131 /*
  132  *      pccard_configure - called by autoconf code.
  133  *      Probes for various PC-CARD controllers, and
  134  *      initialises data structures to point to the
  135  *      various slots.
  136  *
  137  *      Each controller indicates the number of slots
  138  *      that it sees, and these are mapped to a master
  139  *      slot number accessed via the character device entries.
  140  */
  141 void
  142 pccard_configure(void)
  143 {
  144         struct pccard_device **drivers, *drv;
  145 
  146 #include "pcic.h"
  147 #if NPCIC > 0
  148         pcic_probe();
  149 #endif
  150 
  151         drivers = (struct pccard_device **)pccarddrv_set.ls_items;
  152         printf("Initializing PC-card drivers:");
  153         while ((drv = *drivers++)) {
  154                 printf(" %s", drv->name);
  155                 pccard_add_driver(drv);
  156         }
  157         printf("\n");
  158 }
  159 
  160 /*
  161  *      pccard_add_driver - Add a new driver to the list of
  162  *      drivers available for allocation.
  163  */
  164 void
  165 pccard_add_driver(struct pccard_device *drv)
  166 {
  167         /*
  168          *      If already loaded, then reject the driver.
  169          */
  170         if (find_driver(drv->name)) {
  171                 printf("Driver %s already loaded\n", drv->name);
  172                 return;
  173         }
  174         drv->next = drivers;
  175         drivers = drv;
  176 }
  177 
  178 #ifdef unused
  179 /*
  180  *      pccard_remove_driver - called to unlink driver
  181  *      from devices. Usually called when drivers are
  182  *      are unloaded from kernel.
  183  */
  184 void
  185 pccard_remove_driver(struct pccard_device *drv)
  186 {
  187         struct slot *slt;
  188         struct pccard_devinfo *devi, *next;
  189         struct pccard_device *drvlist;
  190 
  191         for (slt = slot_list; slt; slt = slt->next)
  192                 for (devi = slt->devices; devi; devi = next) {
  193                         next = devi->next;
  194                         if (devi->drv == drv)
  195                                 remove_device(devi);
  196                 }
  197         /*
  198          *      Once all the devices belonging to this driver have been
  199          *      freed, then remove the driver from the list
  200          *      of registered drivers.
  201          */
  202         if (drivers == drv)
  203                 drivers = drv->next;
  204         else
  205                 for (drvlist = drivers; drvlist->next; drvlist = drvlist->next)
  206                         if (drvlist->next == drv) {
  207                                 drvlist->next = drv->next;
  208                                 break;
  209                         }
  210 }
  211 #endif
  212 
  213 /*
  214  *      pccard_remove_controller - Called when the slot
  215  *      driver is unloaded. The plan is to unload
  216  *      drivers from the slots, and then remove the
  217  *      slots from the slot list, and then finally
  218  *      remove the controller structure. Messy...
  219  */
  220 void
  221 pccard_remove_controller(struct slot_ctrl *ctrl)
  222 {
  223         struct slot *slt, *next, *last = 0;
  224         struct slot_ctrl *cl;
  225         struct pccard_devinfo *devi;
  226 
  227         for (slt = slot_list; slt; slt = next) {
  228                 next = slt->next;
  229                 /*
  230                  *      If this slot belongs to this controller,
  231                  *      remove this slot.
  232                  */
  233                 if (slt->ctrl == ctrl) {
  234                         pccard_slots[slt->slotnum] = 0;
  235                         if (slt->insert_seq)
  236                                 untimeout(inserted, (void *)slt);
  237                         /*
  238                          * Unload the drivers attached to this slot.
  239                          */
  240                         while (devi = slt->devices)
  241                                 remove_device(devi);
  242                         /*
  243                          * Disable the slot and unlink the slot from the 
  244                          * slot list.
  245                          */
  246                         disable_slot(slt);
  247                         if (last)
  248                                 last->next = next;
  249                         else
  250                                 slot_list = next;
  251 #if NAPM > 0
  252                         apm_hook_disestablish(APM_HOOK_SUSPEND,
  253                                 &s_hook[slt->slotnum]);
  254                         apm_hook_disestablish(APM_HOOK_RESUME,
  255                                 &r_hook[slt->slotnum]);
  256 #endif
  257                         if (ctrl->extra && slt->cdata)
  258                                 FREE(slt->cdata, M_DEVBUF);
  259                         FREE(slt, M_DEVBUF);
  260                         /*
  261                          * Can't use slot after we have freed it.
  262                          */
  263                 } else {
  264                         last = slt;
  265                 }
  266         }
  267         /*
  268          *      Unlink controller structure from controller list.
  269          */
  270         if (cont_list == ctrl)
  271                 cont_list = ctrl->next;
  272         else
  273                 for (cl = cont_list; cl->next; cl = cl->next)
  274                         if (cl->next == ctrl) {
  275                                 cl->next = ctrl->next;
  276                                 break;
  277                         }
  278 }
  279 
  280 /*
  281  *      Power off the slot.
  282  *      (doing it immediately makes the removal of some cards unstable)
  283  */
  284 static void
  285 power_off_slot(void *arg)
  286 {
  287         struct slot *slt = (struct slot *)arg;
  288 
  289         /* Power off the slot. */
  290         slt->pwr_off_pending = 0;
  291         slt->ctrl->disable(slt);
  292 }
  293 
  294 /*
  295  *      unregister_device_interrupt - Disable the interrupt generation to
  296  *      the device driver which is handling it, so we can remove it.
  297  */
  298 static void
  299 unregister_device_interrupt(struct pccard_devinfo *devi)
  300 {
  301         struct slot *slt = devi->slt;
  302         int s;
  303 
  304         if (devi->running) {
  305                 s = splhigh();
  306                 devi->drv->disable(devi);
  307                 devi->running = 0;
  308                 if (devi->isahd.id_irq && --slt->irqref <= 0) {
  309                         printf("Return IRQ=%d\n",slt->irq);
  310                         slt->ctrl->mapirq(slt, 0);
  311                         INTRDIS(1<<slt->irq);
  312                         unregister_intr(slt->irq, slot_irq_handler);
  313                         if (devi->drv->imask)
  314                                 INTRUNMASK(*devi->drv->imask,(1<<slt->irq));
  315                         /* Remove from the PCIC controller imask */
  316                         if (slt->ctrl->imask)
  317                                 INTRUNMASK(*(slt->ctrl->imask), (1<<slt->irq));
  318                         slt->irq = 0;
  319                 }
  320                 splx(s);
  321         }
  322 }
  323 
  324 /*
  325  *      disable_slot - Disables the slot by removing
  326  *      the power and unmapping the I/O
  327  */
  328 static void
  329 disable_slot(struct slot *slt)
  330 {
  331         struct pccard_devinfo *devi;
  332         int i;
  333         /*
  334          * Unload all the drivers on this slot. Note we can't
  335          * remove the device structures themselves, because this
  336          * may be called from the event routine, which is called
  337          * from the slot controller's ISR, and removing the structures
  338          * shouldn't happen during the middle of some driver activity.
  339          *
  340          * Note that a race condition is possible here; if a
  341          * driver is accessing the device and it is removed, then
  342          * all bets are off...
  343          */
  344         for (devi = slt->devices; devi; devi = devi->next)
  345                 unregister_device_interrupt(devi);
  346 
  347         /* Power off the slot 1/2 second after removal of the card */
  348         timeout(power_off_slot, (caddr_t)slt, hz / 2);
  349         slt->pwr_off_pending = 1;
  350 
  351         /* De-activate all contexts. */
  352         for (i = 0; i < slt->ctrl->maxmem; i++)
  353                 if (slt->mem[i].flags & MDF_ACTIVE) {
  354                         slt->mem[i].flags = 0;
  355                         (void)slt->ctrl->mapmem(slt, i);
  356                 }
  357         for (i = 0; i < slt->ctrl->maxio; i++)
  358                 if (slt->io[i].flags & IODF_ACTIVE) {
  359                         slt->io[i].flags = 0;
  360                         (void)slt->ctrl->mapio(slt, i);
  361                 }
  362 }
  363 
  364 /*
  365  *      APM hooks for suspending and resuming.
  366  */
  367 #if   NAPM > 0
  368 static int
  369 slot_suspend(void *arg)
  370 {
  371         struct slot *slt = arg;
  372 
  373         /* This code stolen from pccard_event:card_removed */
  374         if (slt->state == filled) {
  375                 int s = splhigh();
  376                 disable_slot(slt);
  377                 slt->state = suspend;
  378                 splx(s);
  379                 printf("Card disabled, slot %d\n", slt->slotnum);
  380         }
  381         /*
  382          * Disable any pending timeouts for this slot since we're
  383          * powering it down/disabling now.
  384          */
  385         untimeout(power_off_slot, (caddr_t)slt); 
  386         slt->ctrl->disable(slt);
  387         return (0);
  388 }
  389 
  390 static int
  391 slot_resume(void *arg)
  392 {
  393         struct slot *slt = arg;
  394 
  395         if (pcic_resume_reset)
  396                 slt->ctrl->resume(slt);
  397         /* This code stolen from pccard_event:card_inserted */
  398         if (slt->state == suspend) {
  399                 slt->state = empty;
  400                 slt->insert_seq = 1;
  401                 timeout(inserted, (void *)slt, hz/4);
  402                 selwakeup(&slt->selp);
  403         }
  404         return (0);
  405 }
  406 #endif  /* NAPM > 0 */
  407 
  408 /*
  409  *      pccard_alloc_slot - Called from controller probe
  410  *      routine, this function allocates a new PC-CARD slot
  411  *      and initialises the data structures using the data provided.
  412  *      It returns the allocated structure to the probe routine
  413  *      to allow the controller specific data to be initialised.
  414  */
  415 struct slot *
  416 pccard_alloc_slot(struct slot_ctrl *ctrl)
  417 {
  418         struct slot *slt;
  419         int slotno;
  420 
  421         for (slotno = 0; slotno < MAXSLOT; slotno++)
  422                 if (pccard_slots[slotno] == 0)
  423                         break;
  424         if (slotno == MAXSLOT)
  425                 return(0);
  426 
  427         MALLOC(slt, struct slot *, sizeof(*slt), M_DEVBUF, M_WAITOK);
  428         bzero(slt, sizeof(*slt));
  429 #ifdef DEVFS
  430         slt->devfs_token = devfs_add_devswf(&crd_cdevsw, 
  431                 0, DV_CHR, 0, 0, 0600, "card%d", slotno);
  432 #endif
  433         if (ctrl->extra) {
  434                 MALLOC(slt->cdata, void *, ctrl->extra, M_DEVBUF, M_WAITOK);
  435                 bzero(slt->cdata, ctrl->extra);
  436         }
  437         slt->ctrl = ctrl;
  438         slt->slotnum = slotno;
  439         pccard_slots[slotno] = slt;
  440         slt->next = slot_list;
  441         slot_list = slt;
  442         /*
  443          *      If this controller hasn't been seen before, then
  444          *      link it into the list of controllers.
  445          */
  446         if (ctrl->slots++ == 0) {
  447                 ctrl->next = cont_list;
  448                 cont_list = ctrl;
  449                 if (ctrl->maxmem > NUM_MEM_WINDOWS)
  450                         ctrl->maxmem = NUM_MEM_WINDOWS;
  451                 if (ctrl->maxio > NUM_IO_WINDOWS)
  452                         ctrl->maxio = NUM_IO_WINDOWS;
  453                 printf("PC-Card %s (%d mem & %d I/O windows)\n",
  454                         ctrl->name, ctrl->maxmem, ctrl->maxio);
  455         }
  456 #if NAPM > 0
  457         {
  458                 struct apmhook *ap;
  459 
  460                 ap = &s_hook[slt->slotnum];
  461                 ap->ah_fun = slot_suspend;
  462                 ap->ah_arg = (void *)slt;
  463                 ap->ah_name = ctrl->name;
  464                 ap->ah_order = APM_MID_ORDER;
  465                 apm_hook_establish(APM_HOOK_SUSPEND, ap);
  466                 ap = &r_hook[slt->slotnum];
  467                 ap->ah_fun = slot_resume;
  468                 ap->ah_arg = (void *)slt;
  469                 ap->ah_name = ctrl->name;
  470                 ap->ah_order = APM_MID_ORDER;
  471                 apm_hook_establish(APM_HOOK_RESUME, ap);
  472         }
  473 #endif /* NAPM > 0 */
  474         return(slt);
  475 }
  476 
  477 /*
  478  *      pccard_alloc_intr - allocate an interrupt from the
  479  *      free interrupts and return its number. The interrupts
  480  *      allowed are passed as a mask.
  481  */
  482 int
  483 pccard_alloc_intr(u_int imask, inthand2_t *hand, int unit,
  484                   u_int *maskp, u_int *pcic_imask)
  485 {
  486         int irq;
  487         unsigned int mask;
  488 
  489         for (irq = 1; irq < ICU_LEN; irq++) {
  490                 mask = 1ul << irq;
  491                 if (!(mask & imask))
  492                         continue;
  493                 INTRMASK(*maskp, mask);
  494                 if (register_intr(irq, 0, 0, hand, maskp, unit) == 0) {
  495                         /* add this to the PCIC controller's mask */
  496                         if (pcic_imask)
  497                                 INTRMASK(*pcic_imask, (1 << irq));
  498                         update_intr_masks();
  499                         INTREN(mask);
  500                         return(irq);
  501                 }
  502                 /* No luck, remove from mask again... */
  503                 INTRUNMASK(*maskp, mask);
  504                 update_intr_masks();
  505         }
  506         return(-1);
  507 }
  508 
  509 /*
  510  *      allocate_driver - Create a new device entry for this
  511  *      slot, and attach a driver to it.
  512  */
  513 static int
  514 allocate_driver(struct slot *slt, struct dev_desc *desc)
  515 {
  516         struct pccard_devinfo *devi;
  517         struct pccard_device *drv;
  518         int err, irq = 0, s;
  519 
  520         drv = find_driver(desc->name);
  521         if (drv == 0)
  522                 return(ENXIO);
  523         /*
  524          *      If an instance of this driver is already installed,
  525          *      but not running, then remove it. If it is running,
  526          *      then reject the request.
  527          */
  528         for (devi = slt->devices; devi; devi = devi->next)
  529                 if (devi->drv == drv && devi->isahd.id_unit == desc->unit) {
  530                         if (devi->running)
  531                                 return(EBUSY);
  532                         remove_device(devi);
  533                         break;
  534                 }
  535         /*
  536          *      If an interrupt mask has been given, then check it
  537          *      against the slot interrupt (if one has been allocated).
  538          */
  539         if (desc->irqmask && drv->imask) {
  540                 if ((slt->ctrl->irqs & desc->irqmask) == 0)
  541                         return(EINVAL);
  542                 if (slt->irq) {
  543                         if (((1 << slt->irq) & desc->irqmask) == 0)
  544                                 return(EINVAL);
  545                         slt->irqref++;
  546                         irq = slt->irq;
  547                 } else {
  548                         /*
  549                          * Attempt to allocate an interrupt.
  550                          * XXX We lose at the moment if the second 
  551                          * device relies on a different interrupt mask.
  552                          */
  553                         irq = pccard_alloc_intr(desc->irqmask,
  554                                 slot_irq_handler, (int)slt,
  555                                 drv->imask, slt->ctrl->imask);
  556                         if (irq < 0)
  557                                 return(EINVAL);
  558                         slt->irq = irq;
  559                         slt->irqref = 1;
  560                         slt->ctrl->mapirq(slt, slt->irq);
  561                 }
  562         }
  563         MALLOC(devi, struct pccard_devinfo *, sizeof(*devi), M_DEVBUF, M_WAITOK);
  564         bzero(devi, sizeof(*devi));
  565         /*
  566          *      Create an entry for the device under this slot.
  567          */
  568         devi->running = 1;
  569         devi->drv = drv;
  570         devi->slt = slt;
  571         devi->isahd.id_irq = irq;
  572         devi->isahd.id_unit = desc->unit;
  573         devi->isahd.id_msize = desc->memsize;
  574         devi->isahd.id_iobase = desc->iobase;
  575         bcopy(desc->misc, devi->misc, sizeof(desc->misc));
  576         if (irq)
  577                 devi->isahd.id_irq = 1 << irq;
  578         devi->isahd.id_flags = desc->flags;
  579         /*
  580          *      Convert the memory to kernel space.
  581          */
  582         if (desc->mem)
  583                 devi->isahd.id_maddr = 
  584                         (caddr_t)(desc->mem + atdevbase - IOM_BEGIN);
  585         else
  586                 devi->isahd.id_maddr = 0;
  587         devi->next = slt->devices;
  588         slt->devices = devi;
  589         s = splhigh();
  590         err = drv->enable(devi);
  591         splx(s);
  592         /*
  593          *      If the enable functions returns no error, then the
  594          *      device has been successfully installed. If so, then
  595          *      attach it to the slot, otherwise free it and return
  596          *      the error.  We assume that when we free the device,
  597          *      it will also set 'running' to off.
  598          */
  599         if (err)
  600                 remove_device(devi);
  601         return(err);
  602 }
  603 
  604 static void
  605 remove_device(struct pccard_devinfo *devi)
  606 {
  607         struct slot *slt = devi->slt;
  608         struct pccard_devinfo *list;
  609 
  610         /*
  611          *      If an interrupt is enabled on this slot,
  612          *      then unregister it if no-one else is using it.
  613          */
  614         unregister_device_interrupt(devi);
  615         /*
  616          *      Remove from device list on this slot.
  617          */
  618         if (slt->devices == devi)
  619                 slt->devices = devi->next;
  620         else
  621                 for (list = slt->devices; list->next; list = list->next)
  622                         if (list->next == devi) {
  623                                 list->next = devi->next;
  624                                 break;
  625                         }
  626         /*
  627          *      Finally, free the memory space.
  628          */
  629         FREE(devi, M_DEVBUF);
  630 }
  631 
  632 /*
  633  *      card insert routine - Called from a timeout to debounce
  634  *      insertion events.
  635  */
  636 static void
  637 inserted(void *arg)
  638 {
  639         struct slot *slt = arg;
  640 
  641         slt->state = filled;
  642         /*
  643          *      Enable 5V to the card so that the CIS can be read.
  644          */
  645         slt->pwr.vcc = 50;
  646         slt->pwr.vpp = 0;
  647         /*
  648          * Disable any pending timeouts for this slot, and explicitly
  649          * power it off right now.  Then, re-enable the power using
  650          * the (possibly new) power settings.
  651          */
  652         untimeout(power_off_slot, (caddr_t)slt);
  653         power_off_slot(slt);
  654         slt->ctrl->power(slt);
  655 
  656         printf("Card inserted, slot %d\n", slt->slotnum);
  657         /*
  658          *      Now start resetting the card.
  659          */
  660         slt->ctrl->reset(slt);
  661 }
  662 
  663 /*
  664  *      Card event callback. Called at splhigh to prevent
  665  *      device interrupts from interceding.
  666  */
  667 void
  668 pccard_event(struct slot *slt, enum card_event event)
  669 {
  670         if (slt->insert_seq) {
  671                 slt->insert_seq = 0;
  672                 untimeout(inserted, (void *)slt);
  673         }
  674 
  675         switch(event) {
  676         case card_removed:
  677                 /*
  678                  *      The slot and devices are disabled, but the
  679                  *      data structures are not unlinked.
  680                  */
  681                 if (slt->state == filled) {
  682                         int s = splhigh();
  683                         disable_slot(slt);
  684                         slt->state = empty;
  685                         splx(s);
  686                         printf("Card removed, slot %d\n", slt->slotnum);
  687                         pccard_remove_beep();
  688                         selwakeup(&slt->selp);
  689                 }
  690                 break;
  691         case card_inserted:
  692                 slt->insert_seq = 1;
  693                 timeout(inserted, (void *)slt, hz/4);
  694                 pccard_remove_beep();
  695                 break;
  696         }
  697 }
  698 
  699 /*
  700  *      slot_irq_handler - Interrupt handler for shared irq devices.
  701  */
  702 static void
  703 slot_irq_handler(int arg)
  704 {
  705         struct pccard_devinfo *devi;
  706         struct slot *slt = (struct slot *)arg;
  707 
  708         /*
  709          *      For each device that has the shared interrupt,
  710          *      call the interrupt handler. If the interrupt was
  711          *      caught, the handler returns true.
  712          */
  713         for (devi = slt->devices; devi; devi = devi->next)
  714                 if (devi->isahd.id_irq && devi->running &&
  715                     devi->drv->handler(devi))
  716                         return;
  717         /*
  718          * XXX - Should 'debounce' these for drivers that have recently
  719          * been removed.
  720          */
  721         printf("Slot %d, unfielded interrupt (%d)\n", slt->slotnum, slt->irq);
  722 }
  723 
  724 /*
  725  *      Device driver interface.
  726  */
  727 static  int
  728 crdopen(dev_t dev, int oflags, int devtype, struct proc *p)
  729 {
  730         struct slot *slt;
  731 
  732         if (minor(dev) >= MAXSLOT)
  733                 return(ENXIO);
  734         slt = pccard_slots[minor(dev)];
  735         if (slt == 0)
  736                 return(ENXIO);
  737         if (slt->rwmem == 0)
  738                 slt->rwmem = MDF_ATTR;
  739         return(0);
  740 }
  741 
  742 /*
  743  *      Close doesn't de-allocate any resources, since
  744  *      slots may be assigned to drivers already.
  745  */
  746 static  int
  747 crdclose(dev_t dev, int fflag, int devtype, struct proc *p)
  748 {
  749         return(0);
  750 }
  751 
  752 /*
  753  *      read interface. Map memory at lseek offset,
  754  *      then transfer to user space.
  755  */
  756 static  int
  757 crdread(dev_t dev, struct uio *uio, int ioflag)
  758 {
  759         struct slot *slt = pccard_slots[minor(dev)];
  760         struct mem_desc *mp, oldmap;
  761         unsigned char *p;
  762         unsigned int offs;
  763         int error = 0, win, count;
  764 
  765         if (slt == 0 || slt->state != filled)
  766                 return(ENXIO);
  767         if (pccard_mem == 0)
  768                 return(ENOMEM);
  769         for (win = 0; win < slt->ctrl->maxmem; win++)
  770                 if ((slt->mem[win].flags & MDF_ACTIVE) == 0)
  771                         break;
  772         if (win >= slt->ctrl->maxmem)
  773                 return(EBUSY);
  774         mp = &slt->mem[win];
  775         oldmap = *mp;
  776         mp->flags = slt->rwmem|MDF_ACTIVE;
  777 #if 0
  778         printf("Rd at offs %d, size %d\n", (int)uio->uio_offset,
  779                                 uio->uio_resid);
  780 #endif
  781         while (uio->uio_resid && error == 0) {
  782                 mp->card = uio->uio_offset;
  783                 mp->size = PCCARD_MEMSIZE;
  784                 mp->start = (caddr_t)pccard_mem;
  785                 if (error = slt->ctrl->mapmem(slt, win))
  786                         break;
  787                 offs = (unsigned int)uio->uio_offset & (PCCARD_MEMSIZE - 1);
  788                 p = pccard_kmem + offs;
  789                 count = MIN(PCCARD_MEMSIZE - offs, uio->uio_resid);
  790                 error = uiomove(p, count, uio);
  791         }
  792         /*
  793          *      Restore original map.
  794          */
  795         *mp = oldmap;
  796         slt->ctrl->mapmem(slt, win);
  797 
  798         return(error);
  799 }
  800 
  801 /*
  802  *      crdwrite - Write data to card memory.
  803  *      Handles wrap around so that only one memory
  804  *      window is used.
  805  */
  806 static  int
  807 crdwrite(dev_t dev, struct uio *uio, int ioflag)
  808 {
  809         struct slot *slt = pccard_slots[minor(dev)];
  810         struct mem_desc *mp, oldmap;
  811         unsigned char *p;
  812         unsigned int offs;
  813         int error = 0, win, count;
  814 
  815         if (slt == 0 || slt->state != filled)
  816                 return(ENXIO);
  817         if (pccard_mem == 0)
  818                 return(ENOMEM);
  819         for (win = 0; win < slt->ctrl->maxmem; win++)
  820                 if ((slt->mem[win].flags & MDF_ACTIVE)==0)
  821                         break;
  822         if (win >= slt->ctrl->maxmem)
  823                 return(EBUSY);
  824         mp = &slt->mem[win];
  825         oldmap = *mp;
  826         mp->flags = slt->rwmem|MDF_ACTIVE;
  827 #if 0
  828         printf("Wr at offs %d, size %d\n", (int)uio->uio_offset,
  829                                 uio->uio_resid);
  830 #endif
  831         while (uio->uio_resid && error == 0) {
  832                 mp->card = uio->uio_offset;
  833                 mp->size = PCCARD_MEMSIZE;
  834                 mp->start = (caddr_t)pccard_mem;
  835                 if (error = slt->ctrl->mapmem(slt, win))
  836                         break;
  837                 offs = (unsigned int)uio->uio_offset & (PCCARD_MEMSIZE - 1);
  838                 p = pccard_kmem + offs;
  839                 count = MIN(PCCARD_MEMSIZE - offs, uio->uio_resid);
  840 #if 0
  841         printf("Writing %d bytes to address 0x%x\n", count, p);
  842 #endif
  843                 error = uiomove(p, count, uio);
  844         }
  845         /*
  846          *      Restore original map.
  847          */
  848         *mp = oldmap;
  849         slt->ctrl->mapmem(slt, win);
  850 
  851         return(error);
  852 }
  853 
  854 /*
  855  *      ioctl calls - allows setting/getting of memory and I/O
  856  *      descriptors, and assignment of drivers.
  857  */
  858 static  int
  859 crdioctl(dev_t dev, int cmd, caddr_t data, int fflag, struct proc *p)
  860 {
  861         struct slot *slt = pccard_slots[minor(dev)];
  862         struct mem_desc *mp;
  863         struct io_desc *ip;
  864         int s, err;
  865 
  866         /* beep is disabled until the 1st call of crdioctl() */
  867         pccard_beep_select(BEEP_ON);
  868 
  869         if (slt == 0 && cmd != PIOCRWMEM)
  870                 return(ENXIO);
  871         switch(cmd) {
  872         default:
  873                 if (slt->ctrl->ioctl)
  874                         return(slt->ctrl->ioctl(slt, cmd, data));
  875                 return(EINVAL);
  876         /*
  877          * Get slot state.
  878          */
  879         case PIOCGSTATE:
  880                 s = splhigh();
  881                 ((struct slotstate *)data)->state = slt->state;
  882                 slt->laststate = slt->state;
  883                 splx(s);
  884                 ((struct slotstate *)data)->maxmem = slt->ctrl->maxmem;
  885                 ((struct slotstate *)data)->maxio = slt->ctrl->maxio;
  886                 ((struct slotstate *)data)->irqs = slt->ctrl->irqs;
  887                 break;
  888         /*
  889          * Get memory context.
  890          */
  891         case PIOCGMEM:
  892                 s = ((struct mem_desc *)data)->window;
  893                 if (s < 0 || s >= slt->ctrl->maxmem)
  894                         return(EINVAL);
  895                 mp = &slt->mem[s];
  896                 ((struct mem_desc *)data)->flags = mp->flags;
  897                 ((struct mem_desc *)data)->start = mp->start;
  898                 ((struct mem_desc *)data)->size = mp->size;
  899                 ((struct mem_desc *)data)->card = mp->card;
  900                 break;
  901         /*
  902          * Set memory context. If context already active, then unmap it.
  903          * It is hard to see how the parameters can be checked.
  904          * At the very least, we only allow root to set the context.
  905          */
  906         case PIOCSMEM:
  907                 if (suser(p->p_ucred, &p->p_acflag))
  908                         return(EPERM);
  909                 if (slt->state != filled)
  910                         return(ENXIO);
  911                 s = ((struct mem_desc *)data)->window;
  912                 if (s < 0 || s >= slt->ctrl->maxmem)
  913                         return(EINVAL);
  914                 slt->mem[s] = *((struct mem_desc *)data);
  915                 return(slt->ctrl->mapmem(slt, s));
  916         /*
  917          * Get I/O port context.
  918          */
  919         case PIOCGIO:
  920                 s = ((struct io_desc *)data)->window;
  921                 if (s < 0 || s >= slt->ctrl->maxio)
  922                         return(EINVAL);
  923                 ip = &slt->io[s];
  924                 ((struct io_desc *)data)->flags = ip->flags;
  925                 ((struct io_desc *)data)->start = ip->start;
  926                 ((struct io_desc *)data)->size = ip->size;
  927                 break;
  928         /*
  929          * Set I/O port context.
  930          */
  931         case PIOCSIO:
  932                 if (suser(p->p_ucred, &p->p_acflag))
  933                         return(EPERM);
  934                 if (slt->state != filled)
  935                         return(ENXIO);
  936                 s = ((struct io_desc *)data)->window;
  937                 if (s < 0 || s >= slt->ctrl->maxio)
  938                         return(EINVAL);
  939                 slt->io[s] = *((struct io_desc *)data);
  940                 return(slt->ctrl->mapio(slt, s));
  941                 break;
  942         /*
  943          * Set memory window flags for read/write interface.
  944          */
  945         case PIOCRWFLAG:
  946                 slt->rwmem = *(int *)data;
  947                 break;
  948         /*
  949          * Set the memory window to be used for the read/write interface.
  950          */
  951         case PIOCRWMEM:
  952                 if (*(unsigned long *)data == 0) {
  953                         if (pccard_mem)
  954                                 *(unsigned long *)data = pccard_mem;
  955                         break;
  956                 }
  957                 if (suser(p->p_ucred, &p->p_acflag))
  958                         return(EPERM);
  959                 /*
  960                  * Validate the memory by checking it against the I/O
  961                  * memory range. It must also start on an aligned block size.
  962                  */
  963                 if (invalid_io_memory(*(unsigned long *)data, PCCARD_MEMSIZE))
  964                         return(EINVAL);
  965                 if (*(unsigned long *)data & (PCCARD_MEMSIZE-1))
  966                         return(EINVAL);
  967                 /*
  968                  *      Map it to kernel VM.
  969                  */
  970                 pccard_mem = *(unsigned long *)data;
  971                 pccard_kmem = (unsigned char *)(pccard_mem
  972                                 + atdevbase - IOM_BEGIN);
  973                 break;
  974         /*
  975          * Set power values.
  976          */
  977         case PIOCSPOW:
  978                 slt->pwr = *(struct power *)data;
  979                 return(slt->ctrl->power(slt));
  980         /*
  981          * Allocate a driver to this slot.
  982          */
  983         case PIOCSDRV:
  984                 if (suser(p->p_ucred, &p->p_acflag))
  985                         return(EPERM);
  986                 err = allocate_driver(slt, (struct dev_desc *)data);
  987                 if (!err)
  988                         pccard_success_beep();
  989                 else
  990                         pccard_failure_beep();
  991                 return err;
  992         }
  993         return(0);
  994 }
  995 
  996 /*
  997  *      select - Selects on exceptions will return true
  998  *      when a change in card status occurs.
  999  */
 1000 static  int
 1001 crdselect(dev_t dev, int rw, struct proc *p)
 1002 {
 1003         int s;
 1004         struct slot *slt = pccard_slots[minor(dev)];
 1005 
 1006         switch (rw) {
 1007         case FREAD:
 1008                 return 1;
 1009         case FWRITE:
 1010                 return 1;
 1011         /*
 1012          *      select for exception - card event.
 1013          */
 1014         case 0:
 1015                 s = splhigh();
 1016                 if (slt == 0 || slt->laststate != slt->state) {
 1017                         splx(s);
 1018                         return(1);
 1019                 }
 1020                 selrecord(p, &slt->selp);
 1021                 splx(s);
 1022         }
 1023         return(0);
 1024 }
 1025 
 1026 /*
 1027  *      invalid_io_memory - verify that the ISA I/O memory block
 1028  *      is a valid and unallocated address.
 1029  *      A simple check of the range is done, and then a
 1030  *      search of the current devices is done to check for
 1031  *      overlapping regions.
 1032  */
 1033 static int
 1034 invalid_io_memory(unsigned long adr, int size)
 1035 {
 1036         /* XXX - What's magic about 0xC0000?? */
 1037         if (adr < 0xC0000 || (adr+size) > IOM_END)
 1038                 return(1);
 1039         return(0);
 1040 }
 1041 
 1042 static struct pccard_device *
 1043 find_driver(char *name)
 1044 {
 1045         struct pccard_device *drv;
 1046 
 1047         for (drv = drivers; drv; drv = drv->next)
 1048                 if (strcmp(drv->name, name)==0)
 1049                         return(drv);
 1050         return(0);
 1051 }
 1052 
 1053 static crd_devsw_installed = 0;
 1054 
 1055 static void
 1056 crd_drvinit(void *unused)
 1057 {
 1058         dev_t dev;
 1059 
 1060         if (!crd_devsw_installed) {
 1061                 dev = makedev(CDEV_MAJOR, 0);
 1062                 cdevsw_add(&dev, &crd_cdevsw, NULL);
 1063                 crd_devsw_installed = 1;
 1064         }
 1065 }
 1066 
 1067 SYSINIT(crddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,crd_drvinit,NULL)

Cache object: 1d314f12b882c745c30efcb6d0edbcb1


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