]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/pccard/pccard.c
Forget to change lookup function for oldcard side.
[FreeBSD/FreeBSD.git] / 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         devi->manufacturer = desc->manufacturer;
228         devi->product = desc->product;
229         devi->prodext = desc->prodext;
230         resource_list_init(&devi->resources);
231         child = device_add_child(pccarddev, devi->name, desc->unit);
232         if (child == NULL) {
233                 if (desc->unit != -1)
234                         device_printf(pccarddev,
235                             "Unit %d failed for %s, try a different unit\n",
236                             desc->unit, devi->name);
237                 else
238                         device_printf(pccarddev,
239                             "No units available for %s.  Impossible?\n",
240                             devi->name);
241                 return (EIO);
242         }
243         device_set_flags(child, desc->flags);
244         device_set_ivars(child, devi);
245         if (bootverbose) {
246                 device_printf(pccarddev,
247                     "Assigning %s: io 0x%x-0x%x irq %d mem 0x%lx-0x%lx\n",
248                     device_get_nameunit(child),
249                     desc->iobase, desc->iobase + desc->iosize - 1,
250                     irq, desc->mem, desc->mem + desc->memsize - 1); 
251         }
252         err = bus_set_resource(child, SYS_RES_IOPORT, 0, desc->iobase,
253             desc->iosize);
254         if (err)
255                 goto err;
256         if (irq)
257                 err = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
258         if (err)
259                 goto err;
260         if (desc->memsize) {
261                 err = bus_set_resource(child, SYS_RES_MEMORY, 0, desc->mem,
262                     desc->memsize);
263                 if (err)
264                         goto err;
265         }
266         err = device_probe_and_attach(child);
267         /*
268          * XXX We unwisely assume that the detach code won't run while the
269          * XXX the attach code is attaching.  Someone should put some
270          * XXX interlock code.  This can happen if probe/attach takes a while
271          * XXX and the user ejects the card, which causes the detach
272          * XXX function to be called.
273          */
274         strncpy(desc->name, device_get_nameunit(child), sizeof(desc->name));
275         desc->name[sizeof(desc->name) - 1] = '\0';
276 err:
277         if (err)
278                 device_delete_child(pccarddev, child);
279         return (err);
280 }
281
282 /*
283  *      card insert routine - Called from a timeout to debounce
284  *      insertion events.
285  */
286 static void
287 inserted(void *arg)
288 {
289         struct slot *slt = arg;
290
291         slt->state = filled;
292         /*
293          *      Enable 5V to the card so that the CIS can be read.
294          */
295         slt->pwr.vcc = -1;
296         slt->pwr.vpp = -1;
297
298         /*
299          * Disable any pending timeouts for this slot, and explicitly
300          * power it off right now.  Then, re-enable the power using
301          * the (possibly new) power settings.
302          */
303         untimeout(power_off_slot, (caddr_t)slt, slt->poff_ch);
304         power_off_slot(slt);
305         slt->ctrl->power(slt);
306
307         printf("pccard: card inserted, slot %d\n", slt->slotnum);
308         pccard_insert_beep();
309         /*
310          *      Now start resetting the card.
311          */
312         slt->ctrl->reset(slt);
313 }
314
315 /*
316  *      Card event callback. Called at splhigh to prevent
317  *      device interrupts from interceding.
318  */
319 void
320 pccard_event(struct slot *slt, enum card_event event)
321 {
322         if (slt->insert_seq) {
323                 slt->insert_seq = 0;
324                 untimeout(inserted, (void *)slt, slt->insert_ch);
325         }
326
327         switch(event) {
328         case card_removed:
329         case card_deactivated:
330                 if (slt->state == filled || slt->state == inactive) {
331                         if (event == card_removed)
332                                 slt->state = empty;
333                         else
334                                 slt->state = inactive;
335                         disable_slot_to(slt);
336                 }
337                 break;
338         case card_inserted:
339                 slt->insert_seq = 1;
340                 slt->insert_ch = timeout(inserted, (void *)slt, hz/4);
341                 break;
342         }
343 }
344
345 /*
346  *      Device driver interface.
347  */
348 static  int
349 crdopen(dev_t dev, int oflags, int devtype, d_thread_t *td)
350 {
351         struct slot *slt = PCCARD_DEV2SOFTC(dev);
352
353         if (slt == NULL)
354                 return (ENXIO);
355         if (slt->rwmem == 0)
356                 slt->rwmem = MDF_ATTR;
357         return (0);
358 }
359
360 /*
361  *      Close doesn't de-allocate any resources, since
362  *      slots may be assigned to drivers already.
363  */
364 static  int
365 crdclose(dev_t dev, int fflag, int devtype, d_thread_t *td)
366 {
367         return (0);
368 }
369
370 /*
371  *      read interface. Map memory at lseek offset,
372  *      then transfer to user space.
373  */
374 static  int
375 crdread(dev_t dev, struct uio *uio, int ioflag)
376 {
377         struct slot *slt = PCCARD_DEV2SOFTC(dev);
378         struct mem_desc *mp, oldmap;
379         unsigned char *p;
380         unsigned int offs;
381         int error = 0, win, count;
382
383         if (slt == 0 || slt->state != filled)
384                 return (ENXIO);
385         if (pccard_mem == 0)
386                 return (ENOMEM);
387         for (win = 0; win < slt->ctrl->maxmem; win++)
388                 if ((slt->mem[win].flags & MDF_ACTIVE) == 0)
389                         break;
390         if (win >= slt->ctrl->maxmem)
391                 return (EBUSY);
392         mp = &slt->mem[win];
393         oldmap = *mp;
394         mp->flags = slt->rwmem | MDF_ACTIVE;
395         while (uio->uio_resid && error == 0) {
396                 mp->card = uio->uio_offset;
397                 mp->size = PCCARD_MEMSIZE;
398                 mp->start = (caddr_t)(void *)(uintptr_t)pccard_mem;
399                 if ((error = slt->ctrl->mapmem(slt, win)) != 0)
400                         break;
401                 offs = (unsigned int)uio->uio_offset & (PCCARD_MEMSIZE - 1);
402                 p = pccard_kmem + offs;
403                 count = MIN(PCCARD_MEMSIZE - offs, uio->uio_resid);
404                 error = uiomove(p, count, uio);
405         }
406         /*
407          *      Restore original map.
408          */
409         *mp = oldmap;
410         slt->ctrl->mapmem(slt, win);
411
412         return (error);
413 }
414
415 /*
416  *      crdwrite - Write data to card memory.
417  *      Handles wrap around so that only one memory
418  *      window is used.
419  */
420 static  int
421 crdwrite(dev_t dev, struct uio *uio, int ioflag)
422 {
423         struct slot *slt = PCCARD_DEV2SOFTC(dev);
424         struct mem_desc *mp, oldmap;
425         unsigned char *p;
426         unsigned int offs;
427         int error = 0, win, count;
428
429         if (slt == 0 || slt->state != filled)
430                 return (ENXIO);
431         if (pccard_mem == 0)
432                 return (ENOMEM);
433         for (win = 0; win < slt->ctrl->maxmem; win++)
434                 if ((slt->mem[win].flags & MDF_ACTIVE) == 0)
435                         break;
436         if (win >= slt->ctrl->maxmem)
437                 return (EBUSY);
438         mp = &slt->mem[win];
439         oldmap = *mp;
440         mp->flags = slt->rwmem | MDF_ACTIVE;
441         while (uio->uio_resid && error == 0) {
442                 mp->card = uio->uio_offset;
443                 mp->size = PCCARD_MEMSIZE;
444                 mp->start = (caddr_t)(void *)(uintptr_t)pccard_mem;
445                 if ((error = slt->ctrl->mapmem(slt, win)) != 0)
446                         break;
447                 offs = (unsigned int)uio->uio_offset & (PCCARD_MEMSIZE - 1);
448                 p = pccard_kmem + offs;
449                 count = MIN(PCCARD_MEMSIZE - offs, uio->uio_resid);
450                 error = uiomove(p, count, uio);
451         }
452         /*
453          *      Restore original map.
454          */
455         *mp = oldmap;
456         slt->ctrl->mapmem(slt, win);
457
458         return (error);
459 }
460
461 /*
462  *      ioctl calls - allows setting/getting of memory and I/O
463  *      descriptors, and assignment of drivers.
464  */
465 static  int
466 crdioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, d_thread_t *td)
467 {
468         u_int32_t       addr;
469         int             err;
470         struct io_desc  *ip;
471         struct mem_desc *mp;
472         device_t        pccarddev;
473         int             pwval;
474         int             s;
475         struct slot     *slt = PCCARD_DEV2SOFTC(dev);
476
477         if (slt == 0 && cmd != PIOCRWMEM)
478                 return (ENXIO);
479         switch(cmd) {
480         default:
481                 if (slt->ctrl->ioctl)
482                         return (slt->ctrl->ioctl(slt, cmd, data));
483                 return (ENOTTY);
484         /*
485          * Get slot state.
486          */
487         case PIOCGSTATE:
488                 s = splhigh();
489                 ((struct slotstate *)data)->state = slt->state;
490                 ((struct slotstate *)data)->laststate = slt->laststate;
491                 slt->laststate = slt->state;
492                 splx(s);
493                 ((struct slotstate *)data)->maxmem = slt->ctrl->maxmem;
494                 ((struct slotstate *)data)->maxio = slt->ctrl->maxio;
495                 ((struct slotstate *)data)->irqs = 0;
496                 break;
497         /*
498          * Get memory context.
499          */
500         case PIOCGMEM:
501                 s = ((struct mem_desc *)data)->window;
502                 if (s < 0 || s >= slt->ctrl->maxmem)
503                         return (EINVAL);
504                 mp = &slt->mem[s];
505                 ((struct mem_desc *)data)->flags = mp->flags;
506                 ((struct mem_desc *)data)->start = mp->start;
507                 ((struct mem_desc *)data)->size = mp->size;
508                 ((struct mem_desc *)data)->card = mp->card;
509                 break;
510         /*
511          * Set memory context. If context already active, then unmap it.
512          * It is hard to see how the parameters can be checked.
513          * At the very least, we only allow root to set the context.
514          */
515         case PIOCSMEM:
516                 if (suser(td))
517                         return (EPERM);
518                 if (slt->state != filled)
519                         return (ENXIO);
520                 s = ((struct mem_desc *)data)->window;
521                 if (s < 0 || s >= slt->ctrl->maxmem)
522                         return (EINVAL);
523                 slt->mem[s] = *((struct mem_desc *)data);
524                 return (slt->ctrl->mapmem(slt, s));
525         /*
526          * Get I/O port context.
527          */
528         case PIOCGIO:
529                 s = ((struct io_desc *)data)->window;
530                 if (s < 0 || s >= slt->ctrl->maxio)
531                         return (EINVAL);
532                 ip = &slt->io[s];
533                 ((struct io_desc *)data)->flags = ip->flags;
534                 ((struct io_desc *)data)->start = ip->start;
535                 ((struct io_desc *)data)->size = ip->size;
536                 break;
537         /*
538          * Set I/O port context.
539          */
540         case PIOCSIO:
541                 if (suser(td))
542                         return (EPERM);
543                 if (slt->state != filled)
544                         return (ENXIO);
545                 s = ((struct io_desc *)data)->window;
546                 if (s < 0 || s >= slt->ctrl->maxio)
547                         return (EINVAL);
548                 slt->io[s] = *((struct io_desc *)data);
549                 /* XXX Don't actually map */
550                 return (0);
551                 break;
552         /*
553          * Set memory window flags for read/write interface.
554          */
555         case PIOCRWFLAG:
556                 slt->rwmem = *(int *)data;
557                 break;
558         /*
559          * Set the memory window to be used for the read/write interface.
560          * Not available on the alpha.
561          */
562         case PIOCRWMEM:
563                 if (*(unsigned long *)data == 0) {
564                         *(unsigned long *)data = pccard_mem;
565                         break;
566                 }
567                 if (suser(td))
568                         return (EPERM);
569                 /*
570                  * Validate the memory by checking it against the I/O
571                  * memory range. It must also start on an aligned block size.
572                  */
573                 if (*(unsigned long *)data & (PCCARD_MEMSIZE-1))
574                         return (EINVAL);
575                 pccarddev = PCCARD_DEV2SOFTC(dev)->dev;
576                 pccard_mem_rid = 0;
577                 addr = *(unsigned long *)data;
578                 if (pccard_mem_res)
579                         bus_release_resource(pccarddev, SYS_RES_MEMORY,
580                             pccard_mem_rid, pccard_mem_res);
581                 pccard_mem_res = bus_alloc_resource(pccarddev, SYS_RES_MEMORY,
582                     &pccard_mem_rid, addr, addr, PCCARD_MEMSIZE,
583                     RF_ACTIVE | rman_make_alignment_flags(PCCARD_MEMSIZE));
584                 if (pccard_mem_res == NULL)
585                         return (EINVAL);
586                 pccard_mem = rman_get_start(pccard_mem_res);
587                 pccard_kmem = rman_get_virtual(pccard_mem_res);
588                 break;
589         /*
590          * Set power values.
591          */
592         case PIOCSPOW:
593                 slt->pwr = *(struct power *)data;
594                 return (slt->ctrl->power(slt));
595         /*
596          * Allocate a driver to this slot.
597          */
598         case PIOCSDRV:
599                 if (suser(td))
600                         return (EPERM);
601                 err = allocate_driver(slt, (struct dev_desc *)data);
602                 if (!err)
603                         pccard_success_beep();
604                 else
605                         pccard_failure_beep();
606                 return (err);
607         /*
608          * Virtual removal/insertion
609          */
610         case PIOCSVIR:
611                 pwval = *(int *)data;
612                 if (!pwval) {
613                         if (slt->state != filled)
614                                 return (EINVAL);
615                         pccard_event(slt, card_deactivated);
616                 } else {
617                         if (slt->state != empty && slt->state != inactive)
618                                 return (EINVAL);
619                         pccard_event(slt, card_inserted);
620                 }
621                 break;
622         case PIOCSBEEP:
623                 if (pccard_beep_select(*(int *)data)) {
624                         return (EINVAL);
625                 }
626                 break;
627         }
628         return (0);
629 }
630
631 /*
632  *      poll - Poll on exceptions will return true
633  *      when a change in card status occurs.
634  */
635 static  int
636 crdpoll(dev_t dev, int events, d_thread_t *td)
637 {
638         int     revents = 0;
639         int     s;
640         struct slot *slt = PCCARD_DEV2SOFTC(dev);
641
642         if (events & (POLLIN | POLLRDNORM))
643                 revents |= events & (POLLIN | POLLRDNORM);
644
645         if (events & (POLLOUT | POLLWRNORM))
646                 revents |= events & (POLLIN | POLLRDNORM);
647
648         s = splhigh();
649         /*
650          *      select for exception - card event.
651          */
652         if (events & POLLRDBAND)
653                 if (slt == 0 || slt->laststate != slt->state)
654                         revents |= POLLRDBAND;
655
656         if (revents == 0)
657                 selrecord(td, &slt->selp);
658
659         splx(s);
660         return (revents);
661 }
662
663 /*
664  *      APM hooks for suspending and resuming.
665  */
666 int
667 pccard_suspend(device_t dev)
668 {
669         struct slot *slt = PCCARD_DEVICE2SOFTC(dev);
670
671         /* This code stolen from pccard_event:card_removed */
672         if (slt->state == filled) {
673                 int s = splhigh();              /* nop on current */
674                 disable_slot(slt);
675                 slt->laststate = suspend;       /* for pccardd */
676                 slt->state = empty;
677                 splx(s);
678                 printf("pccard: card disabled, slot %d\n", slt->slotnum);
679         }
680         /*
681          * Disable any pending timeouts for this slot since we're
682          * powering it down/disabling now.
683          */
684         untimeout(power_off_slot, (caddr_t)slt, slt->poff_ch);
685         slt->ctrl->disable(slt);
686         return (0);
687 }
688
689 int
690 pccard_resume(device_t dev)
691 {
692         struct slot *slt = PCCARD_DEVICE2SOFTC(dev);
693
694         slt->ctrl->resume(slt);
695         return (0);
696 }