2 * pccard.c - Interface code for PC-CARD controllers.
4 * June 1995, Andrew McRae (andrew@mega.com.au)
5 *-------------------------------------------------------------------------
7 * Copyright (c) 2001 M. Warner Losh. All rights reserved.
8 * Copyright (c) 1995 Andrew McRae. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
32 * $FreeBSD: src/sys/pccard/pccard.c,v 1.106.2.15 2003/02/26 18:42:00 imp Exp $
33 * $DragonFly: src/sys/bus/pccard/pccard.c,v 1.4 2003/06/25 03:56:09 dillon Exp $
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/sysctl.h>
47 #include <machine/bus.h>
49 #include <pccard/cardinfo.h>
50 #include <pccard/driver.h>
51 #include <pccard/slot.h>
52 #include <pccard/pccard_nbk.h>
54 #include <machine/md_var.h>
56 #define MIN(a,b) ((a)<(b)?(a):(b))
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 *);
65 * The driver interface for read/write uses a block
66 * of memory in the ISA I/O memory space allocated via
69 * Now that we have different bus attachments, we should really
70 * use a better algorythm to allocate memory.
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;
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;
85 static struct cdevsw crd_cdevsw = {
93 /* strategy */ nostrategy,
102 * Power off the slot.
103 * (doing it immediately makes the removal of some cards unstable)
106 power_off_slot(void *arg)
108 struct slot *slt = (struct slot *)arg;
112 * The following will generate an interrupt. So, to hold off
113 * the interrupt unitl after disable runs so that we can get rid
114 * rid of the interrupt before it becomes unsafe to touch the
117 * XXX In current, the spl stuff is a nop.
120 /* Power off the slot. */
121 slt->pwr_off_pending = 0;
122 slt->ctrl->disable(slt);
127 * disable_slot - Disables the slot by removing
128 * the power and unmapping the I/O
131 disable_slot(struct slot *slt)
140 * Note that a race condition is possible here; if a
141 * driver is accessing the device and it is removed, then
142 * all bets are off...
144 pccarddev = slt->dev;
145 device_get_children(pccarddev, &kids, &nkids);
146 for (i = 0; i < nkids; i++) {
147 if ((ret = device_delete_child(pccarddev, kids[i])) != 0)
148 printf("pccard: delete of %s failed: %d\n",
149 device_get_nameunit(kids[i]), ret);
153 /* Power off the slot 1/2 second after removal of the card */
154 slt->poff_ch = timeout(power_off_slot, (caddr_t)slt, hz / 2);
155 slt->pwr_off_pending = 1;
159 disable_slot_to(struct slot *slt)
162 if (slt->state == empty)
163 printf("pccard: card removed, slot %d\n", slt->slotnum);
165 printf("pccard: card deactivated, slot %d\n", slt->slotnum);
166 pccard_remove_beep();
167 selwakeup(&slt->selp);
171 * pccard_init_slot - Initialize the slot controller and attach various
172 * things to it. We also make the device for it. We create the device that
173 * will be exported to devfs.
176 pccard_init_slot(device_t dev, struct slot_ctrl *ctrl)
181 slt = PCCARD_DEVICE2SOFTC(dev);
182 slotno = device_get_unit(dev);
184 slt->d = make_dev(&crd_cdevsw, slotno, 0, 0, 0600, "card%d", slotno);
185 slt->d->si_drv1 = slt;
187 slt->slotnum = slotno;
188 callout_handle_init(&slt->insert_ch);
189 callout_handle_init(&slt->poff_ch);
195 * allocate_driver - Create a new device entry for this
196 * slot, and attach a driver to it.
199 allocate_driver(struct slot *slt, struct dev_desc *desc)
201 struct pccard_devinfo *devi;
208 pccarddev = slt->dev;
209 err = device_get_children(pccarddev, &devs, &count);
214 device_printf(pccarddev,
215 "Can not attach more than one child.\n");
218 irq = ffs(desc->irqmask) - 1;
219 MALLOC(devi, struct pccard_devinfo *, sizeof(*devi), M_DEVBUF,
221 strcpy(devi->name, desc->name);
223 * Create an entry for the device under this slot.
227 bcopy(desc->misc, devi->misc, sizeof(desc->misc));
228 strcpy(devi->manufstr, desc->manufstr);
229 strcpy(devi->versstr, desc->versstr);
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);
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);
241 device_printf(pccarddev,
242 "No units available for %s. Impossible?\n",
246 device_set_flags(child, desc->flags);
247 device_set_ivars(child, devi);
249 device_printf(pccarddev, "Assigning %s:",
250 device_get_nameunit(child));
252 printf(" io 0x%x-0x%x",
253 desc->iobase, desc->iobase + desc->iosize - 1);
255 printf(" irq %d", irq);
257 printf(" mem 0x%lx-0x%lx", desc->mem,
258 desc->mem + desc->memsize - 1);
259 printf(" flags 0x%x\n", desc->flags);
261 err = bus_set_resource(child, SYS_RES_IOPORT, 0, desc->iobase,
266 err = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
270 err = bus_set_resource(child, SYS_RES_MEMORY, 0, desc->mem,
275 err = device_probe_and_attach(child);
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.
283 strncpy(desc->name, device_get_nameunit(child), sizeof(desc->name));
284 desc->name[sizeof(desc->name) - 1] = '\0';
287 device_delete_child(pccarddev, child);
292 * card insert routine - Called from a timeout to debounce
298 struct slot *slt = arg;
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.
306 untimeout(power_off_slot, (caddr_t)slt, slt->poff_ch);
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.
315 slt->ctrl->power(slt);
317 printf("pccard: card inserted, slot %d\n", slt->slotnum);
318 pccard_insert_beep();
319 slt->ctrl->reset(slt);
323 * Card event callback. Called at splhigh to prevent
324 * device interrupts from interceding.
327 pccard_event(struct slot *slt, enum card_event event)
329 if (slt->insert_seq) {
331 untimeout(inserted, (void *)slt, slt->insert_ch);
336 case card_deactivated:
337 if (slt->state == filled || slt->state == inactive) {
338 if (event == card_removed)
341 slt->state = inactive;
342 disable_slot_to(slt);
347 slt->insert_ch = timeout(inserted, (void *)slt, hz/4);
353 * Device driver interface.
356 crdopen(dev_t dev, int oflags, int devtype, d_thread_t *td)
358 struct slot *slt = PCCARD_DEV2SOFTC(dev);
363 slt->rwmem = MDF_ATTR;
368 * Close doesn't de-allocate any resources, since
369 * slots may be assigned to drivers already.
372 crdclose(dev_t dev, int fflag, int devtype, d_thread_t *td)
378 * read interface. Map memory at lseek offset,
379 * then transfer to user space.
382 crdread(dev_t dev, struct uio *uio, int ioflag)
384 struct slot *slt = PCCARD_DEV2SOFTC(dev);
385 struct mem_desc *mp, oldmap;
388 int error = 0, win, count;
390 if (slt == 0 || slt->state != filled)
394 for (win = slt->ctrl->maxmem - 1; win >= 0; win--)
395 if ((slt->mem[win].flags & MDF_ACTIVE) == 0)
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)
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);
414 * Restore original map.
417 slt->ctrl->mapmem(slt, win);
423 * crdwrite - Write data to card memory.
424 * Handles wrap around so that only one memory
428 crdwrite(dev_t dev, struct uio *uio, int ioflag)
430 struct slot *slt = PCCARD_DEV2SOFTC(dev);
431 struct mem_desc *mp, oldmap;
434 int error = 0, win, count;
436 if (slt == 0 || slt->state != filled)
440 for (win = slt->ctrl->maxmem - 1; win >= 0; win--)
441 if ((slt->mem[win].flags & MDF_ACTIVE) == 0)
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)
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);
460 * Restore original map.
463 slt->ctrl->mapmem(slt, win);
469 * ioctl calls - allows setting/getting of memory and I/O
470 * descriptors, and assignment of drivers.
473 crdioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, d_thread_t *td)
482 struct slot *slt = PCCARD_DEV2SOFTC(dev);
484 if (slt == 0 && cmd != PIOCRWMEM)
487 KKASSERT(td->td_proc != NULL);
491 if (slt->ctrl->ioctl)
492 return (slt->ctrl->ioctl(slt, cmd, data));
499 ((struct slotstate *)data)->state = slt->state;
500 ((struct slotstate *)data)->laststate = slt->laststate;
501 slt->laststate = slt->state;
503 ((struct slotstate *)data)->maxmem = slt->ctrl->maxmem;
504 ((struct slotstate *)data)->maxio = slt->ctrl->maxio;
505 ((struct slotstate *)data)->irqs = 0;
508 * Get memory context.
511 s = ((struct mem_desc *)data)->window;
512 if (s < 0 || s >= slt->ctrl->maxmem)
515 ((struct mem_desc *)data)->flags = mp->flags;
516 ((struct mem_desc *)data)->start = mp->start;
517 ((struct mem_desc *)data)->size = mp->size;
518 ((struct mem_desc *)data)->card = mp->card;
521 * Set memory context. If context already active, then unmap it.
522 * It is hard to see how the parameters can be checked.
523 * At the very least, we only allow root to set the context.
528 if (slt->state != filled)
530 s = ((struct mem_desc *)data)->window;
531 if (s < 0 || s >= slt->ctrl->maxmem)
533 slt->mem[s] = *((struct mem_desc *)data);
534 return (slt->ctrl->mapmem(slt, s));
536 * Get I/O port context.
539 s = ((struct io_desc *)data)->window;
540 if (s < 0 || s >= slt->ctrl->maxio)
543 ((struct io_desc *)data)->flags = ip->flags;
544 ((struct io_desc *)data)->start = ip->start;
545 ((struct io_desc *)data)->size = ip->size;
548 * Set I/O port context.
553 if (slt->state != filled)
555 s = ((struct io_desc *)data)->window;
556 if (s < 0 || s >= slt->ctrl->maxio)
558 slt->io[s] = *((struct io_desc *)data);
559 /* XXX Don't actually map */
563 * Set memory window flags for read/write interface.
566 slt->rwmem = *(int *)data;
569 * Set the memory window to be used for the read/write interface.
572 if (*(unsigned long *)data == 0) {
573 *(unsigned long *)data = pccard_mem;
579 * Validate the memory by checking it against the I/O
580 * memory range. It must also start on an aligned block size.
582 if (*(unsigned long *)data & (PCCARD_MEMSIZE-1))
584 pccarddev = PCCARD_DEV2SOFTC(dev)->dev;
586 addr = *(unsigned long *)data;
588 bus_release_resource(pccarddev, SYS_RES_MEMORY,
589 pccard_mem_rid, pccard_mem_res);
590 pccard_mem_res = bus_alloc_resource(pccarddev, SYS_RES_MEMORY,
591 &pccard_mem_rid, addr, addr, PCCARD_MEMSIZE,
592 RF_ACTIVE | rman_make_alignment_flags(PCCARD_MEMSIZE));
593 if (pccard_mem_res == NULL)
595 pccard_mem = rman_get_start(pccard_mem_res);
596 pccard_kmem = rman_get_virtual(pccard_mem_res);
602 slt->pwr = *(struct power *)data;
603 return (slt->ctrl->power(slt));
605 * Allocate a driver to this slot.
610 err = allocate_driver(slt, (struct dev_desc *)data);
612 pccard_success_beep();
614 pccard_failure_beep();
617 * Virtual removal/insertion
620 pwval = *(int *)data;
622 if (slt->state != filled)
624 pccard_event(slt, card_deactivated);
626 if (slt->state != empty && slt->state != inactive)
628 pccard_event(slt, card_inserted);
632 if (pccard_beep_select(*(int *)data)) {
641 * poll - Poll on exceptions will return true
642 * when a change in card status occurs.
645 crdpoll(dev_t dev, int events, d_thread_t *td)
649 struct slot *slt = PCCARD_DEV2SOFTC(dev);
651 if (events & (POLLIN | POLLRDNORM))
652 revents |= events & (POLLIN | POLLRDNORM);
654 if (events & (POLLOUT | POLLWRNORM))
655 revents |= events & (POLLIN | POLLRDNORM);
659 * select for exception - card event.
661 if (events & POLLRDBAND)
662 if (slt == 0 || slt->laststate != slt->state)
663 revents |= POLLRDBAND;
666 selrecord(td, &slt->selp);
673 * APM hooks for suspending and resuming.
676 pccard_suspend(device_t dev)
678 struct slot *slt = PCCARD_DEVICE2SOFTC(dev);
680 /* This code stolen from pccard_event:card_removed */
681 if (slt->state == filled) {
682 int s = splhigh(); /* nop on current */
684 slt->laststate = suspend; /* for pccardd */
687 printf("pccard: card disabled, slot %d\n", slt->slotnum);
690 * Disable any pending timeouts for this slot since we're
691 * powering it down/disabling now.
693 untimeout(power_off_slot, (caddr_t)slt, slt->poff_ch);
694 slt->ctrl->disable(slt);
699 pccard_resume(device_t dev)
701 struct slot *slt = PCCARD_DEVICE2SOFTC(dev);
703 slt->ctrl->resume(slt);