Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / bus / pccard / mecia.c
1 /*
2  *  NEC MECIA controller.
3  *-------------------------------------------------------------------------
4  *
5  * Copyright (c) 2001 M. Warner Losh.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * $FreeBSD: src/sys/pccard/mecia.c,v 1.2.2.4 2001/08/14 23:36:18 imp Exp $
28  *
29  * Based heavily on the FreeBSD pcic driver's pcic98 support, derived
30  * from PAO3 tree.  This copyright notice likely needs modification for
31  * such a linage.  The only authorship I could find was:
32  *
33  * PC9801 original PCMCIA controller code for NS/A,Ne,NX/C,NR/L.
34  * by Noriyuki Hosobuchi <hoso@ce.mbn.or.jp>
35  */
36
37 #include <sys/param.h>
38 #include <sys/bus.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/module.h>
42
43 #include <pccard/meciareg.h>
44 #include <pccard/cardinfo.h>
45 #include <pccard/slot.h>
46 #ifndef MECIA_IOBASE
47 #define MECIA_IOBASE   0x80d0
48 #endif
49
50 /* Get pnp IDs */
51 #include <isa/isavar.h>
52
53 #include <dev/pccard/pccardvar.h>
54 #include "card_if.h"
55
56 #define MECIA_DEVICE2SOFTC(dev) ((struct mecia_slot *) device_get_softc(dev))
57
58 /*
59  *      Prototypes for interrupt handler.
60  */
61 static driver_intr_t    meciaintr;
62 static int              mecia_ioctl(struct slot *, int, caddr_t);
63 static int              mecia_power(struct slot *);
64 static void             mecia_mapirq(struct slot *, int);
65 static timeout_t        mecia_reset;
66 static void             mecia_resume(struct slot *);
67 static void             mecia_disable(struct slot *);
68 static timeout_t        meciatimeout;
69 static struct callout_handle meciatimeout_ch
70     = CALLOUT_HANDLE_INITIALIZER(&meciatimeout_ch);
71 static int              mecia_memory(struct slot *, int);
72 static int              mecia_io(struct slot *, int);
73
74 /*
75  *      Per-slot data table.
76  */
77 struct mecia_slot {
78         int             unit;           /* Unit number */
79         int             slotnum;        /* My slot number */
80         struct slot     *slt;           /* Back ptr to slot */
81         device_t        dev;            /* My device */
82         u_char          last_reg1;      /* Last value of change reg */
83 };
84
85 static struct slot_ctrl mecia_cinfo = {
86         mecia_mapirq,
87         mecia_memory,
88         mecia_io,
89         mecia_reset,
90         mecia_disable,
91         mecia_power,
92         mecia_ioctl,
93         mecia_resume,
94         1,
95 #if 0
96         1
97 #else
98         2               /* Fake for UE2212 LAN card */
99 #endif
100 };
101
102 static int validunits = 0;
103
104 /*
105  *      Look for an NEC MECIA.
106  *      For each available slot, allocate a PC-CARD slot.
107  */
108
109 static int
110 mecia_probe(device_t dev)
111 {
112         int             validslots = 0;
113
114         /* Check isapnp ids */
115         if (isa_get_logicalid(dev))             /* skip PnP probes */
116                 return (ENXIO);
117
118         if (inb(MECIA_REG0) != 0xff) {
119                 validslots++;
120                 /* XXX need to allocated the port resources */
121                 device_set_desc(dev, "MECIA PC98 Original PCMCIA Controller");
122         }
123         return (validslots ? 0 : ENXIO);
124 }
125
126 static int
127 mecia_attach(device_t dev)
128 {
129         int             error;
130         int             irq;
131         void            *ih;
132         device_t        kid;
133         struct resource *r;
134         int             rid;
135         struct slot     *slt;
136         struct mecia_slot *sp;
137         
138         sp = MECIA_DEVICE2SOFTC(dev);
139         sp->unit = validunits++;
140         kid = device_add_child(dev, NULL, -1);
141         if (kid == NULL) {
142                 device_printf(dev, "Can't add pccard bus slot 0\n");
143                 return (ENXIO);
144         }
145         device_probe_and_attach(kid);
146         slt = pccard_init_slot(kid, &mecia_cinfo);
147         if (slt == 0) {
148                 device_printf(dev, "Can't get pccard info slot 0\n");
149                 return (ENXIO);
150         }
151         slt->cdata = sp;
152         sp->slt = slt;
153         validunits++;
154
155         rid = 0;
156         r = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE);
157         if (!r)
158                 return (ENXIO);
159
160         irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0);
161         if (irq == 0) {
162                 /* See if the user has requested a specific IRQ */
163                 if (!getenv_int("machdep.pccard.mecia_irq", &irq))
164                         irq = 0;
165         }
166         rid = 0;
167         r = 0;
168         if (irq > 0) {
169                 r = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq,
170                     irq, 1, RF_ACTIVE);
171         }
172         if (r && ((1 << (rman_get_start(r))) & MECIA_INT_MASK_ALLOWED) == 0) {
173                 device_printf(dev,
174                     "Hardware does not support irq %d, trying polling.\n",
175                     irq);
176                 bus_release_resource(dev, SYS_RES_IRQ, rid, r);
177                 r = 0;
178                 irq = 0;
179         }
180         if (r) {
181                 error = bus_setup_intr(dev, r, INTR_TYPE_MISC,
182                     meciaintr, (void *) sp, &ih);
183                 if (error) {
184                         bus_release_resource(dev, SYS_RES_IRQ, rid, r);
185                         return (error);
186                 }
187                 irq = rman_get_start(r);
188                 device_printf(dev, "management irq %d\n", irq);
189         } else {
190                 irq = 0;
191         }
192         if (irq == 0) {
193                 meciatimeout_ch = timeout(meciatimeout, (void *) sp, hz/2);
194                 device_printf(dev, "Polling mode\n");
195         }
196
197         sp->last_reg1 = inb(MECIA_REG1);
198         if (sp->last_reg1 & MECIA_CARDEXIST) {
199                 /* PCMCIA card exist */
200                 sp->slt->laststate = sp->slt->state = filled;
201                 pccard_event(sp->slt, card_inserted);
202         } else {
203                 sp->slt->laststate = sp->slt->state = empty;
204         }
205         sp->slt->irq = irq;
206
207         return (bus_generic_attach(dev));
208 }
209
210 static int
211 mecia_sresource(struct slot *slt, caddr_t data)
212 {
213         struct pccard_resource *pr;
214         struct resource *r;
215         int flags;
216         int rid = 0;
217         device_t pccarddev = slt->dev;
218
219         pr = (struct pccard_resource *)data;
220         pr->resource_addr = ~0ul;
221         switch(pr->type) {
222         default:
223                 return (EINVAL);
224         case SYS_RES_MEMORY:
225         case SYS_RES_IRQ:
226         case SYS_RES_IOPORT:
227                 break;
228         }
229         flags = rman_make_alignment_flags(pr->size);
230         r = bus_alloc_resource(pccarddev, pr->type, &rid, pr->min, pr->max,
231            pr->size, flags);
232         if (r != NULL) {
233                 pr->resource_addr = (u_long)rman_get_start(r);
234                 bus_release_resource(bridgedev, pr->type, rid, r);
235         }
236         return (0);
237 }
238
239 /*
240  *      ioctl calls - Controller specific ioctls
241  */
242 static int
243 mecia_ioctl(struct slot *slt, int cmd, caddr_t data)
244 {
245         switch(cmd) {
246         default:
247                 return (ENOTTY);
248         case PIOCSRESOURCE:             /* Can I use this resource? */
249                 mecia_sresource(slt, data);
250                 break;
251         }
252         return (0);
253 }
254
255 /*
256  *      MECIA timer.  If the controller doesn't have a free IRQ to use
257  *      or if interrupt steering doesn't work, poll the controller for
258  *      insertion/removal events.
259  */
260 static void
261 meciatimeout(void *chan)
262 {
263         meciaintr(chan);
264         meciatimeout_ch = timeout(meciatimeout, chan, hz/2);
265 }
266
267 /*
268  *      MECIA Interrupt handler.
269  *      Check the slot and report any changes.
270  */
271 static void
272 meciaintr(void *arg)
273 {
274         u_char  reg1;
275         int     s;
276         struct mecia_slot *sp = (struct mecia_slot *) arg;
277
278         s = splhigh();
279         /* Check for a card in this slot */
280         reg1 = inb(MECIA_REG1);
281         if ((sp->last_reg1 ^ reg1) & MECIA_CARDEXIST) {
282                 sp->last_reg1 = reg1;
283                 if (reg1 & MECIA_CARDEXIST)
284                         pccard_event(sp->slt, card_inserted);
285                 else
286                         pccard_event(sp->slt, card_removed);
287         }
288         splx(s);
289 }
290
291 /*
292  * local functions for PC-98 Original PC-Card controller
293  */
294 #define MECIA_ALWAYS_128MAPPING 1       /* trick for using UE2212  */
295
296 int mecia_mode = 0;     /* almost the same as the value in MECIA_REG2 */
297
298 static unsigned char reg_winsel = MECIA_UNMAPWIN;
299 static unsigned short reg_pagofs = 0;
300
301 static int
302 mecia_memory(struct slot *slt, int win)
303 {
304         struct mem_desc *mp = &slt->mem[win];
305         unsigned char x;
306
307         if (mp->flags & MDF_ACTIVE) {
308                 /* slot = 0, window = 0, sys_addr = 0xda000, length = 8KB */
309                 if ((unsigned long)mp->start != 0xda000) {
310                         printf(
311                         "sys_addr must be 0xda000. requested address = %p\n",
312                         mp->start);
313                         return (EINVAL);
314                 }
315
316                 /* omajinai ??? */
317                 outb(MECIA_REG0, 0);
318                 x = inb(MECIA_REG1);
319                 x &= 0xfc;
320                 x |= 0x02;
321                 outb(MECIA_REG1, x);
322                 reg_winsel = inb(MECIA_REG_WINSEL);
323                 reg_pagofs = inw(MECIA_REG_PAGOFS);
324                 outb(MECIA_REG_WINSEL, MECIA_MAPWIN);
325                 outw(MECIA_REG_PAGOFS, (mp->card >> 13)); /* 8KB */
326
327                 if (mp->flags & MDF_ATTR)
328                         outb(MECIA_REG7, inb(MECIA_REG7) | MECIA_ATTRMEM);
329                 else
330                         outb(MECIA_REG7, inb(MECIA_REG7) & (~MECIA_ATTRMEM));
331
332                 outb(MECIA_REG_WINSEL, MECIA_MAPWIN);
333 #if 0
334                 if ((mp->flags & MDF_16BITS) == 1)      /* 16bit */
335                         outb(MECIA_REG2, inb(MECIA_REG2) & (~MECIA_8BIT));
336                 else                                    /* 8bit */
337                         outb(MECIA_REG2, inb(MECIA_REG2) | MECIA_8BIT);
338 #endif
339         } else {  /* !(mp->flags & MDF_ACTIVE) */
340                 outb(MECIA_REG0, 0);
341                 x = inb(MECIA_REG1);
342                 x &= 0xfc;
343                 x |= 0x02;
344                 outb(MECIA_REG1, x);
345 #if 0
346                 outb(MECIA_REG_WINSEL, MECIA_UNMAPWIN);
347                 outw(MECIA_REG_PAGOFS, 0);
348 #else
349                 outb(MECIA_REG_WINSEL, reg_winsel);
350                 outw(MECIA_REG_PAGOFS, reg_pagofs);
351 #endif
352         }
353         return (0);
354 }
355
356 static int
357 mecia_io(struct slot *slt, int win)
358 {
359         struct io_desc *ip = &slt->io[win];
360         unsigned char x;
361         unsigned short cardbase;
362         u_short ofst;
363
364         if (win != 0) {
365                 /* ignore for UE2212 */
366                 printf(
367                 "mecia:Illegal MECIA I/O window(%d) request! Ignored.\n", win);
368 /*              return (EINVAL);*/
369                 return (0);
370         }
371
372         if (ip->flags & IODF_ACTIVE) {
373                 x = inb(MECIA_REG2) & 0x0f;
374 #if 0
375                 if (! (ip->flags & IODF_CS16))
376                         x |= MECIA_8BIT;
377 #else
378                 if (! (ip->flags & IODF_16BIT)) {
379                         x |= MECIA_8BIT;
380                         mecia_mode |= MECIA_8BIT;
381                 }
382 #endif
383
384                 ofst = ip->start & 0xf;
385                 cardbase = ip->start & ~0xf;
386 #ifndef MECIA_ALWAYS_128MAPPING
387                 if (ip->size + ofst > 16)
388 #endif
389                 {       /* 128bytes mapping */
390                         x |= MECIA_MAP128;
391                         mecia_mode |= MECIA_MAP128;
392                         ofst |= ((cardbase & 0x70) << 4);
393                         cardbase &= ~0x70;
394                 }
395
396                 x |= MECIA_MAPIO;
397                 outb(MECIA_REG2, x);
398     
399                 outw(MECIA_REG4, MECIA_IOBASE); /* 98side I/O base */
400                 outw(MECIA_REG5, cardbase);     /* card side I/O base */
401
402                 if (bootverbose) {
403                         printf("mecia: I/O mapped 0x%04x(98) -> "
404                                "0x%04x(Card) and width %d bytes\n",
405                                 MECIA_IOBASE+ofst, ip->start, ip->size);
406                         printf("mecia: reg2=0x%02x reg3=0x%02x reg7=0x%02x\n",
407                                 inb(MECIA_REG2), inb(MECIA_REG3),
408                                 inb(MECIA_REG7));
409                         printf("mecia: mode=%d\n", mecia_mode);
410                 }
411
412                 ip->start = MECIA_IOBASE + ofst;
413         } else {
414                 outb(MECIA_REG2, inb(MECIA_REG2) & (~MECIA_MAPIO));
415                 mecia_mode = 0;
416         }
417         return (0);
418 }
419
420 static int
421 mecia_power(struct slot *slt)
422 {
423         unsigned char reg;
424
425         reg = inb(MECIA_REG7) & (~MECIA_VPP12V);
426         switch(slt->pwr.vpp) {
427         default:
428                 return (EINVAL);
429         case 50:
430                 break;
431         case 120:
432                 reg |= MECIA_VPP12V;
433                 break;
434         }
435         outb(MECIA_REG7, reg);
436         DELAY(100*1000);
437
438         reg = inb(MECIA_REG2) & (~MECIA_VCC3P3V);
439         switch(slt->pwr.vcc) {
440         default:
441                 return (EINVAL);
442         case 33:
443                 reg |= MECIA_VCC3P3V;
444                 break;
445         case 50:
446                 break;
447         }
448         outb(MECIA_REG2, reg);
449         DELAY(100*1000);
450         return (0);
451 }
452
453 static void
454 mecia_mapirq(struct slot *slt, int irq)
455 {
456         u_char x;
457
458         switch (irq) {
459         case 3:
460                 x = MECIA_INT0;
461                 break;
462         case 5:
463                 x = MECIA_INT1;
464                 break;
465         case 6:
466                 x = MECIA_INT2;
467                 break;
468         case 10:
469                 x = MECIA_INT4;
470                 break;
471         case 12:
472                 x = MECIA_INT5;
473                 break;
474         case 0:         /* disable */
475                 x = MECIA_INTDISABLE;
476                 break;
477         default:
478                 printf("mecia: illegal irq %d\n", irq);
479                 return;
480         }
481 #ifdef  MECIA_DEBUG
482         printf("mecia: irq=%d mapped.\n", irq);
483 #endif
484         outb(MECIA_REG3, x);
485 }
486
487 static void
488 mecia_reset(void *chan)
489 {
490         struct slot *slt = chan;
491
492         outb(MECIA_REG0, 0);
493         outb(MECIA_REG2, inb(MECIA_REG2) & (~MECIA_MAPIO));
494         outb(MECIA_REG3, MECIA_INTDISABLE);
495 #if 0
496 /* mecia_reset() is called after mecia_power() */
497         outb(MECIA_REG2, inb(MECIA_REG2) & (~MECIA_VCC3P3V));
498         outb(MECIA_REG7, inb(MECIA_REG7) & (~MECIA_VPP12V));
499 #endif
500         outb(MECIA_REG1, 0);
501
502         selwakeup(&slt->selp);
503 }
504
505 static void
506 mecia_disable(struct slot *slt)
507 {
508         /* null function */
509 }
510
511 static void
512 mecia_resume(struct slot *slt)
513 {
514         /* XXX MECIA How ? */
515 }
516
517 static int
518 mecia_activate_resource(device_t dev, device_t child, int type, int rid,
519     struct resource *r)
520 {
521         struct pccard_devinfo *devi = device_get_ivars(child);
522         int err;
523
524         if (dev != device_get_parent(device_get_parent(child)) || devi == NULL)
525                 return (bus_generic_activate_resource(dev, child, type,
526                     rid, r));
527
528         switch (type) {
529         case SYS_RES_IOPORT: {
530                 struct io_desc *ip;
531                 ip = &devi->slt->io[rid];
532                 if (ip->flags == 0) {
533                         if (rid == 0)
534                                 ip->flags = IODF_WS | IODF_16BIT | IODF_CS16;
535                         else
536                                 ip->flags = devi->slt->io[0].flags;
537                 }
538                 ip->flags |= IODF_ACTIVE;
539                 ip->start = rman_get_start(r);
540                 ip->size = rman_get_end(r) - rman_get_start(r) + 1;
541                 err = mecia_cinfo.mapio(devi->slt, rid);
542                 if (err)
543                         return (err);
544                 break;
545         }
546         case SYS_RES_IRQ:
547                 /*
548                  * We actually defer the activation of the IRQ resource
549                  * until the interrupt is registered to avoid stray
550                  * interrupt messages.
551                  */
552                 break;
553         case SYS_RES_MEMORY: {
554                 struct mem_desc *mp;
555                 if (rid >= NUM_MEM_WINDOWS)
556                         return (EINVAL);
557                 mp = &devi->slt->mem[rid];
558                 mp->flags |= MDF_ACTIVE;
559                 mp->start = (caddr_t) rman_get_start(r);
560                 mp->size = rman_get_end(r) - rman_get_start(r) + 1;
561                 err = mecia_cinfo.mapmem(devi->slt, rid);
562                 if (err)
563                         return (err);
564                 break;
565         }
566         default:
567                 break;
568         }
569         err = bus_generic_activate_resource(dev, child, type, rid, r);
570         return (err);
571 }
572
573 static int
574 mecia_deactivate_resource(device_t dev, device_t child, int type, int rid,
575     struct resource *r)
576 {
577         struct pccard_devinfo *devi = device_get_ivars(child);
578         int err;
579
580         if (dev != device_get_parent(device_get_parent(child)) || devi == NULL)
581                 return (bus_generic_deactivate_resource(dev, child, type,
582                     rid, r));
583
584         switch (type) {
585         case SYS_RES_IOPORT: {
586                 struct io_desc *ip = &devi->slt->io[rid];
587                 ip->flags &= ~IODF_ACTIVE;
588                 err = mecia_cinfo.mapio(devi->slt, rid);
589                 if (err)
590                         return (err);
591                 break;
592         }
593         case SYS_RES_IRQ:
594                 break;
595         case SYS_RES_MEMORY: {
596                 struct mem_desc *mp = &devi->slt->mem[rid];
597                 mp->flags &= ~(MDF_ACTIVE | MDF_ATTR);
598                 err = mecia_cinfo.mapmem(devi->slt, rid);
599                 if (err)
600                         return (err);
601                 break;
602         }
603         default:
604                 break;
605         }
606         err = bus_generic_deactivate_resource(dev, child, type, rid, r);
607         return (err);
608 }
609
610 static int
611 mecia_setup_intr(device_t dev, device_t child, struct resource *irq,
612     int flags, driver_intr_t *intr, void *arg, void **cookiep)
613 {
614         struct pccard_devinfo *devi = device_get_ivars(child);
615         int err;
616
617         if (((1 << rman_get_start(irq)) & MECIA_INT_MASK_ALLOWED) == 0) {
618                 device_printf(dev, "Hardware does not support irq %ld.\n",
619                     rman_get_start(irq));
620                 return (EINVAL);
621         }
622
623         err = bus_generic_setup_intr(dev, child, irq, flags, intr, arg,
624             cookiep);
625         if (err == 0)
626                 mecia_cinfo.mapirq(devi->slt, rman_get_start(irq));
627         else
628                 device_printf(dev, "Error %d irq %ld\n", err,
629                     rman_get_start(irq));
630         return (err);
631 }
632
633 static int
634 mecia_teardown_intr(device_t dev, device_t child, struct resource *irq,
635     void *cookie)
636 {
637         struct pccard_devinfo *devi = device_get_ivars(child);
638
639         mecia_cinfo.mapirq(devi->slt, 0);
640         return (bus_generic_teardown_intr(dev, child, irq, cookie));
641 }
642
643 static int
644 mecia_set_res_flags(device_t bus, device_t child, int restype, int rid,
645     u_long value)
646 {
647         struct pccard_devinfo *devi = device_get_ivars(child);
648         int err = 0;
649
650         switch (restype) {
651         case SYS_RES_MEMORY: {
652                 struct mem_desc *mp = &devi->slt->mem[rid];
653                 switch (value) {
654                 case PCCARD_A_MEM_COM:
655                         mp->flags &= ~MDF_ATTR;
656                         break;
657                 case PCCARD_A_MEM_ATTR:
658                         mp->flags |= MDF_ATTR;
659                         break;
660                 case PCCARD_A_MEM_8BIT:
661                         mp->flags &= ~MDF_16BITS;
662                         break;
663                 case PCCARD_A_MEM_16BIT:
664                         mp->flags |= MDF_16BITS;
665                         break;
666                 }
667                 err = mecia_cinfo.mapmem(devi->slt, rid);
668                 break;
669         }
670         default:
671                 err = EOPNOTSUPP;
672         }
673         return (err);
674 }
675
676 static int
677 mecia_get_res_flags(device_t bus, device_t child, int restype, int rid,
678     u_long *value)
679 {
680         struct pccard_devinfo *devi = device_get_ivars(child);
681         int err = 0;
682
683         if (value == 0)
684                 return (ENOMEM);
685
686         switch (restype) {
687         case SYS_RES_IOPORT: {
688                 struct io_desc *ip = &devi->slt->io[rid];
689                 *value = ip->flags;
690                 break;
691         }
692         case SYS_RES_MEMORY: {
693                 struct mem_desc *mp = &devi->slt->mem[rid];
694                 *value = mp->flags;
695                 break;
696         }
697         default:
698                 err = EOPNOTSUPP;
699         }
700         return (err);
701 }
702
703 static int
704 mecia_set_memory_offset(device_t bus, device_t child, int rid,
705     u_int32_t offset, u_int32_t *deltap)
706 {
707         struct pccard_devinfo *devi = device_get_ivars(child);
708         struct mem_desc *mp = &devi->slt->mem[rid];
709
710         mp->card = offset;
711         if (deltap)
712                 *deltap = 0;                    /* XXX BAD XXX */
713         return (mecia_cinfo.mapmem(devi->slt, rid));
714 }
715
716 static int
717 mecia_get_memory_offset(device_t bus, device_t child, int rid,
718     u_int32_t *offset)
719 {
720         struct pccard_devinfo *devi = device_get_ivars(child);
721         struct mem_desc *mp = &devi->slt->mem[rid];
722
723         if (offset == 0)
724                 return (ENOMEM);
725
726         *offset = mp->card;
727
728         return (0);
729 }
730
731 static device_method_t mecia_methods[] = {
732         /* Device interface */
733         DEVMETHOD(device_probe,         mecia_probe),
734         DEVMETHOD(device_attach,        mecia_attach),
735         DEVMETHOD(device_detach,        bus_generic_detach),
736         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
737         DEVMETHOD(device_suspend,       bus_generic_suspend),
738         DEVMETHOD(device_resume,        bus_generic_resume),
739
740         /* Bus interface */
741         DEVMETHOD(bus_print_child,      bus_generic_print_child),
742         DEVMETHOD(bus_alloc_resource,   bus_generic_alloc_resource),
743         DEVMETHOD(bus_release_resource, bus_generic_release_resource),
744         DEVMETHOD(bus_activate_resource, mecia_activate_resource),
745         DEVMETHOD(bus_deactivate_resource, mecia_deactivate_resource),
746         DEVMETHOD(bus_setup_intr,       mecia_setup_intr),
747         DEVMETHOD(bus_teardown_intr,    mecia_teardown_intr),
748
749         /* Card interface */
750         DEVMETHOD(card_set_res_flags,   mecia_set_res_flags),
751         DEVMETHOD(card_get_res_flags,   mecia_get_res_flags),
752         DEVMETHOD(card_set_memory_offset, mecia_set_memory_offset),
753         DEVMETHOD(card_get_memory_offset, mecia_get_memory_offset),
754
755         { 0, 0 }
756 };
757
758 devclass_t      mecia_devclass;
759
760 static driver_t mecia_driver = {
761         "mecia",
762         mecia_methods,
763         sizeof(struct mecia_slot)
764 };
765
766 DRIVER_MODULE(mecia, isa, mecia_driver, mecia_devclass, 0, 0);