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