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 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  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. #include "etherboot.h"
  36. #include "timer.h"
  37. #include "isapnp.h"
  38. /*
  39. * We can have only one ISAPnP bus in a system. Once the read port is
  40. * known and all cards have been allocated CSNs, there's nothing to be
  41. * gained by re-scanning for cards.
  42. *
  43. * However, we shouldn't make scanning the ISAPnP bus an INIT_FN(),
  44. * because even ISAPnP probing can still screw up other devices on the
  45. * ISA bus. We therefore probe only when we are first asked to find
  46. * an ISAPnP device.
  47. *
  48. */
  49. static uint16_t isapnp_read_port;
  50. static uint16_t isapnp_max_csn;
  51. static const char initdata[] = INITDATA;
  52. /*
  53. * ISAPnP utility functions
  54. *
  55. */
  56. static inline void isapnp_write_address ( uint8_t address ) {
  57. outb ( address, ISAPNP_ADDRESS );
  58. }
  59. static inline void isapnp_write_data ( uint8_t data ) {
  60. outb ( data, ISAPNP_WRITE_DATA );
  61. }
  62. static inline void isapnp_write_byte ( uint8_t address, uint8_t value ) {
  63. isapnp_write_address ( address );
  64. isapnp_write_data ( value );
  65. }
  66. static inline uint8_t isapnp_read_data ( void ) {
  67. return inb ( isapnp_read_port );
  68. }
  69. static inline void isapnp_set_read_port ( void ) {
  70. isapnp_write_byte ( ISAPNP_READPORT, isapnp_read_port >> 2 );
  71. }
  72. static inline void isapnp_serialisolation ( void ) {
  73. isapnp_write_address ( ISAPNP_SERIALISOLATION );
  74. }
  75. static inline void isapnp_wait_for_key ( void ) {
  76. isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_WAIT_FOR_KEY );
  77. }
  78. static inline void isapnp_reset_csn ( void ) {
  79. isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_RESET_CSN );
  80. }
  81. static inline void isapnp_wake ( uint8_t csn ) {
  82. isapnp_write_byte ( ISAPNP_WAKE, csn );
  83. }
  84. static inline void isapnp_write_csn ( uint8_t csn ) {
  85. isapnp_write_byte ( ISAPNP_CARDSELECTNUMBER, csn );
  86. }
  87. /*
  88. * The linear feedback shift register as described in Appendix B of
  89. * the PnP ISA spec. The hardware implementation uses eight D-type
  90. * latches and two XOR gates. I think this is probably the smallest
  91. * possible implementation in software. :)
  92. *
  93. */
  94. static inline uint8_t isapnp_lfsr_next ( uint8_t lfsr, int input_bit ) {
  95. register uint8_t lfsr_next;
  96. lfsr_next = lfsr >> 1;
  97. lfsr_next |= ( ( ( lfsr ^ lfsr_next ) ^ input_bit ) ) << 7;
  98. return lfsr_next;
  99. }
  100. /*
  101. * Send the ISAPnP initiation key
  102. *
  103. */
  104. static void isapnp_send_key ( void ) {
  105. unsigned int i;
  106. uint8_t lfsr;
  107. udelay ( 1000 );
  108. isapnp_write_address ( 0x00 );
  109. isapnp_write_address ( 0x00 );
  110. lfsr = ISAPNP_LFSR_SEED;
  111. for ( i = 0 ; i < 32 ; i-- ) {
  112. isapnp_write_address ( lfsr );
  113. lfsr = isapnp_lfsr_next ( lfsr, 0 );
  114. }
  115. }
  116. /*
  117. * Compute ISAPnP identifier checksum
  118. *
  119. */
  120. static uint8_t isapnp_checksum ( union isapnp_identifier *identifier ) {
  121. int i, j;
  122. uint8_t lfsr;
  123. uint8_t byte;
  124. lfsr = ISAPNP_LFSR_SEED;
  125. for ( i = 0 ; i < 8 ; i++ ) {
  126. byte = identifier->bytes[i];
  127. for ( j = 0 ; j < 8 ; j++ ) {
  128. lfsr = isapnp_lfsr_next ( lfsr, byte );
  129. byte >>= 1;
  130. }
  131. }
  132. return lfsr;
  133. }
  134. /*
  135. * Try isolating ISAPnP cards at the current read port. Return the
  136. * number of ISAPnP cards found.
  137. *
  138. * The state diagram on page 18 (PDF page 24) of the PnP ISA spec
  139. * gives the best overview of what happens here.
  140. *
  141. */
  142. static int isapnp_try_isolate ( void ) {
  143. union isapnp_identifier identifier;
  144. int i, j, seen55aa;
  145. uint16_t data;
  146. uint8_t byte;
  147. DBG ( "ISAPnP attempting isolation at read port %hx\n",
  148. isapnp_read_port );
  149. /* Place all cards into the Sleep state, whatever state
  150. * they're currently in.
  151. */
  152. isapnp_wait_for_key ();
  153. isapnp_send_key ();
  154. /* Reset all assigned CSNs */
  155. isapnp_reset_csn ();
  156. isapnp_max_csn = 0;
  157. udelay ( 2000 );
  158. /* Place all cards into the Isolation state */
  159. isapnp_wait_for_key ();
  160. isapnp_send_key ();
  161. isapnp_wake ( 0x00 );
  162. /* Set the read port */
  163. isapnp_set_read_port ();
  164. udelay ( 1000 );
  165. while ( 1 ) {
  166. /* All cards that do not have assigned CSNs are
  167. * currently in the Isolation state, each time we go
  168. * through this loop.
  169. */
  170. /* Initiate serial isolation */
  171. isapnp_serialisolation ();
  172. udelay ( 1000 );
  173. /* Read identifier serially via the ISAPnP read port. */
  174. memset ( &identifier, 0, sizeof ( identifier ) );
  175. seen55aa = 0;
  176. for ( i = 0 ; i < 9 ; i++ ) {
  177. byte = 0;
  178. for ( j = 0 ; j < 8 ; j++ ) {
  179. data = isapnp_read_data ();
  180. udelay ( 1000 );
  181. data = ( data << 8 ) | isapnp_read_data ();
  182. udelay ( 1000 );
  183. if ( data == 0x55aa ) {
  184. byte |= 1;
  185. }
  186. byte <<= 1;
  187. }
  188. identifier.bytes[i] = byte;
  189. if ( byte ) {
  190. seen55aa = 1;
  191. }
  192. }
  193. /* If we didn't see a valid ISAPnP device, stop here */
  194. if ( ( ! seen55aa ) ||
  195. ( identifier.checksum != isapnp_checksum (&identifier) ) )
  196. break;
  197. /* Give the device a CSN */
  198. isapnp_max_csn++;
  199. DBG ( "ISAPnP isolation found device "
  200. "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx "
  201. "(checksum %hhx), assigning CSN %hhx\n",
  202. identifier.bytes[0], identifier.bytes[1],
  203. identifier.bytes[2], identifier.bytes[3],
  204. identifier.bytes[4], identifier.bytes[5],
  205. identifier.bytes[6], identifier.bytes[7],
  206. identifier.checksum, isapnp_max_csn );
  207. isapnp_write_csn ( isapnp_max_csn );
  208. udelay ( 1000 );
  209. /* Send this card back to Sleep and force all cards
  210. * without a CSN into Isolation state
  211. */
  212. isapnp_wake ( 0x00 );
  213. udelay ( 1000 );
  214. }
  215. /* Place all cards in Wait for Key state */
  216. isapnp_wait_for_key ();
  217. /* Return number of cards found */
  218. DBG ( "ISAPnP found %d devices at read port %hx\n", isapnp_read_port );
  219. return isapnp_max_csn;
  220. }
  221. /*
  222. * Isolate all ISAPnP cards, locating a valid read port in the process.
  223. *
  224. */
  225. static void isapnp_isolate ( void ) {
  226. for ( isapnp_read_port = ISAPNP_READ_PORT_MIN ;
  227. isapnp_read_port <= ISAPNP_READ_PORT_MAX ;
  228. isapnp_read_port += ISAPNP_READ_PORT_STEP ) {
  229. /* Avoid problematic locations such as the NE2000
  230. * probe space
  231. */
  232. if ( ( isapnp_read_port >= 0x280 ) &&
  233. ( isapnp_read_port <= 0x380 ) )
  234. continue;
  235. /* If we detect any ISAPnP cards at this location, stop */
  236. if ( isapnp_try_isolate () )
  237. return;
  238. }
  239. }
  240. /*
  241. * Build device list for all present ISA PnP devices.
  242. */
  243. static int isapnp_build_device_list(void)
  244. {
  245. int csn, device, vendor, serial;
  246. unsigned char header[9], checksum;
  247. for (csn = 1; csn <= 10; csn++) {
  248. Wake(csn);
  249. isapnp_peek(header, 9);
  250. checksum = isapnp_checksum(header);
  251. #ifdef EDEBUG
  252. printf
  253. ("vendor: 0x%hX:0x%hX:0x%hX:0x%hX:0x%hX:0x%hX:0x%hX:0x%hX:0x%hX\n",
  254. header[0], header[1], header[2], header[3], header[4],
  255. header[5], header[6], header[7], header[8]);
  256. printf("checksum = 0xhX\n", checksum);
  257. #endif
  258. /* Don't be strict on the checksum, here !
  259. e.g. 'SCM SwapBox Plug and Play' has header[8]==0 (should be: b7) */
  260. if (header[8] == 0);
  261. else if (checksum == 0x00 || checksum != header[8]) /* not valid CSN */
  262. continue;
  263. vendor = (header[1] << 8) | header[0];
  264. device = (header[3] << 8) | header[2];
  265. serial =
  266. (header[7] << 24) | (header[6] << 16) | (header[5] <<
  267. 8) |
  268. header[4];
  269. if (vendor == 0x6D50)
  270. if (device == 0x5150) {
  271. printf
  272. ("\nFound 3Com 3c515 PNP Card!\n Vendor ID: 0x%hX, Device ID: 0x%hX, Serial Num: 0x%hX\n",
  273. vendor, device, serial);
  274. pnp_card_csn = csn;
  275. }
  276. isapnp_checksum_value = 0x00;
  277. }
  278. return 0;
  279. }
  280. int Config(int csn)
  281. {
  282. #define TIMEOUT_PNP 100
  283. unsigned char id[IDENT_LEN];
  284. int i, x;
  285. Wake(csn);
  286. udelay(1000);
  287. for (i = 0; i < IDENT_LEN; i++) {
  288. for (x = 1; x < TIMEOUT_PNP; x++) {
  289. if (STATUS & 1)
  290. break;
  291. udelay(1000);
  292. }
  293. id[i] = RESOURCEDATA;
  294. #ifdef EDEBUG
  295. printf(" 0x%hX ", id[i]);
  296. #endif
  297. }
  298. #ifdef EDEBUG
  299. printf("Got The status bit\n");
  300. #endif
  301. /*Set Logical Device Register active */
  302. LOGICALDEVICENUMBER;
  303. /* Specify the first logical device */
  304. WRITE_DATA(0);
  305. /* Apparently just activating the card is enough
  306. for Etherboot to detect it. Why bother with the
  307. following code. Left in place in case it is
  308. later required */
  309. /*==========================================*/
  310. /* set DMA */
  311. /* ADDRESS(0x74 + 0);
  312. WRITE_DATA(7); */
  313. /*Set IRQ */
  314. /* udelay(1000);
  315. ADDRESS(0x70 + (0 << 1));
  316. WRITE_DATA(9);
  317. udelay(1000); */
  318. /*=============================================*/
  319. /*Activate */
  320. ACTIVATE;
  321. WRITE_DATA(1);
  322. udelay(250);
  323. /* Ask for access to the Wait for Key command - ConfigControl register */
  324. CONFIGCONTROL;
  325. /* Write the Wait for Key Command to the ConfigControl Register */
  326. WRITE_DATA(CONFIG_WAIT_FOR_KEY);
  327. /* As per doc. Two Write cycles of 0x00 required befor the Initialization key is sent */
  328. ADDRESS(0);
  329. ADDRESS(0);
  330. return 1;
  331. }
  332. static void isapnp_peek(unsigned char *data, int bytes)
  333. {
  334. int i, j;
  335. unsigned char d = 0;
  336. for (i = 1; i <= bytes; i++) {
  337. for (j = 0; j < 20; j++) {
  338. d = STATUS;
  339. if (d & 1)
  340. break;
  341. udelay(100);
  342. }
  343. if (!(d & 1)) {
  344. if (data != NULL)
  345. *data++ = 0xff;
  346. continue;
  347. }
  348. d = RESOURCEDATA; /* PRESDI */
  349. isapnp_checksum_value += d;
  350. if (data != NULL)
  351. *data++ = d;
  352. }
  353. }
  354. /*
  355. * Ensure that there is sufficient space in the shared dev_bus
  356. * structure for a struct isapnp_device.
  357. *
  358. */
  359. DEV_BUS( struct isapnp_device, isapnp_dev );
  360. static char isapnp_magic[0]; /* guaranteed unique symbol */
  361. /*
  362. * Fill in parameters for an ISAPnP device based on CSN
  363. *
  364. * Return 1 if device present, 0 otherwise
  365. *
  366. */
  367. static int fill_isapnp_device ( struct isapnp_device *isapnp ) {
  368. /*
  369. * Ensure that all ISAPnP cards have CSNs allocated to them,
  370. * if we haven't already done so.
  371. *
  372. */
  373. if ( ! isapnp_read_port ) {
  374. isapnp_isolate();
  375. }
  376. /* wake csn, read config, send card to sleep */
  377. DBG ( "ISAPnP found CSN %hhx ID %hx:%hx (\"%s\")\n",
  378. isapnp->csn, isapnp->vendor_id, isapnp->prod_id,
  379. isa_id_string ( isapnp->vendor_id, isapnp->prod_id ) );
  380. return 0;
  381. }
  382. /*
  383. * Find an ISAPnP device matching the specified driver
  384. *
  385. */
  386. int find_isapnp_device ( struct isapnp_device *isapnp,
  387. struct isapnp_driver *driver ) {
  388. unsigned int i;
  389. /* Initialise struct isapnp if it's the first time it's been used. */
  390. if ( isapnp->magic != isapnp_magic ) {
  391. memset ( isapnp, 0, sizeof ( *isapnp ) );
  392. isapnp->magic = isapnp_magic;
  393. isapnp->csn = 1;
  394. }
  395. /* Iterate through all possible ISAPNP CSNs, starting where we
  396. * left off.
  397. */
  398. for ( ; isapnp->csn <= isapnp_max_csn ; isapnp->csn++ ) {
  399. /* If we've already used this device, skip it */
  400. if ( isapnp->already_tried ) {
  401. isapnp->already_tried = 0;
  402. continue;
  403. }
  404. /* Fill in device parameters */
  405. if ( ! fill_isapnp_device ( isapnp ) ) {
  406. continue;
  407. }
  408. /* Compare against driver's ID list */
  409. for ( i = 0 ; i < driver->id_count ; i++ ) {
  410. struct isapnp_id *id = &driver->ids[i];
  411. if ( ( isapnp->vendor_id == id->vendor_id ) &&
  412. ( ISA_PROD_ID ( isapnp->prod_id ) ==
  413. ISA_PROD_ID ( id->prod_id ) ) ) {
  414. DBG ( "Device %s (driver %s) matches ID %s\n",
  415. id->name, driver->name,
  416. isa_id_string ( isapnp->vendor_id,
  417. isapnp->prod_id ) );
  418. isapnp->name = id->name;
  419. isapnp->already_tried = 1;
  420. return 1;
  421. }
  422. }
  423. }
  424. /* No device found */
  425. isapnp->csn = 1;
  426. return 0;
  427. }
  428. /*
  429. * Find the next ISAPNP device that can be used to boot using the
  430. * specified driver.
  431. *
  432. */
  433. int find_isapnp_boot_device ( struct dev *dev, struct isapnp_driver *driver ) {
  434. struct isapnp_device *isapnp = ( struct isapnp_device * ) dev->bus;
  435. if ( ! find_isapnp_device ( isapnp, driver ) )
  436. return 0;
  437. dev->name = isapnp->name;
  438. dev->devid.bus_type = ISA_BUS_TYPE;
  439. dev->devid.vendor_id = isapnp->vendor_id;
  440. dev->devid.device_id = isapnp->prod_id;
  441. return 1;
  442. }