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

Cache object: c47acb73b0ad468f88c0e2913279e9dc


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