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

Cache object: a86c80678a2ace3da7468abccd57a066


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