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