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) 2001 M. Warner Losh.  All rights reserved.
    8  * Copyright (c) 1995 Andrew McRae.  All rights reserved.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. The name of the author may not be used to endorse or promote products
   19  *    derived from this software without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  *
   32  * $FreeBSD$
   33  */
   34 
   35 #include <sys/param.h>
   36 #include <sys/types.h>
   37 #include <sys/systm.h>
   38 #include <sys/kernel.h>
   39 #include <sys/malloc.h>
   40 #include <sys/sysctl.h>
   41 #include <sys/conf.h>
   42 #include <sys/uio.h>
   43 #include <sys/poll.h>
   44 #include <sys/bus.h>
   45 #include <sys/proc.h>
   46 #include <machine/bus.h>
   47 
   48 #include <pccard/cardinfo.h>
   49 #include <pccard/driver.h>
   50 #include <pccard/slot.h>
   51 #include <pccard/pccard_nbk.h>
   52 
   53 #include <machine/md_var.h>
   54 
   55 #define MIN(a,b)        ((a)<(b)?(a):(b))
   56 
   57 static int              allocate_driver(struct slot *, struct dev_desc *);
   58 static void             inserted(void *);
   59 static void             disable_slot(struct slot *);
   60 static void             disable_slot_to(struct slot *);
   61 static void             power_off_slot(void *);
   62 
   63 /*
   64  *      The driver interface for read/write uses a block
   65  *      of memory in the ISA I/O memory space allocated via
   66  *      an ioctl setting.
   67  *
   68  *      Now that we have different bus attachments, we should really
   69  *      use a better algorythm to allocate memory.
   70  */
   71 static unsigned long pccard_mem;        /* Physical memory */
   72 static unsigned char *pccard_kmem;      /* Kernel virtual address */
   73 static struct resource *pccard_mem_res;
   74 static int pccard_mem_rid;
   75 
   76 static  d_open_t        crdopen;
   77 static  d_close_t       crdclose;
   78 static  d_read_t        crdread;
   79 static  d_write_t       crdwrite;
   80 static  d_ioctl_t       crdioctl;
   81 static  d_poll_t        crdpoll;
   82 
   83 #define CDEV_MAJOR 50
   84 static struct cdevsw crd_cdevsw = {
   85         /* open */      crdopen,
   86         /* close */     crdclose,
   87         /* read */      crdread,
   88         /* write */     crdwrite,
   89         /* ioctl */     crdioctl,
   90         /* poll */      crdpoll,
   91         /* mmap */      nommap,
   92         /* strategy */  nostrategy,
   93         /* name */      "crd",
   94         /* maj */       CDEV_MAJOR,
   95         /* dump */      nodump,
   96         /* psize */     nopsize,
   97         /* flags */     0,
   98 };
   99 
  100 /*
  101  *      Power off the slot.
  102  *      (doing it immediately makes the removal of some cards unstable)
  103  */
  104 static void
  105 power_off_slot(void *arg)
  106 {
  107         struct slot *slt = (struct slot *)arg;
  108         int s;
  109 
  110         /*
  111          * The following will generate an interrupt.  So, to hold off
  112          * the interrupt unitl after disable runs so that we can get rid
  113          * rid of the interrupt before it becomes unsafe to touch the
  114          * device.
  115          *
  116          * XXX In current, the spl stuff is a nop.
  117          */
  118         s = splhigh();
  119         /* Power off the slot. */
  120         slt->pwr_off_pending = 0;
  121         slt->ctrl->disable(slt);
  122         splx(s);
  123 }
  124 
  125 /*
  126  *      disable_slot - Disables the slot by removing
  127  *      the power and unmapping the I/O
  128  */
  129 static void
  130 disable_slot(struct slot *slt)
  131 {
  132         device_t pccarddev;
  133         device_t *kids;
  134         int nkids;
  135         int i;
  136         int ret;
  137 
  138         /*
  139          * Note that a race condition is possible here; if a
  140          * driver is accessing the device and it is removed, then
  141          * all bets are off...
  142          */
  143         pccarddev = slt->dev;
  144         device_get_children(pccarddev, &kids, &nkids);
  145         for (i = 0; i < nkids; i++) {
  146                 if ((ret = device_delete_child(pccarddev, kids[i])) != 0)
  147                         printf("pccard: delete of %s failed: %d\n",
  148                                 device_get_nameunit(kids[i]), ret);
  149         }
  150         free(kids, M_TEMP);
  151 
  152         /* Power off the slot 1/2 second after removal of the card */
  153         slt->poff_ch = timeout(power_off_slot, (caddr_t)slt, hz / 2);
  154         slt->pwr_off_pending = 1;
  155 }
  156 
  157 static void
  158 disable_slot_to(struct slot *slt)
  159 {
  160         disable_slot(slt);
  161         if (slt->state == empty)
  162                 printf("pccard: card removed, slot %d\n", slt->slotnum);
  163         else
  164                 printf("pccard: card deactivated, slot %d\n", slt->slotnum);
  165         pccard_remove_beep();
  166         selwakeup(&slt->selp);
  167 }
  168 
  169 /*
  170  *      pccard_init_slot - Initialize the slot controller and attach various
  171  * things to it.  We also make the device for it.  We create the device that
  172  * will be exported to devfs.
  173  */
  174 struct slot *
  175 pccard_init_slot(device_t dev, struct slot_ctrl *ctrl)
  176 {
  177         int             slotno;
  178         struct slot     *slt;
  179 
  180         slt = PCCARD_DEVICE2SOFTC(dev);
  181         slotno = device_get_unit(dev);
  182         slt->dev = dev;
  183         slt->d = make_dev(&crd_cdevsw, slotno, 0, 0, 0600, "card%d", slotno);
  184         slt->d->si_drv1 = slt;
  185         slt->ctrl = ctrl;
  186         slt->slotnum = slotno;
  187         callout_handle_init(&slt->insert_ch);
  188         callout_handle_init(&slt->poff_ch);
  189 
  190         return (slt);
  191 }
  192 
  193 /*
  194  *      allocate_driver - Create a new device entry for this
  195  *      slot, and attach a driver to it.
  196  */
  197 static int
  198 allocate_driver(struct slot *slt, struct dev_desc *desc)
  199 {
  200         struct pccard_devinfo *devi;
  201         device_t pccarddev;
  202         int err, irq = 0;
  203         device_t child;
  204         device_t *devs;
  205         int count;
  206 
  207         pccarddev = slt->dev;
  208         err = device_get_children(pccarddev, &devs, &count);
  209         if (err != 0)
  210                 return (err);
  211         free(devs, M_TEMP);
  212         if (count) {
  213                 device_printf(pccarddev,
  214                     "Can not attach more than one child.\n");
  215                 return (EIO);
  216         }
  217         irq = ffs(desc->irqmask) - 1;
  218         MALLOC(devi, struct pccard_devinfo *, sizeof(*devi), M_DEVBUF,
  219             M_WAITOK | M_ZERO);
  220         strcpy(devi->name, desc->name);
  221         /*
  222          *      Create an entry for the device under this slot.
  223          */
  224         devi->running = 1;
  225         devi->slt = slt;
  226         bcopy(desc->misc, devi->misc, sizeof(desc->misc));
  227         strcpy(devi->manufstr, desc->manufstr);
  228         strcpy(devi->versstr, desc->versstr);
  229         devi->manufacturer = desc->manufacturer;
  230         devi->product = desc->product;
  231         devi->prodext = desc->prodext;
  232         resource_list_init(&devi->resources);
  233         child = device_add_child(pccarddev, devi->name, desc->unit);
  234         if (child == NULL) {
  235                 if (desc->unit != -1)
  236                         device_printf(pccarddev,
  237                             "Unit %d failed for %s, try a different unit\n",
  238                             desc->unit, devi->name);
  239                 else
  240                         device_printf(pccarddev,
  241                             "No units available for %s.  Impossible?\n",
  242                             devi->name);
  243                 return (EIO);
  244         }
  245         device_set_flags(child, desc->flags);
  246         device_set_ivars(child, devi);
  247         if (bootverbose) {
  248                 device_printf(pccarddev, "Assigning %s:",
  249                     device_get_nameunit(child));
  250                 if (desc->iobase)
  251                         printf(" io 0x%x-0x%x",
  252                             desc->iobase, desc->iobase + desc->iosize - 1);
  253                 if (irq)
  254                         printf(" irq %d", irq);
  255                 if (desc->mem)
  256                         printf(" mem 0x%lx-0x%lx", desc->mem,
  257                             desc->mem + desc->memsize - 1);
  258                 printf(" flags 0x%x\n", desc->flags);
  259         }
  260         err = bus_set_resource(child, SYS_RES_IOPORT, 0, desc->iobase,
  261             desc->iosize);
  262         if (err)
  263                 goto err;
  264         if (irq)
  265                 err = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
  266         if (err)
  267                 goto err;
  268         if (desc->memsize) {
  269                 err = bus_set_resource(child, SYS_RES_MEMORY, 0, desc->mem,
  270                     desc->memsize);
  271                 if (err)
  272                         goto err;
  273         }
  274         err = device_probe_and_attach(child);
  275         /*
  276          * XXX We unwisely assume that the detach code won't run while the
  277          * XXX the attach code is attaching.  Someone should put some
  278          * XXX interlock code.  This can happen if probe/attach takes a while
  279          * XXX and the user ejects the card, which causes the detach
  280          * XXX function to be called.
  281          */
  282         strncpy(desc->name, device_get_nameunit(child), sizeof(desc->name));
  283         desc->name[sizeof(desc->name) - 1] = '\0';
  284 err:
  285         if (err)
  286                 device_delete_child(pccarddev, child);
  287         return (err);
  288 }
  289 
  290 /*
  291  *      card insert routine - Called from a timeout to debounce
  292  *      insertion events.
  293  */
  294 static void
  295 inserted(void *arg)
  296 {
  297         struct slot *slt = arg;
  298 
  299         slt->state = filled;
  300         /*
  301          * Disable any pending timeouts for this slot, and explicitly
  302          * power it off right now.  Then, re-enable the power using
  303          * the (possibly new) power settings.
  304          */
  305         untimeout(power_off_slot, (caddr_t)slt, slt->poff_ch);
  306         power_off_slot(slt);
  307 
  308         /*
  309          *      Enable 5V to the card so that the CIS can be read.  Well,
  310          * enable the most natural voltage so that the CIS can be read.
  311          */
  312         slt->pwr.vcc = -1;
  313         slt->pwr.vpp = -1;
  314         slt->ctrl->power(slt);
  315 
  316         printf("pccard: card inserted, slot %d\n", slt->slotnum);
  317         pccard_insert_beep();
  318         slt->ctrl->reset(slt);
  319 }
  320 
  321 /*
  322  *      Card event callback. Called at splhigh to prevent
  323  *      device interrupts from interceding.
  324  */
  325 void
  326 pccard_event(struct slot *slt, enum card_event event)
  327 {
  328         if (slt->insert_seq) {
  329                 slt->insert_seq = 0;
  330                 untimeout(inserted, (void *)slt, slt->insert_ch);
  331         }
  332 
  333         switch(event) {
  334         case card_removed:
  335         case card_deactivated:
  336                 if (slt->state == filled || slt->state == inactive) {
  337                         if (event == card_removed)
  338                                 slt->state = empty;
  339                         else
  340                                 slt->state = inactive;
  341                         disable_slot_to(slt);
  342                 }
  343                 break;
  344         case card_inserted:
  345                 slt->insert_seq = 1;
  346                 slt->insert_ch = timeout(inserted, (void *)slt, hz/4);
  347                 break;
  348         }
  349 }
  350 
  351 /*
  352  *      Device driver interface.
  353  */
  354 static  int
  355 crdopen(dev_t dev, int oflags, int devtype, d_thread_t *td)
  356 {
  357         struct slot *slt = PCCARD_DEV2SOFTC(dev);
  358 
  359         if (slt == NULL)
  360                 return (ENXIO);
  361         if (slt->rwmem == 0)
  362                 slt->rwmem = MDF_ATTR;
  363         return (0);
  364 }
  365 
  366 /*
  367  *      Close doesn't de-allocate any resources, since
  368  *      slots may be assigned to drivers already.
  369  */
  370 static  int
  371 crdclose(dev_t dev, int fflag, int devtype, d_thread_t *td)
  372 {
  373         return (0);
  374 }
  375 
  376 /*
  377  *      read interface. Map memory at lseek offset,
  378  *      then transfer to user space.
  379  */
  380 static  int
  381 crdread(dev_t dev, struct uio *uio, int ioflag)
  382 {
  383         struct slot *slt = PCCARD_DEV2SOFTC(dev);
  384         struct mem_desc *mp, oldmap;
  385         unsigned char *p;
  386         unsigned int offs;
  387         int error = 0, win, count;
  388 
  389         if (slt == 0 || slt->state != filled)
  390                 return (ENXIO);
  391         if (pccard_mem == 0)
  392                 return (ENOMEM);
  393         for (win = slt->ctrl->maxmem - 1; win >= 0; win--)
  394                 if ((slt->mem[win].flags & MDF_ACTIVE) == 0)
  395                         break;
  396         if (win < 0)
  397                 return (EBUSY);
  398         mp = &slt->mem[win];
  399         oldmap = *mp;
  400         mp->flags = slt->rwmem | MDF_ACTIVE;
  401         while (uio->uio_resid && error == 0) {
  402                 mp->card = uio->uio_offset;
  403                 mp->size = PCCARD_MEMSIZE;
  404                 mp->start = (caddr_t)(void *)(uintptr_t)pccard_mem;
  405                 if ((error = slt->ctrl->mapmem(slt, win)) != 0)
  406                         break;
  407                 offs = (unsigned int)uio->uio_offset & (PCCARD_MEMSIZE - 1);
  408                 p = pccard_kmem + offs;
  409                 count = MIN(PCCARD_MEMSIZE - offs, uio->uio_resid);
  410                 error = uiomove(p, count, uio);
  411         }
  412         /*
  413          *      Restore original map.
  414          */
  415         *mp = oldmap;
  416         slt->ctrl->mapmem(slt, win);
  417 
  418         return (error);
  419 }
  420 
  421 /*
  422  *      crdwrite - Write data to card memory.
  423  *      Handles wrap around so that only one memory
  424  *      window is used.
  425  */
  426 static  int
  427 crdwrite(dev_t dev, struct uio *uio, int ioflag)
  428 {
  429         struct slot *slt = PCCARD_DEV2SOFTC(dev);
  430         struct mem_desc *mp, oldmap;
  431         unsigned char *p;
  432         unsigned int offs;
  433         int error = 0, win, count;
  434 
  435         if (slt == 0 || slt->state != filled)
  436                 return (ENXIO);
  437         if (pccard_mem == 0)
  438                 return (ENOMEM);
  439         for (win = slt->ctrl->maxmem - 1; win >= 0; win--)
  440                 if ((slt->mem[win].flags & MDF_ACTIVE) == 0)
  441                         break;
  442         if (win < 0)
  443                 return (EBUSY);
  444         mp = &slt->mem[win];
  445         oldmap = *mp;
  446         mp->flags = slt->rwmem | MDF_ACTIVE;
  447         while (uio->uio_resid && error == 0) {
  448                 mp->card = uio->uio_offset;
  449                 mp->size = PCCARD_MEMSIZE;
  450                 mp->start = (caddr_t)(void *)(uintptr_t)pccard_mem;
  451                 if ((error = slt->ctrl->mapmem(slt, win)) != 0)
  452                         break;
  453                 offs = (unsigned int)uio->uio_offset & (PCCARD_MEMSIZE - 1);
  454                 p = pccard_kmem + offs;
  455                 count = MIN(PCCARD_MEMSIZE - offs, uio->uio_resid);
  456                 error = uiomove(p, count, uio);
  457         }
  458         /*
  459          *      Restore original map.
  460          */
  461         *mp = oldmap;
  462         slt->ctrl->mapmem(slt, win);
  463 
  464         return (error);
  465 }
  466 
  467 /*
  468  *      ioctl calls - allows setting/getting of memory and I/O
  469  *      descriptors, and assignment of drivers.
  470  */
  471 static  int
  472 crdioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, d_thread_t *td)
  473 {
  474         u_int32_t       addr;
  475         int             err;
  476         struct io_desc  *ip;
  477         struct mem_desc *mp;
  478         device_t        pccarddev;
  479         int             pwval;
  480         int             s;
  481         struct slot     *slt = PCCARD_DEV2SOFTC(dev);
  482 
  483         if (slt == 0 && cmd != PIOCRWMEM)
  484                 return (ENXIO);
  485         switch(cmd) {
  486         default:
  487                 if (slt->ctrl->ioctl)
  488                         return (slt->ctrl->ioctl(slt, cmd, data));
  489                 return (ENOTTY);
  490         /*
  491          * Get slot state.
  492          */
  493         case PIOCGSTATE:
  494                 s = splhigh();
  495                 ((struct slotstate *)data)->state = slt->state;
  496                 ((struct slotstate *)data)->laststate = slt->laststate;
  497                 slt->laststate = slt->state;
  498                 splx(s);
  499                 ((struct slotstate *)data)->maxmem = slt->ctrl->maxmem;
  500                 ((struct slotstate *)data)->maxio = slt->ctrl->maxio;
  501                 ((struct slotstate *)data)->irqs = 0;
  502                 break;
  503         /*
  504          * Get memory context.
  505          */
  506         case PIOCGMEM:
  507                 s = ((struct mem_desc *)data)->window;
  508                 if (s < 0 || s >= slt->ctrl->maxmem)
  509                         return (EINVAL);
  510                 mp = &slt->mem[s];
  511                 ((struct mem_desc *)data)->flags = mp->flags;
  512                 ((struct mem_desc *)data)->start = mp->start;
  513                 ((struct mem_desc *)data)->size = mp->size;
  514                 ((struct mem_desc *)data)->card = mp->card;
  515                 break;
  516         /*
  517          * Set memory context. If context already active, then unmap it.
  518          * It is hard to see how the parameters can be checked.
  519          * At the very least, we only allow root to set the context.
  520          */
  521         case PIOCSMEM:
  522                 if (suser(td))
  523                         return (EPERM);
  524                 if (slt->state != filled)
  525                         return (ENXIO);
  526                 s = ((struct mem_desc *)data)->window;
  527                 if (s < 0 || s >= slt->ctrl->maxmem)
  528                         return (EINVAL);
  529                 slt->mem[s] = *((struct mem_desc *)data);
  530                 return (slt->ctrl->mapmem(slt, s));
  531         /*
  532          * Get I/O port context.
  533          */
  534         case PIOCGIO:
  535                 s = ((struct io_desc *)data)->window;
  536                 if (s < 0 || s >= slt->ctrl->maxio)
  537                         return (EINVAL);
  538                 ip = &slt->io[s];
  539                 ((struct io_desc *)data)->flags = ip->flags;
  540                 ((struct io_desc *)data)->start = ip->start;
  541                 ((struct io_desc *)data)->size = ip->size;
  542                 break;
  543         /*
  544          * Set I/O port context.
  545          */
  546         case PIOCSIO:
  547                 if (suser(td))
  548                         return (EPERM);
  549                 if (slt->state != filled)
  550                         return (ENXIO);
  551                 s = ((struct io_desc *)data)->window;
  552                 if (s < 0 || s >= slt->ctrl->maxio)
  553                         return (EINVAL);
  554                 slt->io[s] = *((struct io_desc *)data);
  555                 /* XXX Don't actually map */
  556                 return (0);
  557                 break;
  558         /*
  559          * Set memory window flags for read/write interface.
  560          */
  561         case PIOCRWFLAG:
  562                 slt->rwmem = *(int *)data;
  563                 break;
  564         /*
  565          * Set the memory window to be used for the read/write interface.
  566          */
  567         case PIOCRWMEM:
  568                 if (*(unsigned long *)data == 0) {
  569                         *(unsigned long *)data = pccard_mem;
  570                         break;
  571                 }
  572                 if (suser(td))
  573                         return (EPERM);
  574                 /*
  575                  * Validate the memory by checking it against the I/O
  576                  * memory range. It must also start on an aligned block size.
  577                  */
  578                 if (*(unsigned long *)data & (PCCARD_MEMSIZE-1))
  579                         return (EINVAL);
  580                 pccarddev = PCCARD_DEV2SOFTC(dev)->dev;
  581                 pccard_mem_rid = 0;
  582                 addr = *(unsigned long *)data;
  583                 if (pccard_mem_res)
  584                         bus_release_resource(pccarddev, SYS_RES_MEMORY,
  585                             pccard_mem_rid, pccard_mem_res);
  586                 pccard_mem_res = bus_alloc_resource(pccarddev, SYS_RES_MEMORY,
  587                     &pccard_mem_rid, addr, addr, PCCARD_MEMSIZE,
  588                     RF_ACTIVE | rman_make_alignment_flags(PCCARD_MEMSIZE));
  589                 if (pccard_mem_res == NULL)
  590                         return (EINVAL);
  591                 pccard_mem = rman_get_start(pccard_mem_res);
  592                 pccard_kmem = rman_get_virtual(pccard_mem_res);
  593                 break;
  594         /*
  595          * Set power values.
  596          */
  597         case PIOCSPOW:
  598                 slt->pwr = *(struct power *)data;
  599                 return (slt->ctrl->power(slt));
  600         /*
  601          * Allocate a driver to this slot.
  602          */
  603         case PIOCSDRV:
  604                 if (suser(td))
  605                         return (EPERM);
  606                 err = allocate_driver(slt, (struct dev_desc *)data);
  607                 if (!err)
  608                         pccard_success_beep();
  609                 else
  610                         pccard_failure_beep();
  611                 return (err);
  612         /*
  613          * Virtual removal/insertion
  614          */
  615         case PIOCSVIR:
  616                 pwval = *(int *)data;
  617                 if (!pwval) {
  618                         if (slt->state != filled)
  619                                 return (EINVAL);
  620                         pccard_event(slt, card_deactivated);
  621                 } else {
  622                         if (slt->state != empty && slt->state != inactive)
  623                                 return (EINVAL);
  624                         pccard_event(slt, card_inserted);
  625                 }
  626                 break;
  627         case PIOCSBEEP:
  628                 if (pccard_beep_select(*(int *)data)) {
  629                         return (EINVAL);
  630                 }
  631                 break;
  632         }
  633         return (0);
  634 }
  635 
  636 /*
  637  *      poll - Poll on exceptions will return true
  638  *      when a change in card status occurs.
  639  */
  640 static  int
  641 crdpoll(dev_t dev, int events, d_thread_t *td)
  642 {
  643         int     revents = 0;
  644         int     s;
  645         struct slot *slt = PCCARD_DEV2SOFTC(dev);
  646 
  647         if (events & (POLLIN | POLLRDNORM))
  648                 revents |= events & (POLLIN | POLLRDNORM);
  649 
  650         if (events & (POLLOUT | POLLWRNORM))
  651                 revents |= events & (POLLIN | POLLRDNORM);
  652 
  653         s = splhigh();
  654         /*
  655          *      select for exception - card event.
  656          */
  657         if (events & POLLRDBAND)
  658                 if (slt == 0 || slt->laststate != slt->state)
  659                         revents |= POLLRDBAND;
  660 
  661         if (revents == 0)
  662                 selrecord(td, &slt->selp);
  663 
  664         splx(s);
  665         return (revents);
  666 }
  667 
  668 /*
  669  *      APM hooks for suspending and resuming.
  670  */
  671 int
  672 pccard_suspend(device_t dev)
  673 {
  674         struct slot *slt = PCCARD_DEVICE2SOFTC(dev);
  675 
  676         /* This code stolen from pccard_event:card_removed */
  677         if (slt->state == filled) {
  678                 int s = splhigh();              /* nop on current */
  679                 disable_slot(slt);
  680                 slt->laststate = suspend;       /* for pccardd */
  681                 slt->state = empty;
  682                 splx(s);
  683                 printf("pccard: card disabled, slot %d\n", slt->slotnum);
  684         }
  685         /*
  686          * Disable any pending timeouts for this slot since we're
  687          * powering it down/disabling now.
  688          */
  689         untimeout(power_off_slot, (caddr_t)slt, slt->poff_ch);
  690         slt->ctrl->disable(slt);
  691         return (0);
  692 }
  693 
  694 int
  695 pccard_resume(device_t dev)
  696 {
  697         struct slot *slt = PCCARD_DEVICE2SOFTC(dev);
  698 
  699         slt->ctrl->resume(slt);
  700         return (0);
  701 }

Cache object: 9008ada2acbae7867ab5489b0c1de613


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