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