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

Cache object: e6358c0e616e2ceade65812b54cfe42b


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