Home | History | Annotate | Download | only in core
      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 (at) 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 */
    657