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

Cache object: cf8cfd6565df442a0971fa45666a60bb


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