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) 1995 Andrew McRae. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/fcntl.h>
36 #include <sys/proc.h>
37 #include <sys/malloc.h>
38 #include <sys/sysctl.h>
39 #include <sys/conf.h>
40 #ifdef DEVFS
41 #include <sys/devfsext.h>
42 #endif /*DEVFS*/
43 #include <sys/uio.h>
44
45 #include <i386/isa/isa_device.h>
46 #include <i386/isa/icu.h>
47
48 #include "apm.h"
49 #if NAPM > 0
50 #include <machine/apm_bios.h>
51 #endif /* NAPM > 0 */
52
53 #include <pccard/cardinfo.h>
54 #include <pccard/driver.h>
55 #include <pccard/slot.h>
56
57 #include <machine/md_var.h>
58
59 /*
60 * XXX We shouldn't be using processor-specific/bus-specific code in
61 * here, but we need the start of the ISA hole (IOM_BEGIN).
62 */
63 #include <i386/isa/isa.h>
64
65 SYSCTL_NODE(_machdep, OID_AUTO, pccard, CTLFLAG_RW, 0, "pccard");
66
67 static int pcic_resume_reset =
68 #ifdef PCIC_RESUME_RESET
69 1;
70 #else
71 0;
72 #endif
73
74 SYSCTL_INT(_machdep_pccard, OID_AUTO, pcic_resume_reset, CTLFLAG_RW,
75 &pcic_resume_reset, 0, "");
76
77 #define PCCARD_MEMSIZE (4*1024)
78
79 #define MIN(a,b) ((a)<(b)?(a):(b))
80
81 static int allocate_driver(struct slot *, struct dev_desc *);
82 static void inserted(void *);
83 static void unregister_device_interrupt(struct pccard_devinfo *);
84 static void disable_slot(struct slot *);
85 static int invalid_io_memory(unsigned long, int);
86 static struct pccard_device *find_driver(char *);
87 static void remove_device(struct pccard_devinfo *);
88 static void slot_irq_handler(int);
89 static void power_off_slot(void *);
90
91 #if NAPM > 0
92 /*
93 * For the APM stuff, the apmhook structure is kept
94 * separate from the slot structure so that the slot
95 * drivers do not need to know about the hooks (or the
96 * data structures).
97 */
98 static int slot_suspend(void *arg);
99 static int slot_resume(void *arg);
100 static struct apmhook s_hook[MAXSLOT]; /* APM suspend */
101 static struct apmhook r_hook[MAXSLOT]; /* APM resume */
102 #endif /* NAPM > 0 */
103
104 static struct slot *pccard_slots[MAXSLOT]; /* slot entries */
105 static struct slot *slot_list;
106 static struct slot_ctrl *cont_list;
107 static struct pccard_device *drivers; /* Card drivers */
108
109 /*
110 * The driver interface for read/write uses a block
111 * of memory in the ISA I/O memory space allocated via
112 * an ioctl setting.
113 */
114 static unsigned long pccard_mem; /* Physical memory */
115 static unsigned char *pccard_kmem; /* Kernel virtual address */
116
117 static d_open_t crdopen;
118 static d_close_t crdclose;
119 static d_read_t crdread;
120 static d_write_t crdwrite;
121 static d_ioctl_t crdioctl;
122 static d_select_t crdselect;
123
124 #define CDEV_MAJOR 50
125 static struct cdevsw crd_cdevsw =
126 { crdopen, crdclose, crdread, crdwrite, /*50*/
127 crdioctl, nostop, nullreset, nodevtotty,/* pcmcia */
128 crdselect, nommap, NULL, "crd", NULL, -1 };
129
130
131 /*
132 * pccard_configure - called by autoconf code.
133 * Probes for various PC-CARD controllers, and
134 * initialises data structures to point to the
135 * various slots.
136 *
137 * Each controller indicates the number of slots
138 * that it sees, and these are mapped to a master
139 * slot number accessed via the character device entries.
140 */
141 void
142 pccard_configure(void)
143 {
144 struct pccard_device **drivers, *drv;
145
146 #include "pcic.h"
147 #if NPCIC > 0
148 pcic_probe();
149 #endif
150
151 drivers = (struct pccard_device **)pccarddrv_set.ls_items;
152 printf("Initializing PC-card drivers:");
153 while ((drv = *drivers++)) {
154 printf(" %s", drv->name);
155 pccard_add_driver(drv);
156 }
157 printf("\n");
158 }
159
160 /*
161 * pccard_add_driver - Add a new driver to the list of
162 * drivers available for allocation.
163 */
164 void
165 pccard_add_driver(struct pccard_device *drv)
166 {
167 /*
168 * If already loaded, then reject the driver.
169 */
170 if (find_driver(drv->name)) {
171 printf("Driver %s already loaded\n", drv->name);
172 return;
173 }
174 drv->next = drivers;
175 drivers = drv;
176 }
177
178 #ifdef unused
179 /*
180 * pccard_remove_driver - called to unlink driver
181 * from devices. Usually called when drivers are
182 * are unloaded from kernel.
183 */
184 void
185 pccard_remove_driver(struct pccard_device *drv)
186 {
187 struct slot *slt;
188 struct pccard_devinfo *devi, *next;
189 struct pccard_device *drvlist;
190
191 for (slt = slot_list; slt; slt = slt->next)
192 for (devi = slt->devices; devi; devi = next) {
193 next = devi->next;
194 if (devi->drv == drv)
195 remove_device(devi);
196 }
197 /*
198 * Once all the devices belonging to this driver have been
199 * freed, then remove the driver from the list
200 * of registered drivers.
201 */
202 if (drivers == drv)
203 drivers = drv->next;
204 else
205 for (drvlist = drivers; drvlist->next; drvlist = drvlist->next)
206 if (drvlist->next == drv) {
207 drvlist->next = drv->next;
208 break;
209 }
210 }
211 #endif
212
213 /*
214 * pccard_remove_controller - Called when the slot
215 * driver is unloaded. The plan is to unload
216 * drivers from the slots, and then remove the
217 * slots from the slot list, and then finally
218 * remove the controller structure. Messy...
219 */
220 void
221 pccard_remove_controller(struct slot_ctrl *ctrl)
222 {
223 struct slot *slt, *next, *last = 0;
224 struct slot_ctrl *cl;
225 struct pccard_devinfo *devi;
226
227 for (slt = slot_list; slt; slt = next) {
228 next = slt->next;
229 /*
230 * If this slot belongs to this controller,
231 * remove this slot.
232 */
233 if (slt->ctrl == ctrl) {
234 pccard_slots[slt->slotnum] = 0;
235 if (slt->insert_seq)
236 untimeout(inserted, (void *)slt);
237 /*
238 * Unload the drivers attached to this slot.
239 */
240 while (devi = slt->devices)
241 remove_device(devi);
242 /*
243 * Disable the slot and unlink the slot from the
244 * slot list.
245 */
246 disable_slot(slt);
247 if (last)
248 last->next = next;
249 else
250 slot_list = next;
251 #if NAPM > 0
252 apm_hook_disestablish(APM_HOOK_SUSPEND,
253 &s_hook[slt->slotnum]);
254 apm_hook_disestablish(APM_HOOK_RESUME,
255 &r_hook[slt->slotnum]);
256 #endif
257 if (ctrl->extra && slt->cdata)
258 FREE(slt->cdata, M_DEVBUF);
259 FREE(slt, M_DEVBUF);
260 /*
261 * Can't use slot after we have freed it.
262 */
263 } else {
264 last = slt;
265 }
266 }
267 /*
268 * Unlink controller structure from controller list.
269 */
270 if (cont_list == ctrl)
271 cont_list = ctrl->next;
272 else
273 for (cl = cont_list; cl->next; cl = cl->next)
274 if (cl->next == ctrl) {
275 cl->next = ctrl->next;
276 break;
277 }
278 }
279
280 /*
281 * Power off the slot.
282 * (doing it immediately makes the removal of some cards unstable)
283 */
284 static void
285 power_off_slot(void *arg)
286 {
287 struct slot *slt = (struct slot *)arg;
288
289 /* Power off the slot. */
290 slt->pwr_off_pending = 0;
291 slt->ctrl->disable(slt);
292 }
293
294 /*
295 * unregister_device_interrupt - Disable the interrupt generation to
296 * the device driver which is handling it, so we can remove it.
297 */
298 static void
299 unregister_device_interrupt(struct pccard_devinfo *devi)
300 {
301 struct slot *slt = devi->slt;
302 int s;
303
304 if (devi->running) {
305 s = splhigh();
306 devi->drv->disable(devi);
307 devi->running = 0;
308 if (devi->isahd.id_irq && --slt->irqref <= 0) {
309 printf("Return IRQ=%d\n",slt->irq);
310 slt->ctrl->mapirq(slt, 0);
311 INTRDIS(1<<slt->irq);
312 unregister_intr(slt->irq, slot_irq_handler);
313 if (devi->drv->imask)
314 INTRUNMASK(*devi->drv->imask,(1<<slt->irq));
315 /* Remove from the PCIC controller imask */
316 if (slt->ctrl->imask)
317 INTRUNMASK(*(slt->ctrl->imask), (1<<slt->irq));
318 slt->irq = 0;
319 }
320 splx(s);
321 }
322 }
323
324 /*
325 * disable_slot - Disables the slot by removing
326 * the power and unmapping the I/O
327 */
328 static void
329 disable_slot(struct slot *slt)
330 {
331 struct pccard_devinfo *devi;
332 int i;
333 /*
334 * Unload all the drivers on this slot. Note we can't
335 * remove the device structures themselves, because this
336 * may be called from the event routine, which is called
337 * from the slot controller's ISR, and removing the structures
338 * shouldn't happen during the middle of some driver activity.
339 *
340 * Note that a race condition is possible here; if a
341 * driver is accessing the device and it is removed, then
342 * all bets are off...
343 */
344 for (devi = slt->devices; devi; devi = devi->next)
345 unregister_device_interrupt(devi);
346
347 /* Power off the slot 1/2 second after removal of the card */
348 timeout(power_off_slot, (caddr_t)slt, hz / 2);
349 slt->pwr_off_pending = 1;
350
351 /* De-activate all contexts. */
352 for (i = 0; i < slt->ctrl->maxmem; i++)
353 if (slt->mem[i].flags & MDF_ACTIVE) {
354 slt->mem[i].flags = 0;
355 (void)slt->ctrl->mapmem(slt, i);
356 }
357 for (i = 0; i < slt->ctrl->maxio; i++)
358 if (slt->io[i].flags & IODF_ACTIVE) {
359 slt->io[i].flags = 0;
360 (void)slt->ctrl->mapio(slt, i);
361 }
362 }
363
364 /*
365 * APM hooks for suspending and resuming.
366 */
367 #if NAPM > 0
368 static int
369 slot_suspend(void *arg)
370 {
371 struct slot *slt = arg;
372
373 /* This code stolen from pccard_event:card_removed */
374 if (slt->state == filled) {
375 int s = splhigh();
376 disable_slot(slt);
377 slt->state = suspend;
378 splx(s);
379 printf("Card disabled, slot %d\n", slt->slotnum);
380 }
381 /*
382 * Disable any pending timeouts for this slot since we're
383 * powering it down/disabling now.
384 */
385 untimeout(power_off_slot, (caddr_t)slt);
386 slt->ctrl->disable(slt);
387 return (0);
388 }
389
390 static int
391 slot_resume(void *arg)
392 {
393 struct slot *slt = arg;
394
395 if (pcic_resume_reset)
396 slt->ctrl->resume(slt);
397 /* This code stolen from pccard_event:card_inserted */
398 if (slt->state == suspend) {
399 slt->state = empty;
400 slt->insert_seq = 1;
401 timeout(inserted, (void *)slt, hz/4);
402 selwakeup(&slt->selp);
403 }
404 return (0);
405 }
406 #endif /* NAPM > 0 */
407
408 /*
409 * pccard_alloc_slot - Called from controller probe
410 * routine, this function allocates a new PC-CARD slot
411 * and initialises the data structures using the data provided.
412 * It returns the allocated structure to the probe routine
413 * to allow the controller specific data to be initialised.
414 */
415 struct slot *
416 pccard_alloc_slot(struct slot_ctrl *ctrl)
417 {
418 struct slot *slt;
419 int slotno;
420
421 for (slotno = 0; slotno < MAXSLOT; slotno++)
422 if (pccard_slots[slotno] == 0)
423 break;
424 if (slotno == MAXSLOT)
425 return(0);
426
427 MALLOC(slt, struct slot *, sizeof(*slt), M_DEVBUF, M_WAITOK);
428 bzero(slt, sizeof(*slt));
429 #ifdef DEVFS
430 slt->devfs_token = devfs_add_devswf(&crd_cdevsw,
431 0, DV_CHR, 0, 0, 0600, "card%d", slotno);
432 #endif
433 if (ctrl->extra) {
434 MALLOC(slt->cdata, void *, ctrl->extra, M_DEVBUF, M_WAITOK);
435 bzero(slt->cdata, ctrl->extra);
436 }
437 slt->ctrl = ctrl;
438 slt->slotnum = slotno;
439 pccard_slots[slotno] = slt;
440 slt->next = slot_list;
441 slot_list = slt;
442 /*
443 * If this controller hasn't been seen before, then
444 * link it into the list of controllers.
445 */
446 if (ctrl->slots++ == 0) {
447 ctrl->next = cont_list;
448 cont_list = ctrl;
449 if (ctrl->maxmem > NUM_MEM_WINDOWS)
450 ctrl->maxmem = NUM_MEM_WINDOWS;
451 if (ctrl->maxio > NUM_IO_WINDOWS)
452 ctrl->maxio = NUM_IO_WINDOWS;
453 printf("PC-Card %s (%d mem & %d I/O windows)\n",
454 ctrl->name, ctrl->maxmem, ctrl->maxio);
455 }
456 #if NAPM > 0
457 {
458 struct apmhook *ap;
459
460 ap = &s_hook[slt->slotnum];
461 ap->ah_fun = slot_suspend;
462 ap->ah_arg = (void *)slt;
463 ap->ah_name = ctrl->name;
464 ap->ah_order = APM_MID_ORDER;
465 apm_hook_establish(APM_HOOK_SUSPEND, ap);
466 ap = &r_hook[slt->slotnum];
467 ap->ah_fun = slot_resume;
468 ap->ah_arg = (void *)slt;
469 ap->ah_name = ctrl->name;
470 ap->ah_order = APM_MID_ORDER;
471 apm_hook_establish(APM_HOOK_RESUME, ap);
472 }
473 #endif /* NAPM > 0 */
474 return(slt);
475 }
476
477 /*
478 * pccard_alloc_intr - allocate an interrupt from the
479 * free interrupts and return its number. The interrupts
480 * allowed are passed as a mask.
481 */
482 int
483 pccard_alloc_intr(u_int imask, inthand2_t *hand, int unit,
484 u_int *maskp, u_int *pcic_imask)
485 {
486 int irq;
487 unsigned int mask;
488
489 for (irq = 1; irq < ICU_LEN; irq++) {
490 mask = 1ul << irq;
491 if (!(mask & imask))
492 continue;
493 INTRMASK(*maskp, mask);
494 if (register_intr(irq, 0, 0, hand, maskp, unit) == 0) {
495 /* add this to the PCIC controller's mask */
496 if (pcic_imask)
497 INTRMASK(*pcic_imask, (1 << irq));
498 update_intr_masks();
499 INTREN(mask);
500 return(irq);
501 }
502 /* No luck, remove from mask again... */
503 INTRUNMASK(*maskp, mask);
504 update_intr_masks();
505 }
506 return(-1);
507 }
508
509 /*
510 * allocate_driver - Create a new device entry for this
511 * slot, and attach a driver to it.
512 */
513 static int
514 allocate_driver(struct slot *slt, struct dev_desc *desc)
515 {
516 struct pccard_devinfo *devi;
517 struct pccard_device *drv;
518 int err, irq = 0, s;
519
520 drv = find_driver(desc->name);
521 if (drv == 0)
522 return(ENXIO);
523 /*
524 * If an instance of this driver is already installed,
525 * but not running, then remove it. If it is running,
526 * then reject the request.
527 */
528 for (devi = slt->devices; devi; devi = devi->next)
529 if (devi->drv == drv && devi->isahd.id_unit == desc->unit) {
530 if (devi->running)
531 return(EBUSY);
532 remove_device(devi);
533 break;
534 }
535 /*
536 * If an interrupt mask has been given, then check it
537 * against the slot interrupt (if one has been allocated).
538 */
539 if (desc->irqmask && drv->imask) {
540 if ((slt->ctrl->irqs & desc->irqmask) == 0)
541 return(EINVAL);
542 if (slt->irq) {
543 if (((1 << slt->irq) & desc->irqmask) == 0)
544 return(EINVAL);
545 slt->irqref++;
546 irq = slt->irq;
547 } else {
548 /*
549 * Attempt to allocate an interrupt.
550 * XXX We lose at the moment if the second
551 * device relies on a different interrupt mask.
552 */
553 irq = pccard_alloc_intr(desc->irqmask,
554 slot_irq_handler, (int)slt,
555 drv->imask, slt->ctrl->imask);
556 if (irq < 0)
557 return(EINVAL);
558 slt->irq = irq;
559 slt->irqref = 1;
560 slt->ctrl->mapirq(slt, slt->irq);
561 }
562 }
563 MALLOC(devi, struct pccard_devinfo *, sizeof(*devi), M_DEVBUF, M_WAITOK);
564 bzero(devi, sizeof(*devi));
565 /*
566 * Create an entry for the device under this slot.
567 */
568 devi->running = 1;
569 devi->drv = drv;
570 devi->slt = slt;
571 devi->isahd.id_irq = irq;
572 devi->isahd.id_unit = desc->unit;
573 devi->isahd.id_msize = desc->memsize;
574 devi->isahd.id_iobase = desc->iobase;
575 bcopy(desc->misc, devi->misc, sizeof(desc->misc));
576 if (irq)
577 devi->isahd.id_irq = 1 << irq;
578 devi->isahd.id_flags = desc->flags;
579 /*
580 * Convert the memory to kernel space.
581 */
582 if (desc->mem)
583 devi->isahd.id_maddr =
584 (caddr_t)(desc->mem + atdevbase - IOM_BEGIN);
585 else
586 devi->isahd.id_maddr = 0;
587 devi->next = slt->devices;
588 slt->devices = devi;
589 s = splhigh();
590 err = drv->enable(devi);
591 splx(s);
592 /*
593 * If the enable functions returns no error, then the
594 * device has been successfully installed. If so, then
595 * attach it to the slot, otherwise free it and return
596 * the error. We assume that when we free the device,
597 * it will also set 'running' to off.
598 */
599 if (err)
600 remove_device(devi);
601 return(err);
602 }
603
604 static void
605 remove_device(struct pccard_devinfo *devi)
606 {
607 struct slot *slt = devi->slt;
608 struct pccard_devinfo *list;
609
610 /*
611 * If an interrupt is enabled on this slot,
612 * then unregister it if no-one else is using it.
613 */
614 unregister_device_interrupt(devi);
615 /*
616 * Remove from device list on this slot.
617 */
618 if (slt->devices == devi)
619 slt->devices = devi->next;
620 else
621 for (list = slt->devices; list->next; list = list->next)
622 if (list->next == devi) {
623 list->next = devi->next;
624 break;
625 }
626 /*
627 * Finally, free the memory space.
628 */
629 FREE(devi, M_DEVBUF);
630 }
631
632 /*
633 * card insert routine - Called from a timeout to debounce
634 * insertion events.
635 */
636 static void
637 inserted(void *arg)
638 {
639 struct slot *slt = arg;
640
641 slt->state = filled;
642 /*
643 * Enable 5V to the card so that the CIS can be read.
644 */
645 slt->pwr.vcc = 50;
646 slt->pwr.vpp = 0;
647 /*
648 * Disable any pending timeouts for this slot, and explicitly
649 * power it off right now. Then, re-enable the power using
650 * the (possibly new) power settings.
651 */
652 untimeout(power_off_slot, (caddr_t)slt);
653 power_off_slot(slt);
654 slt->ctrl->power(slt);
655
656 printf("Card inserted, slot %d\n", slt->slotnum);
657 /*
658 * Now start resetting the card.
659 */
660 slt->ctrl->reset(slt);
661 }
662
663 /*
664 * Card event callback. Called at splhigh to prevent
665 * device interrupts from interceding.
666 */
667 void
668 pccard_event(struct slot *slt, enum card_event event)
669 {
670 if (slt->insert_seq) {
671 slt->insert_seq = 0;
672 untimeout(inserted, (void *)slt);
673 }
674
675 switch(event) {
676 case card_removed:
677 /*
678 * The slot and devices are disabled, but the
679 * data structures are not unlinked.
680 */
681 if (slt->state == filled) {
682 int s = splhigh();
683 disable_slot(slt);
684 slt->state = empty;
685 splx(s);
686 printf("Card removed, slot %d\n", slt->slotnum);
687 pccard_remove_beep();
688 selwakeup(&slt->selp);
689 }
690 break;
691 case card_inserted:
692 slt->insert_seq = 1;
693 timeout(inserted, (void *)slt, hz/4);
694 pccard_remove_beep();
695 break;
696 }
697 }
698
699 /*
700 * slot_irq_handler - Interrupt handler for shared irq devices.
701 */
702 static void
703 slot_irq_handler(int arg)
704 {
705 struct pccard_devinfo *devi;
706 struct slot *slt = (struct slot *)arg;
707
708 /*
709 * For each device that has the shared interrupt,
710 * call the interrupt handler. If the interrupt was
711 * caught, the handler returns true.
712 */
713 for (devi = slt->devices; devi; devi = devi->next)
714 if (devi->isahd.id_irq && devi->running &&
715 devi->drv->handler(devi))
716 return;
717 /*
718 * XXX - Should 'debounce' these for drivers that have recently
719 * been removed.
720 */
721 printf("Slot %d, unfielded interrupt (%d)\n", slt->slotnum, slt->irq);
722 }
723
724 /*
725 * Device driver interface.
726 */
727 static int
728 crdopen(dev_t dev, int oflags, int devtype, struct proc *p)
729 {
730 struct slot *slt;
731
732 if (minor(dev) >= MAXSLOT)
733 return(ENXIO);
734 slt = pccard_slots[minor(dev)];
735 if (slt == 0)
736 return(ENXIO);
737 if (slt->rwmem == 0)
738 slt->rwmem = MDF_ATTR;
739 return(0);
740 }
741
742 /*
743 * Close doesn't de-allocate any resources, since
744 * slots may be assigned to drivers already.
745 */
746 static int
747 crdclose(dev_t dev, int fflag, int devtype, struct proc *p)
748 {
749 return(0);
750 }
751
752 /*
753 * read interface. Map memory at lseek offset,
754 * then transfer to user space.
755 */
756 static int
757 crdread(dev_t dev, struct uio *uio, int ioflag)
758 {
759 struct slot *slt = pccard_slots[minor(dev)];
760 struct mem_desc *mp, oldmap;
761 unsigned char *p;
762 unsigned int offs;
763 int error = 0, win, count;
764
765 if (slt == 0 || slt->state != filled)
766 return(ENXIO);
767 if (pccard_mem == 0)
768 return(ENOMEM);
769 for (win = 0; win < slt->ctrl->maxmem; win++)
770 if ((slt->mem[win].flags & MDF_ACTIVE) == 0)
771 break;
772 if (win >= slt->ctrl->maxmem)
773 return(EBUSY);
774 mp = &slt->mem[win];
775 oldmap = *mp;
776 mp->flags = slt->rwmem|MDF_ACTIVE;
777 #if 0
778 printf("Rd at offs %d, size %d\n", (int)uio->uio_offset,
779 uio->uio_resid);
780 #endif
781 while (uio->uio_resid && error == 0) {
782 mp->card = uio->uio_offset;
783 mp->size = PCCARD_MEMSIZE;
784 mp->start = (caddr_t)pccard_mem;
785 if (error = slt->ctrl->mapmem(slt, win))
786 break;
787 offs = (unsigned int)uio->uio_offset & (PCCARD_MEMSIZE - 1);
788 p = pccard_kmem + offs;
789 count = MIN(PCCARD_MEMSIZE - offs, uio->uio_resid);
790 error = uiomove(p, count, uio);
791 }
792 /*
793 * Restore original map.
794 */
795 *mp = oldmap;
796 slt->ctrl->mapmem(slt, win);
797
798 return(error);
799 }
800
801 /*
802 * crdwrite - Write data to card memory.
803 * Handles wrap around so that only one memory
804 * window is used.
805 */
806 static int
807 crdwrite(dev_t dev, struct uio *uio, int ioflag)
808 {
809 struct slot *slt = pccard_slots[minor(dev)];
810 struct mem_desc *mp, oldmap;
811 unsigned char *p;
812 unsigned int offs;
813 int error = 0, win, count;
814
815 if (slt == 0 || slt->state != filled)
816 return(ENXIO);
817 if (pccard_mem == 0)
818 return(ENOMEM);
819 for (win = 0; win < slt->ctrl->maxmem; win++)
820 if ((slt->mem[win].flags & MDF_ACTIVE)==0)
821 break;
822 if (win >= slt->ctrl->maxmem)
823 return(EBUSY);
824 mp = &slt->mem[win];
825 oldmap = *mp;
826 mp->flags = slt->rwmem|MDF_ACTIVE;
827 #if 0
828 printf("Wr at offs %d, size %d\n", (int)uio->uio_offset,
829 uio->uio_resid);
830 #endif
831 while (uio->uio_resid && error == 0) {
832 mp->card = uio->uio_offset;
833 mp->size = PCCARD_MEMSIZE;
834 mp->start = (caddr_t)pccard_mem;
835 if (error = slt->ctrl->mapmem(slt, win))
836 break;
837 offs = (unsigned int)uio->uio_offset & (PCCARD_MEMSIZE - 1);
838 p = pccard_kmem + offs;
839 count = MIN(PCCARD_MEMSIZE - offs, uio->uio_resid);
840 #if 0
841 printf("Writing %d bytes to address 0x%x\n", count, p);
842 #endif
843 error = uiomove(p, count, uio);
844 }
845 /*
846 * Restore original map.
847 */
848 *mp = oldmap;
849 slt->ctrl->mapmem(slt, win);
850
851 return(error);
852 }
853
854 /*
855 * ioctl calls - allows setting/getting of memory and I/O
856 * descriptors, and assignment of drivers.
857 */
858 static int
859 crdioctl(dev_t dev, int cmd, caddr_t data, int fflag, struct proc *p)
860 {
861 struct slot *slt = pccard_slots[minor(dev)];
862 struct mem_desc *mp;
863 struct io_desc *ip;
864 int s, err;
865
866 /* beep is disabled until the 1st call of crdioctl() */
867 pccard_beep_select(BEEP_ON);
868
869 if (slt == 0 && cmd != PIOCRWMEM)
870 return(ENXIO);
871 switch(cmd) {
872 default:
873 if (slt->ctrl->ioctl)
874 return(slt->ctrl->ioctl(slt, cmd, data));
875 return(EINVAL);
876 /*
877 * Get slot state.
878 */
879 case PIOCGSTATE:
880 s = splhigh();
881 ((struct slotstate *)data)->state = slt->state;
882 slt->laststate = slt->state;
883 splx(s);
884 ((struct slotstate *)data)->maxmem = slt->ctrl->maxmem;
885 ((struct slotstate *)data)->maxio = slt->ctrl->maxio;
886 ((struct slotstate *)data)->irqs = slt->ctrl->irqs;
887 break;
888 /*
889 * Get memory context.
890 */
891 case PIOCGMEM:
892 s = ((struct mem_desc *)data)->window;
893 if (s < 0 || s >= slt->ctrl->maxmem)
894 return(EINVAL);
895 mp = &slt->mem[s];
896 ((struct mem_desc *)data)->flags = mp->flags;
897 ((struct mem_desc *)data)->start = mp->start;
898 ((struct mem_desc *)data)->size = mp->size;
899 ((struct mem_desc *)data)->card = mp->card;
900 break;
901 /*
902 * Set memory context. If context already active, then unmap it.
903 * It is hard to see how the parameters can be checked.
904 * At the very least, we only allow root to set the context.
905 */
906 case PIOCSMEM:
907 if (suser(p->p_ucred, &p->p_acflag))
908 return(EPERM);
909 if (slt->state != filled)
910 return(ENXIO);
911 s = ((struct mem_desc *)data)->window;
912 if (s < 0 || s >= slt->ctrl->maxmem)
913 return(EINVAL);
914 slt->mem[s] = *((struct mem_desc *)data);
915 return(slt->ctrl->mapmem(slt, s));
916 /*
917 * Get I/O port context.
918 */
919 case PIOCGIO:
920 s = ((struct io_desc *)data)->window;
921 if (s < 0 || s >= slt->ctrl->maxio)
922 return(EINVAL);
923 ip = &slt->io[s];
924 ((struct io_desc *)data)->flags = ip->flags;
925 ((struct io_desc *)data)->start = ip->start;
926 ((struct io_desc *)data)->size = ip->size;
927 break;
928 /*
929 * Set I/O port context.
930 */
931 case PIOCSIO:
932 if (suser(p->p_ucred, &p->p_acflag))
933 return(EPERM);
934 if (slt->state != filled)
935 return(ENXIO);
936 s = ((struct io_desc *)data)->window;
937 if (s < 0 || s >= slt->ctrl->maxio)
938 return(EINVAL);
939 slt->io[s] = *((struct io_desc *)data);
940 return(slt->ctrl->mapio(slt, s));
941 break;
942 /*
943 * Set memory window flags for read/write interface.
944 */
945 case PIOCRWFLAG:
946 slt->rwmem = *(int *)data;
947 break;
948 /*
949 * Set the memory window to be used for the read/write interface.
950 */
951 case PIOCRWMEM:
952 if (*(unsigned long *)data == 0) {
953 if (pccard_mem)
954 *(unsigned long *)data = pccard_mem;
955 break;
956 }
957 if (suser(p->p_ucred, &p->p_acflag))
958 return(EPERM);
959 /*
960 * Validate the memory by checking it against the I/O
961 * memory range. It must also start on an aligned block size.
962 */
963 if (invalid_io_memory(*(unsigned long *)data, PCCARD_MEMSIZE))
964 return(EINVAL);
965 if (*(unsigned long *)data & (PCCARD_MEMSIZE-1))
966 return(EINVAL);
967 /*
968 * Map it to kernel VM.
969 */
970 pccard_mem = *(unsigned long *)data;
971 pccard_kmem = (unsigned char *)(pccard_mem
972 + atdevbase - IOM_BEGIN);
973 break;
974 /*
975 * Set power values.
976 */
977 case PIOCSPOW:
978 slt->pwr = *(struct power *)data;
979 return(slt->ctrl->power(slt));
980 /*
981 * Allocate a driver to this slot.
982 */
983 case PIOCSDRV:
984 if (suser(p->p_ucred, &p->p_acflag))
985 return(EPERM);
986 err = allocate_driver(slt, (struct dev_desc *)data);
987 if (!err)
988 pccard_success_beep();
989 else
990 pccard_failure_beep();
991 return err;
992 }
993 return(0);
994 }
995
996 /*
997 * select - Selects on exceptions will return true
998 * when a change in card status occurs.
999 */
1000 static int
1001 crdselect(dev_t dev, int rw, struct proc *p)
1002 {
1003 int s;
1004 struct slot *slt = pccard_slots[minor(dev)];
1005
1006 switch (rw) {
1007 case FREAD:
1008 return 1;
1009 case FWRITE:
1010 return 1;
1011 /*
1012 * select for exception - card event.
1013 */
1014 case 0:
1015 s = splhigh();
1016 if (slt == 0 || slt->laststate != slt->state) {
1017 splx(s);
1018 return(1);
1019 }
1020 selrecord(p, &slt->selp);
1021 splx(s);
1022 }
1023 return(0);
1024 }
1025
1026 /*
1027 * invalid_io_memory - verify that the ISA I/O memory block
1028 * is a valid and unallocated address.
1029 * A simple check of the range is done, and then a
1030 * search of the current devices is done to check for
1031 * overlapping regions.
1032 */
1033 static int
1034 invalid_io_memory(unsigned long adr, int size)
1035 {
1036 /* XXX - What's magic about 0xC0000?? */
1037 if (adr < 0xC0000 || (adr+size) > IOM_END)
1038 return(1);
1039 return(0);
1040 }
1041
1042 static struct pccard_device *
1043 find_driver(char *name)
1044 {
1045 struct pccard_device *drv;
1046
1047 for (drv = drivers; drv; drv = drv->next)
1048 if (strcmp(drv->name, name)==0)
1049 return(drv);
1050 return(0);
1051 }
1052
1053 static crd_devsw_installed = 0;
1054
1055 static void
1056 crd_drvinit(void *unused)
1057 {
1058 dev_t dev;
1059
1060 if (!crd_devsw_installed) {
1061 dev = makedev(CDEV_MAJOR, 0);
1062 cdevsw_add(&dev, &crd_cdevsw, NULL);
1063 crd_devsw_installed = 1;
1064 }
1065 }
1066
1067 SYSINIT(crddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,crd_drvinit,NULL)
Cache object: 1d314f12b882c745c30efcb6d0edbcb1
|