You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

isapnp.c 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. /**************************************************************************
  2. *
  3. * isapnp.c -- Etherboot isapnp support for the 3Com 3c515
  4. * Written 2002-2003 by Timothy Legge <tlegge@rogers.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19. * 02110-1301, USA.
  20. *
  21. * Portions of this code:
  22. * Copyright (C) 2001 P.J.H.Fox (fox@roestock.demon.co.uk)
  23. *
  24. *
  25. * REVISION HISTORY:
  26. * ================
  27. * Version 0.1 April 26, 2002 TJL
  28. * Version 0.2 01/08/2003 TJL Moved outside the 3c515.c driver file
  29. * Version 0.3 Sept 23, 2003 timlegge Change delay to currticks
  30. *
  31. *
  32. * Generalised into an ISAPnP bus that can be used by more than just
  33. * the 3c515 by Michael Brown <mbrown@fensystems.co.uk>
  34. *
  35. ***************************************************************************/
  36. /** @file
  37. *
  38. * ISAPnP bus support
  39. *
  40. * Etherboot orignally gained ISAPnP support in a very limited way for
  41. * the 3c515 NIC. The current implementation is almost a complete
  42. * rewrite based on the ISAPnP specification, with passing reference
  43. * to the Linux ISAPnP code.
  44. *
  45. * There can be only one ISAPnP bus in a system. Once the read port
  46. * is known and all cards have been allocated CSNs, there's nothing to
  47. * be gained by re-scanning for cards.
  48. *
  49. * External code (e.g. the ISAPnP ROM prefix) may already know the
  50. * read port address, in which case it can store it in
  51. * #isapnp_read_port. Note that setting the read port address in this
  52. * way will prevent further isolation from taking place; you should
  53. * set the read port address only if you know that devices have
  54. * already been allocated CSNs.
  55. *
  56. */
  57. FILE_LICENCE ( GPL2_OR_LATER );
  58. #include <stdint.h>
  59. #include <stdlib.h>
  60. #include <string.h>
  61. #include <stdio.h>
  62. #include <errno.h>
  63. #include <ipxe/io.h>
  64. #include <unistd.h>
  65. #include <ipxe/isapnp.h>
  66. /**
  67. * ISAPnP Read Port address.
  68. *
  69. * ROM prefix may be able to set this address, which is why this is
  70. * non-static.
  71. */
  72. uint16_t isapnp_read_port;
  73. static void isapnpbus_remove ( struct root_device *rootdev );
  74. /*
  75. * ISAPnP utility functions
  76. *
  77. */
  78. #define ISAPNP_CARD_ID_FMT "ID %04x:%04x (\"%s\") serial %x"
  79. #define ISAPNP_CARD_ID_DATA(identifier) \
  80. (identifier)->vendor_id, (identifier)->prod_id, \
  81. isa_id_string ( (identifier)->vendor_id, (identifier)->prod_id ), \
  82. (identifier)->serial
  83. #define ISAPNP_DEV_ID_FMT "ID %04x:%04x (\"%s\")"
  84. #define ISAPNP_DEV_ID_DATA(isapnp) \
  85. (isapnp)->vendor_id, (isapnp)->prod_id, \
  86. isa_id_string ( (isapnp)->vendor_id, (isapnp)->prod_id )
  87. static inline void isapnp_write_address ( unsigned int address ) {
  88. outb ( address, ISAPNP_ADDRESS );
  89. }
  90. static inline void isapnp_write_data ( unsigned int data ) {
  91. outb ( data, ISAPNP_WRITE_DATA );
  92. }
  93. static inline unsigned int isapnp_read_data ( void ) {
  94. return inb ( isapnp_read_port );
  95. }
  96. static inline void isapnp_write_byte ( unsigned int address,
  97. unsigned int value ) {
  98. isapnp_write_address ( address );
  99. isapnp_write_data ( value );
  100. }
  101. static inline unsigned int isapnp_read_byte ( unsigned int address ) {
  102. isapnp_write_address ( address );
  103. return isapnp_read_data ();
  104. }
  105. static inline unsigned int isapnp_read_word ( unsigned int address ) {
  106. /* Yes, they're in big-endian order */
  107. return ( ( isapnp_read_byte ( address ) << 8 )
  108. | isapnp_read_byte ( address + 1 ) );
  109. }
  110. /** Inform cards of a new read port address */
  111. static inline void isapnp_set_read_port ( void ) {
  112. isapnp_write_byte ( ISAPNP_READPORT, ( isapnp_read_port >> 2 ) );
  113. }
  114. /**
  115. * Enter the Isolation state.
  116. *
  117. * Only cards currently in the Sleep state will respond to this
  118. * command.
  119. */
  120. static inline void isapnp_serialisolation ( void ) {
  121. isapnp_write_address ( ISAPNP_SERIALISOLATION );
  122. }
  123. /**
  124. * Enter the Wait for Key state.
  125. *
  126. * All cards will respond to this command, regardless of their current
  127. * state.
  128. */
  129. static inline void isapnp_wait_for_key ( void ) {
  130. isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_WAIT_FOR_KEY );
  131. }
  132. /**
  133. * Reset (i.e. remove) Card Select Number.
  134. *
  135. * Only cards currently in the Sleep state will respond to this
  136. * command.
  137. */
  138. static inline void isapnp_reset_csn ( void ) {
  139. isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_RESET_CSN );
  140. }
  141. /**
  142. * Place a specified card into the Config state.
  143. *
  144. * @v csn Card Select Number
  145. * @ret None -
  146. * @err None -
  147. *
  148. * Only cards currently in the Sleep, Isolation, or Config states will
  149. * respond to this command. The card that has the specified CSN will
  150. * enter the Config state, all other cards will enter the Sleep state.
  151. */
  152. static inline void isapnp_wake ( uint8_t csn ) {
  153. isapnp_write_byte ( ISAPNP_WAKE, csn );
  154. }
  155. static inline unsigned int isapnp_read_resourcedata ( void ) {
  156. return isapnp_read_byte ( ISAPNP_RESOURCEDATA );
  157. }
  158. static inline unsigned int isapnp_read_status ( void ) {
  159. return isapnp_read_byte ( ISAPNP_STATUS );
  160. }
  161. /**
  162. * Assign a Card Select Number to a card, and enter the Config state.
  163. *
  164. * @v csn Card Select Number
  165. *
  166. * Only cards in the Isolation state will respond to this command.
  167. * The isolation protocol is designed so that only one card will
  168. * remain in the Isolation state by the time the isolation protocol
  169. * completes.
  170. */
  171. static inline void isapnp_write_csn ( unsigned int csn ) {
  172. isapnp_write_byte ( ISAPNP_CARDSELECTNUMBER, csn );
  173. }
  174. static inline void isapnp_logicaldevice ( unsigned int logdev ) {
  175. isapnp_write_byte ( ISAPNP_LOGICALDEVICENUMBER, logdev );
  176. }
  177. static inline void isapnp_activate ( unsigned int logdev ) {
  178. isapnp_logicaldevice ( logdev );
  179. isapnp_write_byte ( ISAPNP_ACTIVATE, 1 );
  180. }
  181. static inline void isapnp_deactivate ( unsigned int logdev ) {
  182. isapnp_logicaldevice ( logdev );
  183. isapnp_write_byte ( ISAPNP_ACTIVATE, 0 );
  184. }
  185. static inline unsigned int isapnp_read_iobase ( unsigned int index ) {
  186. return isapnp_read_word ( ISAPNP_IOBASE ( index ) );
  187. }
  188. static inline unsigned int isapnp_read_irqno ( unsigned int index ) {
  189. return isapnp_read_byte ( ISAPNP_IRQNO ( index ) );
  190. }
  191. static void isapnp_delay ( void ) {
  192. udelay ( 1000 );
  193. }
  194. /**
  195. * Linear feedback shift register.
  196. *
  197. * @v lfsr Current value of the LFSR
  198. * @v input_bit Current input bit to the LFSR
  199. * @ret lfsr Next value of the LFSR
  200. *
  201. * This routine implements the linear feedback shift register as
  202. * described in Appendix B of the PnP ISA spec. The hardware
  203. * implementation uses eight D-type latches and two XOR gates. I
  204. * think this is probably the smallest possible implementation in
  205. * software. Six instructions when input_bit is a constant 0 (for
  206. * isapnp_send_key). :)
  207. */
  208. static inline unsigned int isapnp_lfsr_next ( unsigned int lfsr,
  209. unsigned int input_bit ) {
  210. register uint8_t lfsr_next;
  211. lfsr_next = lfsr >> 1;
  212. lfsr_next |= ( ( ( lfsr ^ lfsr_next ) ^ input_bit ) ) << 7;
  213. return lfsr_next;
  214. }
  215. /**
  216. * Send the ISAPnP initiation key.
  217. *
  218. * Sending the key causes all ISAPnP cards that are currently in the
  219. * Wait for Key state to transition into the Sleep state.
  220. */
  221. static void isapnp_send_key ( void ) {
  222. unsigned int i;
  223. unsigned int lfsr;
  224. isapnp_delay();
  225. isapnp_write_address ( 0x00 );
  226. isapnp_write_address ( 0x00 );
  227. lfsr = ISAPNP_LFSR_SEED;
  228. for ( i = 0 ; i < 32 ; i++ ) {
  229. isapnp_write_address ( lfsr );
  230. lfsr = isapnp_lfsr_next ( lfsr, 0 );
  231. }
  232. }
  233. /**
  234. * Compute ISAPnP identifier checksum
  235. *
  236. * @v identifier ISAPnP identifier
  237. * @ret checksum Expected checksum value
  238. */
  239. static unsigned int isapnp_checksum ( struct isapnp_identifier *identifier ) {
  240. unsigned int i, j;
  241. unsigned int lfsr;
  242. unsigned int byte;
  243. lfsr = ISAPNP_LFSR_SEED;
  244. for ( i = 0 ; i < 8 ; i++ ) {
  245. byte = * ( ( ( uint8_t * ) identifier ) + i );
  246. for ( j = 0 ; j < 8 ; j++ ) {
  247. lfsr = isapnp_lfsr_next ( lfsr, byte );
  248. byte >>= 1;
  249. }
  250. }
  251. return lfsr;
  252. }
  253. /*
  254. * Read a byte of resource data from the current location
  255. *
  256. * @ret byte Byte of resource data
  257. */
  258. static inline unsigned int isapnp_peek_byte ( void ) {
  259. unsigned int i;
  260. /* Wait for data to be ready */
  261. for ( i = 0 ; i < 20 ; i++ ) {
  262. if ( isapnp_read_status() & 0x01 ) {
  263. /* Byte ready - read it */
  264. return isapnp_read_resourcedata();
  265. }
  266. isapnp_delay();
  267. }
  268. /* Data never became ready - return 0xff */
  269. return 0xff;
  270. }
  271. /**
  272. * Read resource data.
  273. *
  274. * @v buf Buffer in which to store data, or NULL
  275. * @v bytes Number of bytes to read
  276. *
  277. * Resource data is read from the current location. If #buf is NULL,
  278. * the data is discarded.
  279. */
  280. static void isapnp_peek ( void *buf, size_t len ) {
  281. unsigned int i;
  282. unsigned int byte;
  283. for ( i = 0 ; i < len ; i++) {
  284. byte = isapnp_peek_byte();
  285. if ( buf )
  286. * ( ( uint8_t * ) buf + i ) = byte;
  287. }
  288. }
  289. /**
  290. * Find a tag within the resource data.
  291. *
  292. * @v wanted_tag The tag that we're looking for
  293. * @v buf Buffer in which to store the tag's contents
  294. * @v len Length of buffer
  295. * @ret rc Return status code
  296. *
  297. * Scan through the resource data until we find a particular tag, and
  298. * read its contents into a buffer.
  299. */
  300. static int isapnp_find_tag ( unsigned int wanted_tag, void *buf, size_t len ) {
  301. unsigned int tag;
  302. unsigned int tag_len;
  303. DBG2 ( "ISAPnP read tag" );
  304. do {
  305. tag = isapnp_peek_byte();
  306. if ( ISAPNP_IS_SMALL_TAG ( tag ) ) {
  307. tag_len = ISAPNP_SMALL_TAG_LEN ( tag );
  308. tag = ISAPNP_SMALL_TAG_NAME ( tag );
  309. } else {
  310. tag_len = ( isapnp_peek_byte() +
  311. ( isapnp_peek_byte() << 8 ) );
  312. tag = ISAPNP_LARGE_TAG_NAME ( tag );
  313. }
  314. DBG2 ( " %02x (%02x)", tag, tag_len );
  315. if ( tag == wanted_tag ) {
  316. if ( len > tag_len )
  317. len = tag_len;
  318. isapnp_peek ( buf, len );
  319. DBG2 ( "\n" );
  320. return 0;
  321. } else {
  322. isapnp_peek ( NULL, tag_len );
  323. }
  324. } while ( tag != ISAPNP_TAG_END );
  325. DBG2 ( "\n" );
  326. return -ENOENT;
  327. }
  328. /**
  329. * Find specified Logical Device ID tag
  330. *
  331. * @v logdev Logical device ID
  332. * @v logdevid Logical device ID structure to fill in
  333. * @ret rc Return status code
  334. */
  335. static int isapnp_find_logdevid ( unsigned int logdev,
  336. struct isapnp_logdevid *logdevid ) {
  337. unsigned int i;
  338. int rc;
  339. for ( i = 0 ; i <= logdev ; i++ ) {
  340. if ( ( rc = isapnp_find_tag ( ISAPNP_TAG_LOGDEVID, logdevid,
  341. sizeof ( *logdevid ) ) ) != 0 )
  342. return rc;
  343. }
  344. return 0;
  345. }
  346. /**
  347. * Try isolating ISAPnP cards at the current read port.
  348. *
  349. * @ret \>0 Number of ISAPnP cards found
  350. * @ret 0 There are no ISAPnP cards in the system
  351. * @ret \<0 A conflict was detected; try a new read port
  352. * @err None -
  353. *
  354. * The state diagram on page 18 (PDF page 24) of the PnP ISA spec
  355. * gives the best overview of what happens here.
  356. */
  357. static int isapnp_try_isolate ( void ) {
  358. struct isapnp_identifier identifier;
  359. unsigned int i, j;
  360. unsigned int seen_55aa, seen_life;
  361. unsigned int csn = 0;
  362. unsigned int data;
  363. unsigned int byte;
  364. DBG ( "ISAPnP attempting isolation at read port %04x\n",
  365. isapnp_read_port );
  366. /* Place all cards into the Sleep state, whatever state
  367. * they're currently in.
  368. */
  369. isapnp_wait_for_key();
  370. isapnp_send_key();
  371. /* Reset all assigned CSNs */
  372. isapnp_reset_csn();
  373. isapnp_delay();
  374. isapnp_delay();
  375. /* Place all cards into the Isolation state */
  376. isapnp_wait_for_key ();
  377. isapnp_send_key();
  378. isapnp_wake ( 0x00 );
  379. /* Set the read port */
  380. isapnp_set_read_port();
  381. isapnp_delay();
  382. while ( 1 ) {
  383. /* All cards that do not have assigned CSNs are
  384. * currently in the Isolation state, each time we go
  385. * through this loop.
  386. */
  387. /* Initiate serial isolation */
  388. isapnp_serialisolation();
  389. isapnp_delay();
  390. /* Read identifier serially via the ISAPnP read port. */
  391. memset ( &identifier, 0, sizeof ( identifier ) );
  392. seen_55aa = seen_life = 0;
  393. for ( i = 0 ; i < 9 ; i++ ) {
  394. byte = 0;
  395. for ( j = 0 ; j < 8 ; j++ ) {
  396. data = isapnp_read_data();
  397. isapnp_delay();
  398. data = ( ( data << 8 ) | isapnp_read_data() );
  399. isapnp_delay();
  400. byte >>= 1;
  401. if ( data != 0xffff ) {
  402. seen_life++;
  403. if ( data == 0x55aa ) {
  404. byte |= 0x80;
  405. seen_55aa++;
  406. }
  407. }
  408. }
  409. *( ( ( uint8_t * ) &identifier ) + i ) = byte;
  410. }
  411. /* If we didn't see any 55aa patterns, stop here */
  412. if ( ! seen_55aa ) {
  413. if ( csn ) {
  414. DBG ( "ISAPnP found no more cards\n" );
  415. } else {
  416. if ( seen_life ) {
  417. DBG ( "ISAPnP saw life but no cards, "
  418. "trying new read port\n" );
  419. csn = -1;
  420. } else {
  421. DBG ( "ISAPnP saw no signs of life, "
  422. "abandoning isolation\n" );
  423. }
  424. }
  425. break;
  426. }
  427. /* If the checksum was invalid stop here */
  428. if ( identifier.checksum != isapnp_checksum ( &identifier) ) {
  429. DBG ( "ISAPnP found malformed card "
  430. ISAPNP_CARD_ID_FMT "\n with checksum %02x "
  431. "(should be %02x), trying new read port\n",
  432. ISAPNP_CARD_ID_DATA ( &identifier ),
  433. identifier.checksum,
  434. isapnp_checksum ( &identifier) );
  435. csn = -1;
  436. break;
  437. }
  438. /* Give the device a CSN */
  439. csn++;
  440. DBG ( "ISAPnP found card " ISAPNP_CARD_ID_FMT
  441. ", assigning CSN %02x\n",
  442. ISAPNP_CARD_ID_DATA ( &identifier ), csn );
  443. isapnp_write_csn ( csn );
  444. isapnp_delay();
  445. /* Send this card back to Sleep and force all cards
  446. * without a CSN into Isolation state
  447. */
  448. isapnp_wake ( 0x00 );
  449. isapnp_delay();
  450. }
  451. /* Place all cards in Wait for Key state */
  452. isapnp_wait_for_key();
  453. /* Return number of cards found */
  454. if ( csn > 0 ) {
  455. DBG ( "ISAPnP found %d cards at read port %04x\n",
  456. csn, isapnp_read_port );
  457. }
  458. return csn;
  459. }
  460. /**
  461. * Find a valid read port and isolate all ISAPnP cards.
  462. *
  463. */
  464. static void isapnp_isolate ( void ) {
  465. for ( isapnp_read_port = ISAPNP_READ_PORT_START ;
  466. isapnp_read_port <= ISAPNP_READ_PORT_MAX ;
  467. isapnp_read_port += ISAPNP_READ_PORT_STEP ) {
  468. /* Avoid problematic locations such as the NE2000
  469. * probe space
  470. */
  471. if ( ( isapnp_read_port >= 0x280 ) &&
  472. ( isapnp_read_port <= 0x380 ) )
  473. continue;
  474. /* If we detect any ISAPnP cards at this location, stop */
  475. if ( isapnp_try_isolate() >= 0 )
  476. return;
  477. }
  478. }
  479. /**
  480. * Activate or deactivate an ISAPnP device.
  481. *
  482. * @v isapnp ISAPnP device
  483. * @v activation True to enable, False to disable the device
  484. * @ret None -
  485. * @err None -
  486. *
  487. * This routine simply activates the device in its current
  488. * configuration, or deactivates the device. It does not attempt any
  489. * kind of resource arbitration.
  490. *
  491. */
  492. void isapnp_device_activation ( struct isapnp_device *isapnp,
  493. int activation ) {
  494. /* Wake the card and select the logical device */
  495. isapnp_wait_for_key ();
  496. isapnp_send_key ();
  497. isapnp_wake ( isapnp->csn );
  498. isapnp_logicaldevice ( isapnp->logdev );
  499. /* Activate/deactivate the logical device */
  500. isapnp_activate ( activation );
  501. isapnp_delay();
  502. /* Return all cards to Wait for Key state */
  503. isapnp_wait_for_key ();
  504. DBG ( "ISAPnP %s device %02x:%02x\n",
  505. ( activation ? "activated" : "deactivated" ),
  506. isapnp->csn, isapnp->logdev );
  507. }
  508. /**
  509. * Probe an ISAPnP device
  510. *
  511. * @v isapnp ISAPnP device
  512. * @ret rc Return status code
  513. *
  514. * Searches for a driver for the ISAPnP device. If a driver is found,
  515. * its probe() routine is called.
  516. */
  517. static int isapnp_probe ( struct isapnp_device *isapnp ) {
  518. struct isapnp_driver *driver;
  519. struct isapnp_device_id *id;
  520. unsigned int i;
  521. int rc;
  522. DBG ( "Adding ISAPnP device %02x:%02x (%04x:%04x (\"%s\") "
  523. "io %x irq %d)\n", isapnp->csn, isapnp->logdev,
  524. isapnp->vendor_id, isapnp->prod_id,
  525. isa_id_string ( isapnp->vendor_id, isapnp->prod_id ),
  526. isapnp->ioaddr, isapnp->irqno );
  527. for_each_table_entry ( driver, ISAPNP_DRIVERS ) {
  528. for ( i = 0 ; i < driver->id_count ; i++ ) {
  529. id = &driver->ids[i];
  530. if ( id->vendor_id != isapnp->vendor_id )
  531. continue;
  532. if ( ISA_PROD_ID ( id->prod_id ) !=
  533. ISA_PROD_ID ( isapnp->prod_id ) )
  534. continue;
  535. isapnp->driver = driver;
  536. isapnp->dev.driver_name = id->name;
  537. DBG ( "...using driver %s\n", isapnp->dev.driver_name );
  538. if ( ( rc = driver->probe ( isapnp, id ) ) != 0 ) {
  539. DBG ( "......probe failed\n" );
  540. continue;
  541. }
  542. return 0;
  543. }
  544. }
  545. DBG ( "...no driver found\n" );
  546. return -ENOTTY;
  547. }
  548. /**
  549. * Remove an ISAPnP device
  550. *
  551. * @v isapnp ISAPnP device
  552. */
  553. static void isapnp_remove ( struct isapnp_device *isapnp ) {
  554. isapnp->driver->remove ( isapnp );
  555. DBG ( "Removed ISAPnP device %02x:%02x\n",
  556. isapnp->csn, isapnp->logdev );
  557. }
  558. /**
  559. * Probe ISAPnP root bus
  560. *
  561. * @v rootdev ISAPnP bus root device
  562. *
  563. * Scans the ISAPnP bus for devices and registers all devices it can
  564. * find.
  565. */
  566. static int isapnpbus_probe ( struct root_device *rootdev ) {
  567. struct isapnp_device *isapnp = NULL;
  568. struct isapnp_identifier identifier;
  569. struct isapnp_logdevid logdevid;
  570. unsigned int csn;
  571. unsigned int logdev;
  572. int rc;
  573. /* Perform isolation if it hasn't yet been done */
  574. if ( ! isapnp_read_port )
  575. isapnp_isolate();
  576. for ( csn = 1 ; csn <= 0xff ; csn++ ) {
  577. for ( logdev = 0 ; logdev <= 0xff ; logdev++ ) {
  578. /* Allocate struct isapnp_device */
  579. if ( ! isapnp )
  580. isapnp = malloc ( sizeof ( *isapnp ) );
  581. if ( ! isapnp ) {
  582. rc = -ENOMEM;
  583. goto err;
  584. }
  585. memset ( isapnp, 0, sizeof ( *isapnp ) );
  586. isapnp->csn = csn;
  587. isapnp->logdev = logdev;
  588. /* Wake the card */
  589. isapnp_wait_for_key();
  590. isapnp_send_key();
  591. isapnp_wake ( csn );
  592. /* Read the card identifier */
  593. isapnp_peek ( &identifier, sizeof ( identifier ) );
  594. /* No card with this CSN; stop here */
  595. if ( identifier.vendor_id & 0x80 )
  596. goto done;
  597. /* Find the Logical Device ID tag */
  598. if ( ( rc = isapnp_find_logdevid ( logdev,
  599. &logdevid ) ) != 0){
  600. /* No more logical devices; go to next CSN */
  601. break;
  602. }
  603. /* Select the logical device */
  604. isapnp_logicaldevice ( logdev );
  605. /* Populate struct isapnp_device */
  606. isapnp->vendor_id = logdevid.vendor_id;
  607. isapnp->prod_id = logdevid.prod_id;
  608. isapnp->ioaddr = isapnp_read_iobase ( 0 );
  609. isapnp->irqno = isapnp_read_irqno ( 0 );
  610. /* Return all cards to Wait for Key state */
  611. isapnp_wait_for_key();
  612. /* Add to device hierarchy */
  613. snprintf ( isapnp->dev.name,
  614. sizeof ( isapnp->dev.name ),
  615. "ISAPnP%02x:%02x", csn, logdev );
  616. isapnp->dev.desc.bus_type = BUS_TYPE_ISAPNP;
  617. isapnp->dev.desc.vendor = isapnp->vendor_id;
  618. isapnp->dev.desc.device = isapnp->prod_id;
  619. isapnp->dev.desc.ioaddr = isapnp->ioaddr;
  620. isapnp->dev.desc.irq = isapnp->irqno;
  621. isapnp->dev.parent = &rootdev->dev;
  622. list_add ( &isapnp->dev.siblings,
  623. &rootdev->dev.children );
  624. INIT_LIST_HEAD ( &isapnp->dev.children );
  625. /* Look for a driver */
  626. if ( isapnp_probe ( isapnp ) == 0 ) {
  627. /* isapnpdev registered, we can drop our ref */
  628. isapnp = NULL;
  629. } else {
  630. /* Not registered; re-use struct */
  631. list_del ( &isapnp->dev.siblings );
  632. }
  633. }
  634. }
  635. done:
  636. free ( isapnp );
  637. return 0;
  638. err:
  639. free ( isapnp );
  640. isapnpbus_remove ( rootdev );
  641. return rc;
  642. }
  643. /**
  644. * Remove ISAPnP root bus
  645. *
  646. * @v rootdev ISAPnP bus root device
  647. */
  648. static void isapnpbus_remove ( struct root_device *rootdev ) {
  649. struct isapnp_device *isapnp;
  650. struct isapnp_device *tmp;
  651. list_for_each_entry_safe ( isapnp, tmp, &rootdev->dev.children,
  652. dev.siblings ) {
  653. isapnp_remove ( isapnp );
  654. list_del ( &isapnp->dev.siblings );
  655. free ( isapnp );
  656. }
  657. }
  658. /** ISAPnP bus root device driver */
  659. static struct root_driver isapnp_root_driver = {
  660. .probe = isapnpbus_probe,
  661. .remove = isapnpbus_remove,
  662. };
  663. /** ISAPnP bus root device */
  664. struct root_device isapnp_root_device __root_device = {
  665. .dev = { .name = "ISAPnP" },
  666. .driver = &isapnp_root_driver,
  667. };