Applied a modified version of holger's regparm patches.
[people/adir/gpxe.git] / src / core / i82365.c
1 #ifdef CONFIG_PCMCIA
2
3 /*
4  *      i82365.c
5  *      Support for i82365 and similar ISA-to-PCMCIA bridges
6  *
7  *      Taken from Linux kernel sources, distributed under GPL2
8  *
9  *   Software distributed under the License is distributed on an "AS
10  *   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  *   implied. See the License for the specific language governing
12  *   rights and limitations under the License.
13  *
14  *   The initial developer of the original code is David A. Hinds
15  *   <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
16  *   are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
17  *
18  *      Ported by: Anselm Martin Hoffmeister, Stockholm Projekt Computer-Service, Sankt Augustin/Bonn, GERMANY
19  */
20
21 /*
22  *
23  *
24  *                      ******************************
25  *                      PLEASE DO NOT YET WORK ON THIS
26  *                      ******************************
27  *
28  *      I'm still fixing it up on every end, so we most probably would interfere
29  *      at some point. If there's anything obvious or better, not-so-obvious,
30  *      please contact me by e-mail: anselm (AT) hoffmeister (DOT) be   *THANKS*
31  */
32 #include "../include/pcmcia.h"
33 #include "../include/pcmcia-opts.h"
34 #include "../include/i82365.h"
35
36 #ifndef CONFIG_ISA
37 #error  PCMCIA_I82365 only works with ISA defined - set CONFIG_ISA
38 #endif
39
40 typedef enum pcic_id {
41     IS_I82365A, IS_I82365B, IS_I82365DF,
42     IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469,
43     IS_PD6710, IS_PD672X, IS_VT83C469,
44 } pcic_id;
45
46 /* Flags for classifying groups of controllers */
47 #define IS_VADEM        0x0001
48 #define IS_CIRRUS       0x0002
49 #define IS_TI           0x0004
50 #define IS_O2MICRO      0x0008
51 #define IS_VIA          0x0010
52 #define IS_TOPIC        0x0020
53 #define IS_RICOH        0x0040
54 #define IS_UNKNOWN      0x0400
55 #define IS_VG_PWR       0x0800
56 #define IS_DF_PWR       0x1000
57 #define IS_PCI          0x2000
58 #define IS_ALIVE        0x8000
59
60 typedef struct pcic_t {
61     char                *name;
62     u_short             flags;
63 } pcic_t;
64
65 static pcic_t pcic[] = {
66     { "Intel i82365sl A step", 0 },
67     { "Intel i82365sl B step", 0 },
68     { "Intel i82365sl DF", IS_DF_PWR },
69     { "IBM Clone", 0 },
70     { "Ricoh RF5C296/396", 0 },
71     { "VLSI 82C146", 0 },
72     { "Vadem VG-468", IS_VADEM },
73     { "Vadem VG-469", IS_VADEM|IS_VG_PWR },
74     { "Cirrus PD6710", IS_CIRRUS },
75     { "Cirrus PD672x", IS_CIRRUS },
76     { "VIA VT83C469", IS_CIRRUS|IS_VIA },
77 };
78
79 typedef struct cirrus_state_t {
80     u_char              misc1, misc2;
81     u_char              timer[6];
82 } cirrus_state_t;
83
84 typedef struct vg46x_state_t {
85     u_char              ctl, ema;
86 } vg46x_state_t;
87
88 typedef struct socket_info_t {
89     u_short             type, flags;
90     socket_cap_t        cap;
91     ioaddr_t            ioaddr;
92     u_short             psock;
93     u_char              cs_irq, intr;
94     void                (*handler)(void *info, u_int events);
95     void                *info;
96     union {
97         cirrus_state_t          cirrus;
98         vg46x_state_t           vg46x;
99     } state;
100 } socket_info_t;
101
102 //static socket_info_t socket[8];
103
104 int     i365_base = 0x3e0; // Default in Linux kernel
105 int     cycle_time = 120; // External clock time in ns, 120ns =~ 8.33 MHz
106 int     mydriverid = 0;
107
108 void    phex ( unsigned char c );
109 /*static int to_cycles(int ns)
110 {
111     return ns/cycle_time;
112 }
113 */
114 /*static int to_ns(int cycles)
115 {
116     return cycle_time*cycles;
117 }
118 */
119
120 static u_char i365_get(u_short sock, u_short reg)
121 {
122     //unsigned long flags;
123     //spin_lock_irqsave(&bus_lock,flags);
124     {
125         ioaddr_t port = pccsock[sock].ioaddr;
126         u_char val;
127         reg = I365_REG(pccsock[sock].internalid, reg);
128         outb(reg, port); val = inb(port+1);
129         //spin_unlock_irqrestore(&bus_lock,flags);
130         return val;
131     }
132 }
133
134 static void i365_set(u_short sock, u_short reg, u_char data)
135 {
136     //unsigned long flags;
137     //spin_lock_irqsave(&bus_lock,flags);
138     {
139         ioaddr_t port = pccsock[sock].ioaddr;
140         u_char val = I365_REG(pccsock[sock].internalid, reg);
141         outb(val, port); outb(data, port+1);
142         //spin_unlock_irqrestore(&bus_lock,flags);
143     }
144 }
145
146 void    add_socket_i365(u_short port, int psock, int type) {
147         pccsock[pccsocks].ioaddr = port;
148         pccsock[pccsocks].internalid = psock;
149         pccsock[pccsocks].type = type;
150         pccsock[pccsocks].flags = pcic[type].flags;
151         pccsock[pccsocks].drivernum = mydriverid;
152         pccsock[pccsocks].configoffset = -1;
153         // Find out if a card in inside that socket
154         pccsock[pccsocks].status = (( 12 == (i365_get(pccsocks,I365_STATUS)&12) )  ?  HASCARD : EMPTY );
155         // *TODO* check if that's all
156         if ( 0 == (psock & 1) ) {
157                 printf ( "Found a PCMCIA controller (i82365) at io %x, type '%s'\n", port, pcic[type].name );
158                 //      pccsock[pccsocks].status == HASCARD? "holds card":"empty" );
159         }
160         pccsocks++;
161         return;
162 }
163
164 void    i365_bset(u_short sock, u_short reg, u_char mask) {
165         u_char d = i365_get(sock, reg);
166         d |= mask;
167         i365_set(sock, reg, d);
168 }
169
170 void    i365_bclr(u_short sock, u_short reg, u_char mask) {
171         u_char d = i365_get(sock, reg);
172         d &= ~mask;
173         i365_set(sock, reg, d);
174 }
175
176
177 /*static void i365_bflip(u_short sock, u_short reg, u_char mask, int b)
178 {
179     u_char d = i365_get(sock, reg);
180     if (b)
181         d |= mask;
182     else
183         d &= ~mask;
184     i365_set(sock, reg, d);
185 }
186 */
187
188 /*
189 static u_short i365_get_pair(u_short sock, u_short reg)
190 {
191     u_short a, b;
192     a = i365_get(sock, reg);
193     b = i365_get(sock, reg+1);
194     return (a + (b<<8));
195 }
196 */
197
198 /*
199 static void i365_set_pair(u_short sock, u_short reg, u_short data)
200 {
201     i365_set(sock, reg, data & 0xff);
202     i365_set(sock, reg+1, data >> 8);
203 }
204 */
205 int     identify_i365 ( u_short port, u_short sock ) {
206         u_char val;
207         int type = -1;
208         /* Use the next free entry in the socket table */
209         pccsock[pccsocks].ioaddr = port;
210         pccsock[pccsocks].internalid = sock;
211         // *TODO* wakeup a sleepy cirrus controller?
212
213         if ((val = i365_get(pccsocks, I365_IDENT)) & 0x70)
214             return -1;
215         switch (val) {
216         case 0x82:
217             type = IS_I82365A; break;
218         case 0x83:
219             type = IS_I82365B; break;
220         case 0x84:
221             type = IS_I82365DF; break;
222         case 0x88: case 0x89: case 0x8a:
223             type = IS_IBM; break;
224         }
225         /* Check for Vadem VG-468 chips */
226         outb(0x0e, port);
227         outb(0x37, port);
228         i365_bset(pccsocks, VG468_MISC, VG468_MISC_VADEMREV);
229         val = i365_get(pccsocks, I365_IDENT);
230         if (val & I365_IDENT_VADEM) {
231             i365_bclr(pccsocks, VG468_MISC, VG468_MISC_VADEMREV);
232             type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468;
233         }
234
235         /* Check for Ricoh chips */
236         val = i365_get(pccsocks, RF5C_CHIP_ID);
237         if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396)) type = IS_RF5Cx96;
238
239         /* Check for Cirrus CL-PD67xx chips */
240         i365_set(pccsocks, PD67_CHIP_INFO, 0);
241         val = i365_get(pccsocks, PD67_CHIP_INFO);
242         if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
243             val = i365_get(pccsocks, PD67_CHIP_INFO);
244             if ((val & PD67_INFO_CHIP_ID) == 0) {
245                 type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710;
246                 i365_set(pccsocks, PD67_EXT_INDEX, 0xe5);
247                 if (i365_get(pccsocks, PD67_EXT_INDEX) != 0xe5) type = IS_VT83C469;
248             }
249         }
250     return type;
251 }
252
253 int     init_i82365(void) {
254         int     i, j, sock, k, ns, id;
255         //unsigned int ui,uj;
256         //unsigned char * upc;
257         ioaddr_t port;
258         int     i82365s = 0;
259         // Change from kernel: No irq init, no check_region, no isapnp support
260         // No ignore socket, no extra sockets to check (so it's easier here :-/)
261         // Probably we don't need any of them; in case YOU do, SHOUT AT ME!
262         id = identify_i365(i365_base, 0);
263         if ((id == IS_I82365DF) && (identify_i365(i365_base, 1) != id)) {
264                 for (i = 0; i < 4; i++) {
265                     port = i365_base + ((i & 1) << 2) + ((i & 2) << 1);
266                     sock = (i & 1) << 1;
267                     if (identify_i365(port, sock) == IS_I82365DF) {
268                         add_socket_i365(port, sock, IS_VLSI);
269                     }
270                 }
271         } else {
272           for (i = 0; i < 4; i += 2) {
273             port = i365_base + 2*(i>>2);
274             sock = (i & 3);
275             id = identify_i365(port, sock);
276             if (id < 0) continue;
277
278             for (j = ns = 0; j < 2; j++) {
279                 /* Does the socket exist? */
280                 if (identify_i365(port, sock+j) < 0)    continue;
281                 /* Check for bad socket decode */
282                 for (k = 0; k <= i82365s; k++)
283                     i365_set(k, I365_MEM(0)+I365_W_OFF, k);
284                 for (k = 0; k <= i82365s; k++)
285                     if (i365_get(k, I365_MEM(0)+I365_W_OFF) != k)
286                         break;
287                 if (k <= i82365s) break;
288                 add_socket_i365(port, sock+j, id); ns++;
289             }
290           }
291         }
292         return  0;
293
294
295
296
297
298
299
300 /*      printf ( "Selecting config 1: io 0x300 @byte 87*2.." );
301         upc[(2*87)] = 2;
302         i365_bclr(1, I365_ADDRWIN, 1 );
303         i365_set(1,I365_INTCTL, 0x65 ); //no-reset, memory-card
304         i365_set(1, I365_IO(0)+0, 0x20 );
305         i365_set(1, I365_IO(0)+1, 0x03 );
306         i365_set(1, I365_IO(0)+2, 0x3f );
307         i365_set(1, I365_IO(0)+3, 0x03 );
308         i365_set(1, 0x3a, 0x05 );
309         i365_set(1, 0x3b, 0x05 );
310         i365_set(1, 0x3c, 0x05 );
311         i365_set(1, 0x3d, 0x05 );
312         i365_set(1, 0x3e, 0x05 );
313         i365_set(1, 0x3f, 0x05 );
314         i365_set(1, 0x07, 0x0a );
315         i365_set(1, I365_ADDRWIN, 0x40 ); // 0x40
316         printf ( "!\n" ); getchar();
317         printf ( "\n" );
318         return 0; */
319 }
320
321 void    phex ( unsigned char c ) {
322         unsigned char a = 0, b = 0;
323         b = ( c & 0xf );
324         if ( b > 9 ) b += ('a'-'9'-1);
325         b += '0';
326         a = ( c & 0xf0 ) >> 4;
327         if ( a > 9 ) a += ('a'-'9'-1);
328         a += '0';
329         printf ( "%c%c ", a, b );
330         return;
331 }
332
333 int     deinit_i82365(void) {
334         printf("Deinitializing i82365\n" );
335         return 0;
336 }
337
338 /*static int i365_get_status(u_short sock, u_int *value)
339 {
340     u_int status;
341
342     status = i365_get(sock, I365_STATUS);
343     *value = ((status & I365_CS_DETECT) == I365_CS_DETECT)
344         ? SS_DETECT : 0;
345
346     if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD)
347         *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
348     else {
349         *value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD;
350         *value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN;
351     }
352     *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
353     *value |= (status & I365_CS_READY) ? SS_READY : 0;
354     *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
355
356 #ifdef CONFIG_ISA
357     if (pccsock[sock].type == IS_VG469) {
358         status = i365_get(sock, VG469_VSENSE);
359         if (pccsock[sock].internalid & 1) {
360             *value |= (status & VG469_VSENSE_B_VS1) ? 0 : SS_3VCARD;
361             *value |= (status & VG469_VSENSE_B_VS2) ? 0 : SS_XVCARD;
362         } else {
363             *value |= (status & VG469_VSENSE_A_VS1) ? 0 : SS_3VCARD;
364             *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD;
365         }
366     }
367 #endif
368
369     printf("i82365: GetStatus(%d) = %#4.4x\n", sock, *value);
370     return 0;
371 } //i365_get_status
372 */
373
374 /*static int i365_set_socket(u_short sock, socket_state_t *state)
375 {
376     socket_info_t *t = &socket[sock];
377     u_char reg;
378
379     printf("i82365: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
380           "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
381           state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
382 printf ("\nERROR:UNIMPLEMENTED\n" );
383 return 0;
384     // First set global controller options 
385     // set_bridge_state(sock); *TODO* check: need this here?
386
387     // IO card, RESET flag, IO interrupt 
388     reg = t->intr;
389     if (state->io_irq != t->cap.pci_irq) reg |= state->io_irq;
390     reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
391     reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
392     i365_set(sock, I365_INTCTL, reg);
393
394     reg = I365_PWR_NORESET;
395     if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO;
396     if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT;
397
398     if (t->flags & IS_CIRRUS) {
399         if (state->Vpp != 0) {
400             if (state->Vpp == 120)
401                 reg |= I365_VPP1_12V;
402             else if (state->Vpp == state->Vcc)
403                 reg |= I365_VPP1_5V;
404             else return -EINVAL;
405         }
406         if (state->Vcc != 0) {
407             reg |= I365_VCC_5V;
408             if (state->Vcc == 33)
409                 i365_bset(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
410             else if (state->Vcc == 50)
411                 i365_bclr(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
412             else return -EINVAL;
413         }
414     } else if (t->flags & IS_VG_PWR) {
415         if (state->Vpp != 0) {
416             if (state->Vpp == 120)
417                 reg |= I365_VPP1_12V;
418             else if (state->Vpp == state->Vcc)
419                 reg |= I365_VPP1_5V;
420             else return -EINVAL;
421         }
422        if (state->Vcc != 0) {
423             reg |= I365_VCC_5V;
424             if (state->Vcc == 33)
425                 i365_bset(sock, VG469_VSELECT, VG469_VSEL_VCC);
426             else if (state->Vcc == 50)
427                 i365_bclr(sock, VG469_VSELECT, VG469_VSEL_VCC);
428             else return -EINVAL;
429         }
430     } else if (t->flags & IS_DF_PWR) {
431         switch (state->Vcc) {
432         case 0:         break;
433         case 33:        reg |= I365_VCC_3V; break;
434         case 50:        reg |= I365_VCC_5V; break;
435         default:        return -EINVAL;
436         }
437         switch (state->Vpp) {
438         case 0:         break;
439         case 50:        reg |= I365_VPP1_5V; break;
440         case 120:       reg |= I365_VPP1_12V; break;
441         default:        return -EINVAL;
442         }
443     } else {
444         switch (state->Vcc) {
445         case 0:         break;
446         case 50:        reg |= I365_VCC_5V; break;
447         default:        return -EINVAL;
448         }
449         switch (state->Vpp) {
450         case 0:         break;
451         case 50:        reg |= I365_VPP1_5V | I365_VPP2_5V; break;
452         case 120:       reg |= I365_VPP1_12V | I365_VPP2_12V; break;
453         default:        return -EINVAL;
454         }
455     }
456
457     if (reg != i365_get(sock, I365_POWER))
458         i365_set(sock, I365_POWER, reg);
459
460     // Chipset-specific functions 
461     if (t->flags & IS_CIRRUS) {
462         // Speaker control 
463         i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA,
464                    state->flags & SS_SPKR_ENA);
465     }
466
467     // Card status change interrupt mask 
468     reg = t->cs_irq << 4;
469     if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
470     if (state->flags & SS_IOCARD) {
471         if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG;
472     } else {
473         if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1;
474         if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2;
475         if (state->csc_mask & SS_READY) reg |= I365_CSC_READY;
476     }
477     i365_set(sock, I365_CSCINT, reg);
478     i365_get(sock, I365_CSC);
479
480     return 0;
481 } // i365_set_socket 
482 */
483
484 /*static int i365_get_io_map(u_short sock, struct pccard_io_map *io)
485 {
486     u_char map, ioctl, addr;
487         printf ( "GETIOMAP unimplemented\n" ); return 0;
488     map = io->map;
489     if (map > 1) return -EINVAL;
490     io->start = i365_get_pair(sock, I365_IO(map)+I365_W_START);
491     io->stop = i365_get_pair(sock, I365_IO(map)+I365_W_STOP);
492     ioctl = i365_get(sock, I365_IOCTL);
493     addr = i365_get(sock, I365_ADDRWIN);
494     io->speed = to_ns(ioctl & I365_IOCTL_WAIT(map)) ? 1 : 0;
495     io->flags  = (addr & I365_ENA_IO(map)) ? MAP_ACTIVE : 0;
496     io->flags |= (ioctl & I365_IOCTL_0WS(map)) ? MAP_0WS : 0;
497     io->flags |= (ioctl & I365_IOCTL_16BIT(map)) ? MAP_16BIT : 0;
498     io->flags |= (ioctl & I365_IOCTL_IOCS16(map)) ? MAP_AUTOSZ : 0;
499     printf("i82365: GetIOMap(%d, %d) = %#2.2x, %d ns, "
500           "%#4.4x-%#4.4x\n", sock, map, io->flags, io->speed,
501           io->start, io->stop);
502     return 0;
503 } // i365_get_io_map 
504 */
505
506 /*====================================================================*/
507
508 /*static int i365_set_io_map(u_short sock, struct pccard_io_map *io)
509 {
510     u_char map, ioctl;
511
512     printf("i82365: SetIOMap(%d, %d, %#2.2x, %d ns, "
513           "%#4.4x-%#4.4x)\n", sock, io->map, io->flags,
514           io->speed, io->start, io->stop);
515 printf ( "UNIMPLEMENTED\n" );
516         return 0;
517     map = io->map;
518     //if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
519     if ((map > 1) ||
520         (io->stop < io->start)) return -EINVAL;
521     // Turn off the window before changing anything 
522     if (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(map))
523         i365_bclr(sock, I365_ADDRWIN, I365_ENA_IO(map));
524     i365_set_pair(sock, I365_IO(map)+I365_W_START, io->start);
525     i365_set_pair(sock, I365_IO(map)+I365_W_STOP, io->stop);
526     ioctl = i365_get(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map);
527     if (io->speed) ioctl |= I365_IOCTL_WAIT(map);
528     if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map);
529     if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);
530     if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map);
531     i365_set(sock, I365_IOCTL, ioctl);
532     // Turn on the window if necessary 
533     if (io->flags & MAP_ACTIVE)
534         i365_bset(sock, I365_ADDRWIN, I365_ENA_IO(map));
535     return 0;
536 } // i365_set_io_map 
537 */
538
539 /*
540 static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
541 {
542     u_short base, i;
543     u_char map;
544
545     printf("i82365: SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5"
546           "lx, %#5.5x)\n", sock, mem->map, mem->flags, mem->speed,
547           mem->sys_start, mem->sys_stop, mem->card_start);
548
549 printf ( "UNIMPLEMENTED\n" );
550         return 0;
551     map = mem->map;
552     if ((map > 4) || (mem->card_start > 0x3ffffff) ||
553         (mem->sys_start > mem->sys_stop) || (mem->speed > 1000))
554         return -EINVAL;
555     if (!(socket[sock].flags & IS_PCI) &&
556         ((mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff)))
557         return -EINVAL;
558
559     // Turn off the window before changing anything 
560     if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map))
561         i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map));
562
563     base = I365_MEM(map);
564     i = (mem->sys_start >> 12) & 0x0fff;
565     if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT;
566     if (mem->flags & MAP_0WS) i |= I365_MEM_0WS;
567     i365_set_pair(sock, base+I365_W_START, i);
568
569     i = (mem->sys_stop >> 12) & 0x0fff;
570     switch (to_cycles(mem->speed)) {
571     case 0:     break;
572     case 1:     i |= I365_MEM_WS0; break;
573     case 2:     i |= I365_MEM_WS1; break;
574     default:    i |= I365_MEM_WS1 | I365_MEM_WS0; break;
575     }
576     i365_set_pair(sock, base+I365_W_STOP, i);
577
578     i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff;
579     if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT;
580     if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG;
581     i365_set_pair(sock, base+I365_W_OFF, i);
582
583     // Turn on the window if necessary 
584     if (mem->flags & MAP_ACTIVE)
585         i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map));
586     return 0;
587 } // i365_set_mem_map 
588 */
589
590
591 int     i82365_interfacer ( interface_func_t func, int sockno, int par1, int par2, void* par3 ) {
592         //int   i, j, k;
593         //u_int ui;
594         u_char *upc;
595         struct pcc_config_t * pccc;
596         switch ( func ) {
597           case  INIT:
598                 mydriverid = par1;
599                 return  init_i82365();
600           case  SHUTDOWN:
601                 i365_set(sockno, I365_ADDRWIN, i365_get(sockno, I365_ADDRWIN) & 0x20 );
602                 i365_set(sockno, I365_INTCTL, 0x05 );
603                 sleepticks(2);
604                 i365_set(sockno,I365_INTCTL, 0x45 ); //no-reset, memory-card
605                 break;
606           case  MAPATTRMEM:
607                 i365_set(sockno,I365_POWER, 0xb1 );
608                 i365_set(sockno, I365_INTCTL, 0x05 );
609                 sleepticks(2);
610                 i365_set(sockno,I365_INTCTL, 0x45 ); //no-reset, memory-card
611                 i365_set(sockno, I365_ADDRWIN, i365_get(sockno, I365_ADDRWIN) & 0x20 );
612                 //i365_bclr(sockno, I365_ADDRWIN, 1 );
613                 i365_set(sockno, I365_MEM(0)+0, ( par1 >> 12 )& 0xff ); //start
614                 i365_set(sockno, I365_MEM(0)+1, ( par1 >> 20 ) & 0x0f );
615                 i365_set(sockno, I365_MEM(0)+2, ((par1 + par2 - 1 ) >> 12 ) & 0xff ); //end
616                 i365_set(sockno, I365_MEM(0)+3, (( par1 + par2 - 1 ) >> 20 ) & 0x0f  );
617                 i365_set(sockno, I365_MEM(0)+4, ((0x4000000 - par1) >> 12) & 0xff ); //offset low
618                 i365_set(sockno, I365_MEM(0)+5, 0x40 | (((0x40000000 - par1) >> 12) & 0x3f));
619                 i365_bset(sockno, I365_ADDRWIN, 1 );
620                 if ( ! ( 1 & i365_get ( sockno, I365_ADDRWIN ) ) ) return 1;
621                 break;
622           case  UNMAPATTRMEM:
623                 i365_set(sockno, I365_ADDRWIN, i365_get(sockno, I365_ADDRWIN) & 0x20 );
624                 i365_set(sockno,I365_INTCTL, 0x45 ); //no-reset, memory-card
625                 break;
626           case  SELECTCONFIG:   // Params: par1: config number; par3 config pointer pointer
627                 if ( 0 > pccsock[sockno].configoffset ) return 1;
628                 if ( NULL == (pccc = par3 ) ) return 2;
629                 // write config number to 
630                 upc = ioremap ( MAP_ATTRMEM_TO, MAP_ATTRMEM_LEN );
631                 if ( pccsock[sockno].configoffset > MAP_ATTRMEM_LEN ) return 3;
632                 if ( ( par1 & 0x7fffffc0 ) ) return 4;
633                 if ( pccc->index != par1 ) return 5;
634                 upc[pccsock[sockno].configoffset] = ( upc[pccsock[sockno].configoffset] & 0xc0 ) | ( par1 & 0x3f );
635                 i365_set(sockno, I365_IOCTL, (i365_get(sockno, I365_IOCTL) & 0xfe) | 0x20 );    // 16bit autosize
636                 i365_set(sockno, I365_IO(0)+0, pccc->iowin & 0xff);
637                 i365_set(sockno, I365_IO(0)+1, (pccc->iowin >> 8) & 0xff);
638                 i365_set(sockno, I365_IO(0)+2, (pccc->iowin+pccc->iolen - 1) & 0xff);
639                 i365_set(sockno, I365_IO(0)+3, ((pccc->iowin+pccc->iolen- 1) >> 8) & 0xff);
640                 // Disable mem mapping
641                 i365_bclr(sockno, I365_ADDRWIN, 1);
642                 i365_set(sockno, I365_INTCTL, 0x65);
643                 i365_bset(sockno, I365_ADDRWIN,0x40);
644                 break;
645           default:
646                 return  -1; // ERROR: Unknown function called
647         }
648         return  0;
649 }
650
651 // get_mem_map[1320]
652 // cirrus_get_state/set/opts...
653 // vg46x_get_state/...
654 // get_bridge_state/...
655
656 #endif /* CONFIG_PCMCIA */