00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 FILE_LICENCE ( GPL2_OR_LATER );
00059
00060 #include <stdint.h>
00061 #include <stdlib.h>
00062 #include <string.h>
00063 #include <stdio.h>
00064 #include <errno.h>
00065 #include <gpxe/io.h>
00066 #include <unistd.h>
00067 #include <gpxe/isapnp.h>
00068
00069
00070
00071
00072
00073
00074
00075 uint16_t isapnp_read_port;
00076
00077 static void isapnpbus_remove ( struct root_device *rootdev );
00078
00079
00080
00081
00082
00083
00084 #define ISAPNP_CARD_ID_FMT "ID %04x:%04x (\"%s\") serial %x"
00085 #define ISAPNP_CARD_ID_DATA(identifier) \
00086 (identifier)->vendor_id, (identifier)->prod_id, \
00087 isa_id_string ( (identifier)->vendor_id, (identifier)->prod_id ), \
00088 (identifier)->serial
00089 #define ISAPNP_DEV_ID_FMT "ID %04x:%04x (\"%s\")"
00090 #define ISAPNP_DEV_ID_DATA(isapnp) \
00091 (isapnp)->vendor_id, (isapnp)->prod_id, \
00092 isa_id_string ( (isapnp)->vendor_id, (isapnp)->prod_id )
00093
00094 static inline void isapnp_write_address ( unsigned int address ) {
00095 outb ( address, ISAPNP_ADDRESS );
00096 }
00097
00098 static inline void isapnp_write_data ( unsigned int data ) {
00099 outb ( data, ISAPNP_WRITE_DATA );
00100 }
00101
00102 static inline unsigned int isapnp_read_data ( void ) {
00103 return inb ( isapnp_read_port );
00104 }
00105
00106 static inline void isapnp_write_byte ( unsigned int address,
00107 unsigned int value ) {
00108 isapnp_write_address ( address );
00109 isapnp_write_data ( value );
00110 }
00111
00112 static inline unsigned int isapnp_read_byte ( unsigned int address ) {
00113 isapnp_write_address ( address );
00114 return isapnp_read_data ();
00115 }
00116
00117 static inline unsigned int isapnp_read_word ( unsigned int address ) {
00118
00119 return ( ( isapnp_read_byte ( address ) << 8 )
00120 | isapnp_read_byte ( address + 1 ) );
00121 }
00122
00123
00124 static inline void isapnp_set_read_port ( void ) {
00125 isapnp_write_byte ( ISAPNP_READPORT, ( isapnp_read_port >> 2 ) );
00126 }
00127
00128
00129
00130
00131
00132
00133
00134 static inline void isapnp_serialisolation ( void ) {
00135 isapnp_write_address ( ISAPNP_SERIALISOLATION );
00136 }
00137
00138
00139
00140
00141
00142
00143
00144 static inline void isapnp_wait_for_key ( void ) {
00145 isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_WAIT_FOR_KEY );
00146 }
00147
00148
00149
00150
00151
00152
00153
00154 static inline void isapnp_reset_csn ( void ) {
00155 isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_RESET_CSN );
00156 }
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 static inline void isapnp_wake ( uint8_t csn ) {
00170 isapnp_write_byte ( ISAPNP_WAKE, csn );
00171 }
00172
00173 static inline unsigned int isapnp_read_resourcedata ( void ) {
00174 return isapnp_read_byte ( ISAPNP_RESOURCEDATA );
00175 }
00176
00177 static inline unsigned int isapnp_read_status ( void ) {
00178 return isapnp_read_byte ( ISAPNP_STATUS );
00179 }
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 static inline void isapnp_write_csn ( unsigned int csn ) {
00192 isapnp_write_byte ( ISAPNP_CARDSELECTNUMBER, csn );
00193 }
00194
00195 static inline void isapnp_logicaldevice ( unsigned int logdev ) {
00196 isapnp_write_byte ( ISAPNP_LOGICALDEVICENUMBER, logdev );
00197 }
00198
00199 static inline void isapnp_activate ( unsigned int logdev ) {
00200 isapnp_logicaldevice ( logdev );
00201 isapnp_write_byte ( ISAPNP_ACTIVATE, 1 );
00202 }
00203
00204 static inline void isapnp_deactivate ( unsigned int logdev ) {
00205 isapnp_logicaldevice ( logdev );
00206 isapnp_write_byte ( ISAPNP_ACTIVATE, 0 );
00207 }
00208
00209 static inline unsigned int isapnp_read_iobase ( unsigned int index ) {
00210 return isapnp_read_word ( ISAPNP_IOBASE ( index ) );
00211 }
00212
00213 static inline unsigned int isapnp_read_irqno ( unsigned int index ) {
00214 return isapnp_read_byte ( ISAPNP_IRQNO ( index ) );
00215 }
00216
00217 static void isapnp_delay ( void ) {
00218 udelay ( 1000 );
00219 }
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235 static inline unsigned int isapnp_lfsr_next ( unsigned int lfsr,
00236 unsigned int input_bit ) {
00237 register uint8_t lfsr_next;
00238
00239 lfsr_next = lfsr >> 1;
00240 lfsr_next |= ( ( ( lfsr ^ lfsr_next ) ^ input_bit ) ) << 7;
00241 return lfsr_next;
00242 }
00243
00244
00245
00246
00247
00248
00249
00250 static void isapnp_send_key ( void ) {
00251 unsigned int i;
00252 unsigned int lfsr;
00253
00254 isapnp_delay();
00255 isapnp_write_address ( 0x00 );
00256 isapnp_write_address ( 0x00 );
00257
00258 lfsr = ISAPNP_LFSR_SEED;
00259 for ( i = 0 ; i < 32 ; i++ ) {
00260 isapnp_write_address ( lfsr );
00261 lfsr = isapnp_lfsr_next ( lfsr, 0 );
00262 }
00263 }
00264
00265
00266
00267
00268
00269
00270
00271 static unsigned int isapnp_checksum ( struct isapnp_identifier *identifier ) {
00272 unsigned int i, j;
00273 unsigned int lfsr;
00274 unsigned int byte;
00275
00276 lfsr = ISAPNP_LFSR_SEED;
00277 for ( i = 0 ; i < 8 ; i++ ) {
00278 byte = * ( ( ( uint8_t * ) identifier ) + i );
00279 for ( j = 0 ; j < 8 ; j++ ) {
00280 lfsr = isapnp_lfsr_next ( lfsr, byte );
00281 byte >>= 1;
00282 }
00283 }
00284 return lfsr;
00285 }
00286
00287
00288
00289
00290
00291
00292 static inline unsigned int isapnp_peek_byte ( void ) {
00293 unsigned int i;
00294
00295
00296 for ( i = 0 ; i < 20 ; i++ ) {
00297 if ( isapnp_read_status() & 0x01 ) {
00298
00299 return isapnp_read_resourcedata();
00300 }
00301 isapnp_delay();
00302 }
00303
00304 return 0xff;
00305 }
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316 static void isapnp_peek ( void *buf, size_t len ) {
00317 unsigned int i;
00318 unsigned int byte;
00319
00320 for ( i = 0 ; i < len ; i++) {
00321 byte = isapnp_peek_byte();
00322 if ( buf )
00323 * ( ( uint8_t * ) buf + i ) = byte;
00324 }
00325 }
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338 static int isapnp_find_tag ( unsigned int wanted_tag, void *buf, size_t len ) {
00339 unsigned int tag;
00340 unsigned int tag_len;
00341
00342 DBG2 ( "ISAPnP read tag" );
00343 do {
00344 tag = isapnp_peek_byte();
00345 if ( ISAPNP_IS_SMALL_TAG ( tag ) ) {
00346 tag_len = ISAPNP_SMALL_TAG_LEN ( tag );
00347 tag = ISAPNP_SMALL_TAG_NAME ( tag );
00348 } else {
00349 tag_len = ( isapnp_peek_byte() +
00350 ( isapnp_peek_byte() << 8 ) );
00351 tag = ISAPNP_LARGE_TAG_NAME ( tag );
00352 }
00353 DBG2 ( " %02x (%02x)", tag, tag_len );
00354 if ( tag == wanted_tag ) {
00355 if ( len > tag_len )
00356 len = tag_len;
00357 isapnp_peek ( buf, len );
00358 DBG2 ( "\n" );
00359 return 0;
00360 } else {
00361 isapnp_peek ( NULL, tag_len );
00362 }
00363 } while ( tag != ISAPNP_TAG_END );
00364 DBG2 ( "\n" );
00365 return -ENOENT;
00366 }
00367
00368
00369
00370
00371
00372
00373
00374
00375 static int isapnp_find_logdevid ( unsigned int logdev,
00376 struct isapnp_logdevid *logdevid ) {
00377 unsigned int i;
00378 int rc;
00379
00380 for ( i = 0 ; i <= logdev ; i++ ) {
00381 if ( ( rc = isapnp_find_tag ( ISAPNP_TAG_LOGDEVID, logdevid,
00382 sizeof ( *logdevid ) ) ) != 0 )
00383 return rc;
00384 }
00385 return 0;
00386 }
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399 static int isapnp_try_isolate ( void ) {
00400 struct isapnp_identifier identifier;
00401 unsigned int i, j;
00402 unsigned int seen_55aa, seen_life;
00403 unsigned int csn = 0;
00404 unsigned int data;
00405 unsigned int byte;
00406
00407 DBG ( "ISAPnP attempting isolation at read port %04x\n",
00408 isapnp_read_port );
00409
00410
00411
00412
00413 isapnp_wait_for_key();
00414 isapnp_send_key();
00415
00416
00417 isapnp_reset_csn();
00418 isapnp_delay();
00419 isapnp_delay();
00420
00421
00422 isapnp_wait_for_key ();
00423 isapnp_send_key();
00424 isapnp_wake ( 0x00 );
00425
00426
00427 isapnp_set_read_port();
00428 isapnp_delay();
00429
00430 while ( 1 ) {
00431
00432
00433
00434
00435
00436
00437
00438 isapnp_serialisolation();
00439 isapnp_delay();
00440
00441
00442 memset ( &identifier, 0, sizeof ( identifier ) );
00443 seen_55aa = seen_life = 0;
00444 for ( i = 0 ; i < 9 ; i++ ) {
00445 byte = 0;
00446 for ( j = 0 ; j < 8 ; j++ ) {
00447 data = isapnp_read_data();
00448 isapnp_delay();
00449 data = ( ( data << 8 ) | isapnp_read_data() );
00450 isapnp_delay();
00451 byte >>= 1;
00452 if ( data != 0xffff ) {
00453 seen_life++;
00454 if ( data == 0x55aa ) {
00455 byte |= 0x80;
00456 seen_55aa++;
00457 }
00458 }
00459 }
00460 *( ( ( uint8_t * ) &identifier ) + i ) = byte;
00461 }
00462
00463
00464 if ( ! seen_55aa ) {
00465 if ( csn ) {
00466 DBG ( "ISAPnP found no more cards\n" );
00467 } else {
00468 if ( seen_life ) {
00469 DBG ( "ISAPnP saw life but no cards, "
00470 "trying new read port\n" );
00471 csn = -1;
00472 } else {
00473 DBG ( "ISAPnP saw no signs of life, "
00474 "abandoning isolation\n" );
00475 }
00476 }
00477 break;
00478 }
00479
00480
00481 if ( identifier.checksum != isapnp_checksum ( &identifier) ) {
00482 DBG ( "ISAPnP found malformed card "
00483 ISAPNP_CARD_ID_FMT "\n with checksum %02x "
00484 "(should be %02x), trying new read port\n",
00485 ISAPNP_CARD_ID_DATA ( &identifier ),
00486 identifier.checksum,
00487 isapnp_checksum ( &identifier) );
00488 csn = -1;
00489 break;
00490 }
00491
00492
00493 csn++;
00494 DBG ( "ISAPnP found card " ISAPNP_CARD_ID_FMT
00495 ", assigning CSN %02x\n",
00496 ISAPNP_CARD_ID_DATA ( &identifier ), csn );
00497
00498 isapnp_write_csn ( csn );
00499 isapnp_delay();
00500
00501
00502
00503
00504 isapnp_wake ( 0x00 );
00505 isapnp_delay();
00506 }
00507
00508
00509 isapnp_wait_for_key();
00510
00511
00512 if ( csn > 0 ) {
00513 DBG ( "ISAPnP found %d cards at read port %04x\n",
00514 csn, isapnp_read_port );
00515 }
00516 return csn;
00517 }
00518
00519
00520
00521
00522
00523 static void isapnp_isolate ( void ) {
00524 for ( isapnp_read_port = ISAPNP_READ_PORT_START ;
00525 isapnp_read_port <= ISAPNP_READ_PORT_MAX ;
00526 isapnp_read_port += ISAPNP_READ_PORT_STEP ) {
00527
00528
00529
00530 if ( ( isapnp_read_port >= 0x280 ) &&
00531 ( isapnp_read_port <= 0x380 ) )
00532 continue;
00533
00534
00535 if ( isapnp_try_isolate() >= 0 )
00536 return;
00537 }
00538 }
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553 void isapnp_device_activation ( struct isapnp_device *isapnp,
00554 int activation ) {
00555
00556 isapnp_wait_for_key ();
00557 isapnp_send_key ();
00558 isapnp_wake ( isapnp->csn );
00559 isapnp_logicaldevice ( isapnp->logdev );
00560
00561
00562 isapnp_activate ( activation );
00563 isapnp_delay();
00564
00565
00566 isapnp_wait_for_key ();
00567
00568 DBG ( "ISAPnP %s device %02x:%02x\n",
00569 ( activation ? "activated" : "deactivated" ),
00570 isapnp->csn, isapnp->logdev );
00571 }
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582 static int isapnp_probe ( struct isapnp_device *isapnp ) {
00583 struct isapnp_driver *driver;
00584 struct isapnp_device_id *id;
00585 unsigned int i;
00586 int rc;
00587
00588 DBG ( "Adding ISAPnP device %02x:%02x (%04x:%04x (\"%s\") "
00589 "io %x irq %d)\n", isapnp->csn, isapnp->logdev,
00590 isapnp->vendor_id, isapnp->prod_id,
00591 isa_id_string ( isapnp->vendor_id, isapnp->prod_id ),
00592 isapnp->ioaddr, isapnp->irqno );
00593
00594 for_each_table_entry ( driver, ISAPNP_DRIVERS ) {
00595 for ( i = 0 ; i < driver->id_count ; i++ ) {
00596 id = &driver->ids[i];
00597 if ( id->vendor_id != isapnp->vendor_id )
00598 continue;
00599 if ( ISA_PROD_ID ( id->prod_id ) !=
00600 ISA_PROD_ID ( isapnp->prod_id ) )
00601 continue;
00602 isapnp->driver = driver;
00603 isapnp->driver_name = id->name;
00604 DBG ( "...using driver %s\n", isapnp->driver_name );
00605 if ( ( rc = driver->probe ( isapnp, id ) ) != 0 ) {
00606 DBG ( "......probe failed\n" );
00607 continue;
00608 }
00609 return 0;
00610 }
00611 }
00612
00613 DBG ( "...no driver found\n" );
00614 return -ENOTTY;
00615 }
00616
00617
00618
00619
00620
00621
00622 static void isapnp_remove ( struct isapnp_device *isapnp ) {
00623 isapnp->driver->remove ( isapnp );
00624 DBG ( "Removed ISAPnP device %02x:%02x\n",
00625 isapnp->csn, isapnp->logdev );
00626 }
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636 static int isapnpbus_probe ( struct root_device *rootdev ) {
00637 struct isapnp_device *isapnp = NULL;
00638 struct isapnp_identifier identifier;
00639 struct isapnp_logdevid logdevid;
00640 unsigned int csn;
00641 unsigned int logdev;
00642 int rc;
00643
00644
00645 if ( ! isapnp_read_port )
00646 isapnp_isolate();
00647
00648 for ( csn = 1 ; csn <= 0xff ; csn++ ) {
00649 for ( logdev = 0 ; logdev <= 0xff ; logdev++ ) {
00650
00651
00652 if ( ! isapnp )
00653 isapnp = malloc ( sizeof ( *isapnp ) );
00654 if ( ! isapnp ) {
00655 rc = -ENOMEM;
00656 goto err;
00657 }
00658 memset ( isapnp, 0, sizeof ( *isapnp ) );
00659 isapnp->csn = csn;
00660 isapnp->logdev = logdev;
00661
00662
00663 isapnp_wait_for_key();
00664 isapnp_send_key();
00665 isapnp_wake ( csn );
00666
00667
00668 isapnp_peek ( &identifier, sizeof ( identifier ) );
00669
00670
00671 if ( identifier.vendor_id & 0x80 )
00672 goto done;
00673
00674
00675 if ( ( rc = isapnp_find_logdevid ( logdev,
00676 &logdevid ) ) != 0){
00677
00678 break;
00679 }
00680
00681
00682 isapnp_logicaldevice ( logdev );
00683
00684
00685 isapnp->vendor_id = logdevid.vendor_id;
00686 isapnp->prod_id = logdevid.prod_id;
00687 isapnp->ioaddr = isapnp_read_iobase ( 0 );
00688 isapnp->irqno = isapnp_read_irqno ( 0 );
00689
00690
00691 isapnp_wait_for_key();
00692
00693
00694 snprintf ( isapnp->dev.name,
00695 sizeof ( isapnp->dev.name ),
00696 "ISAPnP%02x:%02x", csn, logdev );
00697 isapnp->dev.desc.bus_type = BUS_TYPE_ISAPNP;
00698 isapnp->dev.desc.vendor = isapnp->vendor_id;
00699 isapnp->dev.desc.device = isapnp->prod_id;
00700 isapnp->dev.desc.ioaddr = isapnp->ioaddr;
00701 isapnp->dev.desc.irq = isapnp->irqno;
00702 isapnp->dev.parent = &rootdev->dev;
00703 list_add ( &isapnp->dev.siblings,
00704 &rootdev->dev.children );
00705 INIT_LIST_HEAD ( &isapnp->dev.children );
00706
00707
00708 if ( isapnp_probe ( isapnp ) == 0 ) {
00709
00710 isapnp = NULL;
00711 } else {
00712
00713 list_del ( &isapnp->dev.siblings );
00714 }
00715 }
00716 }
00717
00718 done:
00719 free ( isapnp );
00720 return 0;
00721
00722 err:
00723 free ( isapnp );
00724 isapnpbus_remove ( rootdev );
00725 return rc;
00726 }
00727
00728
00729
00730
00731
00732
00733 static void isapnpbus_remove ( struct root_device *rootdev ) {
00734 struct isapnp_device *isapnp;
00735 struct isapnp_device *tmp;
00736
00737 list_for_each_entry_safe ( isapnp, tmp, &rootdev->dev.children,
00738 dev.siblings ) {
00739 isapnp_remove ( isapnp );
00740 list_del ( &isapnp->dev.siblings );
00741 free ( isapnp );
00742 }
00743 }
00744
00745
00746 static struct root_driver isapnp_root_driver = {
00747 .probe = isapnpbus_probe,
00748 .remove = isapnpbus_remove,
00749 };
00750
00751
00752 struct root_device isapnp_root_device __root_device = {
00753 .dev = { .name = "ISAPnP" },
00754 .driver = &isapnp_root_driver,
00755 };