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