FreeBSD/Linux Kernel Cross Reference
sys/pccard/pccard.c
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
|