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.

cromutil.c 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /*
  2. * JLdL 21Jun04.
  3. *
  4. * cromutil.c
  5. *
  6. * Perform various control operations on the flash EEPROM of
  7. * _ the 3COM models 3C905C or 3C905CX network cards, in order
  8. * _ to write a boot program such as Etherboot into it.
  9. *
  10. * This program is meant for the Linux operating system only,
  11. * _ and only for the i386 architecture.
  12. *
  13. * The flash EEPROM usually used in these cards is the AT49BV512
  14. * _ chip, which has 512 Kbit (64 KByte). Another possible chip,
  15. * _ which is equivalent to this one, is the SST39VF512.
  16. *
  17. * Added alternative read128 and prog128 commands for cards with
  18. * _ the SST29EE020 fast page-write (super-)flash EEPROM, which
  19. * _ has 2 Mbit (256 KByte), and which has to be programmed in
  20. * _ a 128-byte page mode. NOTE: it seems that the card can
  21. * _ address only the first half of the memory in this chip,
  22. * _ so only 128 Kbytes are actually available for use.
  23. *
  24. * Added a few informative messages and a detailed help message.
  25. *
  26. */
  27. #ifndef __i386__
  28. # error "This program can't compile or run on non-Intel computers"
  29. #else
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <unistd.h>
  33. #include <sys/io.h>
  34. #include <string.h>
  35. int main(int argc, char **argv)
  36. {
  37. /* Counters. */
  38. unsigned int i, j, n;
  39. /* For ROM chips larger than 64 KB, a long integer
  40. _ is needed for the global byte counter. */
  41. unsigned long k;
  42. /* The I/O address of the card. */
  43. unsigned int ioaddr;
  44. /* Storage for a byte. */
  45. unsigned char b;
  46. /* Storage for a page. */
  47. unsigned char buf[128];
  48. /* Initialize a few things to avoid compiler warnings. */
  49. i=0; j=0; n=0; k=0;
  50. /* Verify the command-line parameters; write
  51. _ out an usage message if needed. */
  52. if (argc != 3) {
  53. /* Exactly 2 command line parameters are needed. */
  54. printf("Usage: ./cromutil ioaddr command [(>|<) file]\n");
  55. printf(" (try './cromutil 0x0000 help' for details)\n");
  56. exit(-1);
  57. }
  58. /* Set the UID to root if possible. */
  59. setuid(0);
  60. /* Get port-access permissions for in{blw}/out{blw}. */
  61. if (iopl(3)) {
  62. perror("iopl()");
  63. exit(1);
  64. }
  65. /* Pass the I/O address of the card to a variable. */
  66. sscanf(argv[1],"%x",&ioaddr);
  67. /* Set the register window to 0. */
  68. outw(0x800, ioaddr+0xe);
  69. /*
  70. * Execute the requested command.
  71. *
  72. * "id": get and write out the ID numbers.
  73. */
  74. if (strcmp(argv[2], "id") == 0) {
  75. /* Software ID entry command sequence. */
  76. outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
  77. outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
  78. outl(0x5555, ioaddr+0x4); outb(0x90, ioaddr+0x8);
  79. /* A 10 ms delay is needed. */
  80. usleep(10000);
  81. /* Get the manufacturer id. */
  82. outl(0x0000, ioaddr+0x4);
  83. printf("Manufacturer ID - %02x\n", inb(ioaddr+0x8));
  84. /* Get the device id. */
  85. outl(0x0001, ioaddr+0x4);
  86. printf("Device ID - %02x\n", inb(ioaddr+0x8));
  87. /* Software ID exit command sequence. */
  88. outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
  89. outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
  90. outl(0x5555, ioaddr+0x4); outb(0xf0, ioaddr+0x8);
  91. }
  92. /*
  93. * "read": read data from the 512 Kbit ROM.
  94. */
  95. else if (strcmp(argv[2], "read") == 0) {
  96. /* Loop over the whole ROM. */
  97. for (k = 0; k < 65536; k++) {
  98. outl(k, ioaddr+0x4);
  99. b = inb(ioaddr+0x8);
  100. write(1, &b, 1);
  101. }
  102. /* Write out an informative message. */
  103. perror("Read 65536 bytes from ROM");
  104. }
  105. /*
  106. * "read128": this alternative is for the 2 Mbit ROM.
  107. */
  108. else if (strcmp(argv[2], "read128") == 0) {
  109. /* Loop over the accessible part of the ROM. */
  110. for (k = 0; k < 131072; k++) {
  111. outl(k, ioaddr+0x4);
  112. b = inb(ioaddr+0x8);
  113. write(1, &b, 1);
  114. }
  115. /* Write out an informative message. */
  116. perror("Read 131072 bytes from ROM");
  117. }
  118. /*
  119. * "erase": erase the ROM contents.
  120. */
  121. else if (strcmp(argv[2], "erase") == 0) {
  122. /* Software chip-erase command sequence. */
  123. outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
  124. outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
  125. outl(0x5555, ioaddr+0x4); outb(0x80, ioaddr+0x8);
  126. outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
  127. outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
  128. outl(0x5555, ioaddr+0x4); outb(0x10, ioaddr+0x8);
  129. /* Wait a bit. */
  130. sleep(1);
  131. /* Write out an informative message. */
  132. printf("Bios ROM at %04x has been erased: Success\n", ioaddr);
  133. }
  134. /*
  135. * "prog": program the 512 Kbit ROM.
  136. */
  137. else if (strcmp(argv[2], "prog") == 0) {
  138. /* Loop over the bytes in pages, to
  139. _ allow for a progress report. */
  140. for (j = 0; j < 512; j++) {
  141. for (i = 0; i < 128; i++) {
  142. /* If this program is to run on a diskless node,
  143. _ must read in the byte _before_ changing the
  144. _ mode of the chip, or NFS may block. */
  145. n = read(0, &b, 1);
  146. /* At EOF exit the inner loop. */
  147. if (n == 0)
  148. break;
  149. if (n < 0) {
  150. perror("Input File Error");
  151. exit(-3);
  152. }
  153. /* Disable SDP temporarily for programming a byte. */
  154. outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
  155. outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
  156. outl(0x5555, ioaddr+0x4); outb(0xA0, ioaddr+0x8);
  157. /* Calculate the address of the byte. */
  158. k=i+128*j;
  159. /* Program this byte. */
  160. outl(k, ioaddr+0x4); outb(b, ioaddr+0x8);
  161. /* Wait for the programming of this byte to complete. */
  162. while (inb(ioaddr+0x8) != b)
  163. ;
  164. }
  165. /* At EOF exit the outer loop. */
  166. if (n == 0)
  167. break;
  168. /* Write out a progress report. */
  169. printf("."); fflush(NULL);
  170. }
  171. /* Write out an informative message. */
  172. printf("\nWrote %ld bytes to ROM: Success\n", k);
  173. }
  174. /*
  175. * "prog128": this alternative is for the 2 Mbit ROM.
  176. */
  177. else if (strcmp(argv[2], "prog128") == 0) {
  178. /* Loop over the accessible pages; the card can
  179. _ access only the first half of the chip. */
  180. for (j = 0; j < 1024; j++) {
  181. /* If this program is to run on a diskless node,
  182. _ must read in the page _before_ changing the
  183. _ mode of the chip, or NFS may block. */
  184. n = read(0, buf, 128);
  185. /* At EOF exit the loop. */
  186. if (n == 0)
  187. break;
  188. if (n < 0) {
  189. perror("Input File Error");
  190. exit(-3);
  191. }
  192. /* Disable SDP temporarily for programming a page. */
  193. outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
  194. outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
  195. outl(0x5555, ioaddr+0x4); outb(0xA0, ioaddr+0x8);
  196. /* Loop over the bytes in a page. */
  197. for (i = 0; i < n; i++) {
  198. /* Calculate the address of the byte. */
  199. k=i+128*j;
  200. /* Program this byte. */
  201. outl(k, ioaddr+0x4); outb(buf[i], ioaddr+0x8);
  202. }
  203. /* Wait for the programming of this page to complete. */
  204. while (inb(ioaddr+0x8) != buf[i-1])
  205. ;
  206. /* Write out a progress report. */
  207. printf("."); fflush(NULL);
  208. }
  209. /* Write out an informative message. */
  210. printf("\nWrote %d pages to ROM: Success\n", j);
  211. }
  212. /*
  213. * "help": write out a detailed help message.
  214. */
  215. else if (strcmp(argv[2], "help") == 0) {
  216. printf("This utility can be used to write data, usually boot loaders\n");
  217. printf(" such as Etherboot, to the flash EEPROM of the 3COM models\n");
  218. printf(" 3C905C and 3C905CX network cards. You use it like this:\n");
  219. printf(" ./cromutil ioaddr command [(>|<) file]\n");
  220. printf("Here ioaddr is the hexadecimal I/O address of the card, such\n");
  221. printf(" as 0xA123, in some cases you need input/output redirection\n");
  222. printf(" from/to a file, and the command can be one of these:\n");
  223. printf(" id get the ID numbers of the card;\n");
  224. printf(" read > file read the contents of the ROM into a file;\n");
  225. printf(" read128 > file read the contents of the ROM into a file;\n");
  226. printf(" erase erase the whole ROM to the 1 state;\n");
  227. printf(" prog < file write the contents of a file into the ROM;\n");
  228. printf(" prog128 < file write the contents of a file into the ROM.\n");
  229. printf("You can get the I/O address of the card using the commands\n");
  230. printf(" 'lspci -v', 'cat /proc/pci', or 'dmesg | grep -i 3C905C'.\n");
  231. printf("The read and prog commands are to be used if the card has a\n");
  232. printf(" traditional 512 Kb (64 KB) flash EEPROM chip, such as:\n");
  233. printf(" | AT49BV512 | SST39VF512 |\n");
  234. printf("The read128 and prog128 versions are for cards with a 2 Mb\n");
  235. printf(" (128 KB usable) page-write flash EEPROM chip, such as:\n");
  236. printf(" | SST29EE020 |\n");
  237. }
  238. /*
  239. * Write out the usage message if an unknown command is used.
  240. */
  241. else {
  242. printf("Usage: ./cromutil ioaddr command [(>|<) file]\n");
  243. printf("(try './cromutil 0x0000 help' for details)\n");
  244. exit(-1);
  245. }
  246. return 0;
  247. }
  248. #endif /* __i386__ */