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$
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 }
Cache object: 9008ada2acbae7867ab5489b0c1de613
|