Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

isapnp.c 20KB

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