| #if 0 | |
| /* | |
| * pcmcia.c | |
| * | |
| * PCMCIA support routines for etherboot - generic stuff | |
| * | |
| * This code has partly be taken from the linux kernel sources, .../drivers/pcmcia/ | |
| * Started & put together by | |
| * Anselm Martin Hoffmeister | |
| * Stockholm Projekt Computer-Service | |
| * Sankt Augustin / Bonn, Germany | |
| * | |
| * Distributed under GPL2 | |
| */ | |
| /* | |
| * | |
| * | |
| * ****************************** | |
| * PLEASE DO NOT YET WORK ON THIS | |
| * ****************************** | |
| * | |
| * I'm still fixing it up on every end, so we most probably would interfere | |
| * at some point. If there's anything obvious or better, not-so-obvious, | |
| * please contact me by e-mail: anselm (AT) hoffmeister (DOT) be *THANKS* | |
| */ | |
| FILE_LICENCE ( GPL2_ONLY ); | |
| #include <stdio.h> | |
| #include <pcmcia.h> | |
| #include <i82365.h> | |
| #define CODE_STATUS "alpha" | |
| #define CODE_VERSION "0.1.3" | |
| #include <pcmcia-opts.h> | |
| #include <ipxe/init.h> | |
| int sockets; /* AHTODO: Phase this out! */ | |
| u_int pccsocks; | |
| struct pccsock_t pccsock[MAXPCCSOCKS]; | |
| int inited = -1; | |
| struct pcc_config_t pccconfig[MAXPCCCONFIGS]; | |
| struct driver_interact_t driver[] = { | |
| #ifdef SUPPORT_I82365 | |
| { I82365, i82365_interfacer, "Intel_82365" }, | |
| #endif | |
| }; | |
| #define NUM_DRIVERS (sizeof(driver)/(sizeof(struct driver_interact_t))) | |
| void sleepticks(int numticks ) { | |
| u_int tmo; | |
| for (tmo = currticks()+numticks; currticks() < tmo; ) { | |
| } | |
| return; | |
| } | |
| static void pcmcia_init_all(void) { | |
| u_int i, j, k, l, m, n, ui, configs = 0; | |
| u_int multicard[8]; | |
| u_char *uc, upc; | |
| if ( PDEBUG > 0 ) printf("Initializing PCMCIA subsystem (code-status: " CODE_STATUS ", Version " CODE_VERSION ")\n"); | |
| if ( PDEBUG > 2 ) { | |
| printf ( "Supporting %d driver(s): ", NUM_DRIVERS ); | |
| for ( i = 0; i < NUM_DRIVERS; ++i ) { | |
| printf ( "[%s] ", driver[i].name ); | |
| } | |
| printf ( "\n" ); | |
| } | |
| pccsocks = 0; | |
| sockets = 0; | |
| // Init all drivers in the driver[] array: | |
| for ( i = 0; i < NUM_DRIVERS; ++i ) { | |
| driver[i].f(INIT,0,i,0,0); // init needs no params. It uses pccsocks and pccsock[]. | |
| // Only i tells it which driver_id itself is. | |
| } | |
| for ( i = 0; i < pccsocks; ++i ) { | |
| printf ( "Socket %d: ", i ); | |
| if ( pccsock[i].status != HASCARD ) { | |
| printf ( "is %s: skipping\n", pccsock[i].status == EMPTY? "empty":"[status unknown]" ); | |
| continue; | |
| } | |
| if ( 0 != driver[pccsock[i].drivernum].f(MAPATTRMEM,pccsock[i].internalid,MAP_ATTRMEM_TO, MAP_ATTRMEM_LEN,0 ) ) { | |
| printf ("PCMCIA controller failed to map attribute memory.\n**** SEVERE ERROR CONDITION. Skipping controller.\n" ); | |
| if ( PDEBUG > 2 ) { | |
| printf ( "<press key. THIS CONDITION SHOULD BE REPORTED!>\n" ); getchar(); | |
| } | |
| continue; | |
| } | |
| // parse configuration information | |
| uc = ioremap ( MAP_ATTRMEM_TO, MAP_ATTRMEM_LEN ); | |
| pccsock[i].stringoffset = pccsock[i].configoffset = pccsock[i].stringlength = 0; | |
| pccsock[i].type = 0xff; | |
| for ( l = 0; l < 8; ++l ) multicard[l] = 0; | |
| sleepticks(2); | |
| for ( l = ui = 0; ui < 0x800; ui += uc[(2*ui)+2] + 2 ) { | |
| if ( uc[(2*ui)] == 0xff ) { | |
| break; | |
| } | |
| // This loop is complete rubbish AFAICS. | |
| // But without it, my test system won't come up. | |
| // It's too bad to develop on broken hardware | |
| // - Anselm | |
| } | |
| sleepticks(2); | |
| configs = 0; | |
| inited = -1; | |
| for ( l = ui = 0; ui < 0x800; ui += uc[(2*ui)+2] + 2 ) { | |
| if ( uc[(2*ui)] == 0xff ) break; | |
| else if ( uc[2*ui] == 0x15 ) { | |
| for ( k = 2 * ( ui + 2 ); ( uc[k] <= ' ' ) && ( k < ( 2 * ( uc[2*(ui+1)] + ui + 2 ) ) ) ; k += 2 ) { ; } | |
| pccsock[i].stringoffset = k; | |
| pccsock[i].stringlength = ( 2 * ( ui + 2 + uc[(2*ui)+2] ) - k ) / 2; | |
| } else if ( uc[2*ui] == 0x21 ) { | |
| pccsock[i].type = uc[(2*ui)+4]; | |
| } else if ( uc[2*ui] == 0x1a ) { // Configuration map | |
| printf ( "\nConfig map 0x1a found [" ); | |
| for ( k = 0; k < uc[2*(ui+1)]; ++k ) { | |
| printf ( "%02x ", uc[2*(ui+k+2)] ); | |
| } | |
| printf ( "]\nHighest config available is %d\n", uc[2*(ui+3)] ); | |
| m = uc[2*(ui+2)]; | |
| pccsock[i].configoffset = 0; | |
| for ( j = 0; j <= (m & 3); ++j ) { | |
| pccsock[i].configoffset += uc[2*(ui+4+j)] << (8*j); | |
| } | |
| pccsock[i].rmask0 = 0; | |
| for ( j = 0; j <= ( ( ( m & 0x3c ) >> 2 ) & 3 ); ++j ) { | |
| pccsock[i].rmask0 += uc[2*(ui+5+(m&3)+j)] << (8*j); | |
| } | |
| j = pccsock[i].rmask0; | |
| printf ( "Config offset is %x, card has regs: < %s%s%s%s%s>\n", pccsock[i].configoffset, | |
| j & 1 ? "COR ":"", j & 2 ? "CCSR ":"", j & 4 ? "PRR ":"", j & 8 ? "SCR ":"", j & 16? "ESR ":"" ); | |
| printf ( "COR + CCSR contents (si/du) %x %x/%x %x\n", uc[pccsock[i].configoffset+0], | |
| uc[pccsock[i].configoffset+2],uc[pccsock[i].configoffset*2],uc[(pccsock[i].configoffset*2)+2] ); | |
| printf ( " " ); | |
| } else if ( uc[2*ui] == 0x1b ) { // Configuration data entry | |
| //printf ( "Config data 0x1b found [\n" );getchar(); | |
| for ( k = 0; k < uc[2*(ui+1)]; ++k ) { | |
| // printf ( "%02x ", uc[2*(ui+k+2)] ); | |
| } | |
| // Parse this tuple into pccconfig[configs] | |
| // printf ( "]\n" ); | |
| if ( configs == MAXPCCCONFIGS ) continue; | |
| k = 2*ui+4; | |
| pccconfig[configs].index = uc[k] & 0x3f; | |
| if ( uc[k] & 0x80 ) { | |
| // printf ( "Special config, unsupp. for now\n" ); | |
| continue; | |
| } | |
| k+=2; | |
| // printf ( "Features: %2x\n", uc[k] ); | |
| if ( uc[k] & 0x7 ) { | |
| // printf ( "Cannot work with Vcc/Timing configs right now\n" ); | |
| continue; | |
| } | |
| pccconfig[configs].iowin = pccconfig[configs].iolen = 0; | |
| if ( 0 != ( uc[k] & 0x8 ) ) { | |
| k+=2; | |
| // printf ( "Reading IO config: " ); | |
| if ( 0 == ( uc[k] & 0x80 ) ) { | |
| // printf ( "Cannot work with auto/io config\n" ); | |
| continue; | |
| } | |
| k+=2; | |
| if ( 0 != ( uc[k] & 0x0f ) ) { | |
| // printf ( "Don't support more than 1 iowin right now\n" ); | |
| continue; | |
| } | |
| j = (uc[k] & 0x30) >> 4; | |
| m = (uc[k] & 0xc0) >> 6; | |
| if ( 3 == j ) ++j; | |
| if ( 3 == m ) ++m; | |
| k += 2; | |
| pccconfig[configs].iowin = 0; | |
| pccconfig[configs].iolen = 1; | |
| for ( n = 0; n < j; ++n, k+=2 ) { | |
| pccconfig[configs].iowin += uc[k] << (n*8); | |
| } | |
| for ( n = 0; n < m; ++n, k+=2 ) { | |
| pccconfig[configs].iolen += uc[k] << (n*8); | |
| } | |
| // printf ( "io %x len %d (%d)\n", pccconfig[configs].iowin, pccconfig[configs].iolen,configs ); | |
| } | |
| for ( j = 0; j < (uc[k] & 3); ++j ) { | |
| // pccconfig[configs].iowin += (uc[k+(2*j)+2]) << (8*j); | |
| } | |
| ++configs; | |
| } | |
| } | |
| if ( pccsock[i].stringoffset > 0 ) { // If no identifier, it's not a valid CIS (as of documentation...) | |
| printf ( "[" ); | |
| for ( k = 0; ( k < pccsock[i].stringlength ) && ( k < 64 ); ++k ) { | |
| j = uc[pccsock[i].stringoffset + 2 * k]; | |
| printf ( "%c", (j>=' '? j:' ' ) ); | |
| } | |
| printf ("]\n is type %d (", pccsock[i].type ); | |
| switch ( pccsock[i].type ) { | |
| case 0x00: | |
| printf ( "MULTI" ); break; | |
| case 0x01: | |
| printf ( "Memory" ); break; | |
| case 0x02: | |
| printf ( "Serial" ); break; | |
| case 0x03: | |
| printf ( "Parallel" ); break; | |
| case 0x04: | |
| printf ( "Fixed" ); break; | |
| case 0x05: | |
| printf ( "Video" ); break; | |
| case 0x06: | |
| printf ( "Network" ); break; | |
| case 0x07: | |
| printf ( "AIMS" ); break; | |
| case 0x08: | |
| printf ( "SCSI" ); break; | |
| case 0x106: // Special / homebrew to say "Multi/network" | |
| printf ( "MULTI, with Network" ); break; // AHTODO find a card for this | |
| default: | |
| printf ( "UNSUPPORTED/UNKNOWN" ); | |
| } | |
| printf ( ") with %d possible configuration(s)\n", configs ); | |
| // Now set dependency: If it's Network or multi->network, accept | |
| if ( (inited <= 0 ) && (6 == (0xff & pccsock[i].type) ) && (0 < configs ) ) { | |
| printf ( "activating this device with ioport %x-%x (config #%d)\n", | |
| pccconfig[0].iowin, pccconfig[0].iowin+pccconfig[0].iolen-1, pccconfig[0].index ); | |
| inited = i; | |
| // And unmap attrmem ourselves! | |
| printf ( "Activating config..." ); | |
| if ( m=driver[pccsock[i].drivernum].f(SELECTCONFIG,pccsock[i].internalid,pccconfig[0].index,0,&pccconfig[0]) ) { | |
| printf ("Failure(%d)!",m); inited = -1; | |
| driver[pccsock[i].drivernum].f(UNMAPATTRMEM,pccsock[i].internalid,0,0,0); | |
| } | |
| printf ( "done!\n" ); | |
| continue; | |
| } | |
| } else { | |
| printf ( "unsupported - no identifier string found in CIS\n" ); | |
| } | |
| // unmap the PCMCIA device | |
| if ( i != inited ) { | |
| if ( 0 != driver[pccsock[i].drivernum].f(UNMAPATTRMEM,pccsock[i].internalid,0,0,0) ) { | |
| printf ("PCMCIA controller failed to unmap attribute memory.\n**** SEVERE ERROR CONDITION ****\n" ); | |
| if ( PDEBUG > 2 ) { | |
| printf ( "<press key. THIS CONDITION SHOULD BE REPORTED!>\n" ); getchar(); | |
| } | |
| continue; | |
| } | |
| } | |
| } | |
| if ( PDEBUG > 2 ) { | |
| printf ( "<press key to exit the pcmcia_init_all routine>\n" ); | |
| getchar(); | |
| } | |
| } | |
| static void pcmcia_shutdown_all(void) { | |
| int i; | |
| //if ( PDEBUG > 2 ) {printf("<press key to continue>\n" ); getchar(); } | |
| for ( i = 0; i < pccsocks; ++i ) { | |
| driver[pccsock[i].drivernum].f(SHUTDOWN,pccsock[i].internalid,0,0,0); | |
| } | |
| printf("Shutdown of PCMCIA subsystem completed"); | |
| } | |
| #endif |