pcmcia.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. #include <u.h>
  2. #include <libc.h>
  3. enum
  4. {
  5. Linktarget = 0x13,
  6. Funcid = 0x21,
  7. End = 0xff,
  8. };
  9. int fd;
  10. int pos;
  11. void tdevice(int, int);
  12. void tlonglnkmfc(int, int);
  13. void tfuncid(int, int);
  14. void tcfig(int, int);
  15. void tentry(int, int);
  16. void tvers1(int, int);
  17. void (*parse[256])(int, int) =
  18. {
  19. [1] tdevice,
  20. [6] tlonglnkmfc,
  21. [0x15] tvers1,
  22. [0x17] tdevice,
  23. [0x1A] tcfig,
  24. [0x1B] tentry,
  25. [Funcid] tfuncid,
  26. };
  27. int hex;
  28. void
  29. fatal(char *fmt, ...)
  30. {
  31. va_list arg;
  32. char buf[512];
  33. va_start(arg, fmt);
  34. vseprint(buf, buf+sizeof(buf), fmt, arg);
  35. va_end(arg);
  36. fprint(2, "pcmcia: %s\n", buf);
  37. exits(buf);
  38. }
  39. int
  40. readc(void *x)
  41. {
  42. int rv;
  43. seek(fd, 2*pos, 0);
  44. pos++;
  45. rv = read(fd, x, 1);
  46. if(hex)
  47. print("%2.2ux ", *(uchar*)x);
  48. return rv;
  49. }
  50. int
  51. tuple(int next, int expect)
  52. {
  53. uchar link;
  54. uchar type;
  55. pos = next;
  56. if(readc(&type) != 1)
  57. return -1;
  58. if(type == 0xff)
  59. return -1;
  60. print("type %.2uX\n", type & 0xff);
  61. if(expect && expect != type){
  62. print("expected %.2uX found %.2uX\n",
  63. expect, type);
  64. return -1;
  65. }
  66. if(readc(&link) != 1)
  67. return -1;
  68. if(parse[type])
  69. (*parse[type])(type, link);
  70. if(link == 0xff)
  71. next = -1;
  72. else
  73. next = next+2+link;
  74. return next;
  75. }
  76. void
  77. main(int argc, char *argv[])
  78. {
  79. char *file;
  80. int next;
  81. ARGBEGIN{
  82. case 'x':
  83. hex = 1;
  84. }ARGEND;
  85. if(argc == 0)
  86. file = "#y/pcm0attr";
  87. else
  88. file = argv[0];
  89. fd = open(file, OREAD);
  90. if(fd < 0)
  91. fatal("opening %s: %r", file);
  92. for(next = 0; next >= 0;)
  93. next = tuple(next, 0);
  94. }
  95. ulong speedtab[16] =
  96. {
  97. [1] 250,
  98. [2] 200,
  99. [3] 150,
  100. [4] 100,
  101. };
  102. ulong mantissa[16] =
  103. {
  104. [1] 10,
  105. [2] 12,
  106. [3] 13,
  107. [4] 15,
  108. [5] 20,
  109. [6] 25,
  110. [7] 30,
  111. [8] 35,
  112. [9] 40,
  113. [0xa] 45,
  114. [0xb] 50,
  115. [0xc] 55,
  116. [0xd] 60,
  117. [0xe] 70,
  118. [0xf] 80,
  119. };
  120. ulong exponent[8] =
  121. {
  122. [0] 1,
  123. [1] 10,
  124. [2] 100,
  125. [3] 1000,
  126. [4] 10000,
  127. [5] 100000,
  128. [6] 1000000,
  129. [7] 10000000,
  130. };
  131. char *typetab[256] =
  132. {
  133. [1] "Masked ROM",
  134. [2] "PROM",
  135. [3] "EPROM",
  136. [4] "EEPROM",
  137. [5] "FLASH",
  138. [6] "SRAM",
  139. [7] "DRAM",
  140. [0xD] "IO+MEM",
  141. };
  142. ulong
  143. getlong(int size)
  144. {
  145. uchar c;
  146. int i;
  147. ulong x;
  148. x = 0;
  149. for(i = 0; i < size; i++){
  150. if(readc(&c) != 1)
  151. break;
  152. x |= c<<(i*8);
  153. }
  154. return x;
  155. }
  156. void
  157. tdevice(int ttype, int len)
  158. {
  159. uchar id;
  160. uchar type;
  161. uchar speed, aespeed;
  162. uchar size;
  163. ulong bytes, ns;
  164. char *tname, *ttname;
  165. while(len > 0){
  166. if(readc(&id) != 1)
  167. return;
  168. len--;
  169. if(id == End)
  170. return;
  171. /* PRISM cards have a device tuple with id = size = 0. */
  172. if(id == 0x00){
  173. if(readc(&size) != 1)
  174. return;
  175. len--;
  176. continue;
  177. }
  178. speed = id & 0x7;
  179. if(speed == 0x7){
  180. if(readc(&speed) != 1)
  181. return;
  182. len--;
  183. if(speed & 0x80){
  184. if(readc(&aespeed) != 1)
  185. return;
  186. ns = 0;
  187. } else
  188. ns = (mantissa[(speed>>3)&0xf]*exponent[speed&7])/10;
  189. } else
  190. ns = speedtab[speed];
  191. type = id>>4;
  192. if(type == 0xE){
  193. if(readc(&type) != 1)
  194. return;
  195. len--;
  196. }
  197. tname = typetab[type];
  198. if(tname == 0)
  199. tname = "unknown";
  200. if(readc(&size) != 1)
  201. return;
  202. len--;
  203. bytes = ((size>>3)+1) * 512 * (1<<(2*(size&0x7)));
  204. if(ttype == 1)
  205. ttname = "device";
  206. else
  207. ttname = "attr device";
  208. print("%s %ld bytes of %ldns %s\n", ttname, bytes, ns, tname);
  209. }
  210. }
  211. void
  212. tlonglnkmfc(int, int)
  213. {
  214. int i, opos;
  215. uchar nfn, space, expect;
  216. int addr;
  217. readc(&nfn);
  218. for(i = 0; i < nfn; i++){
  219. readc(&space);
  220. addr = getlong(4);
  221. opos = pos;
  222. expect = Linktarget;
  223. while(addr > 0){
  224. addr = tuple(addr, expect);
  225. expect = 0;
  226. }
  227. pos = opos;
  228. }
  229. }
  230. static char *funcids[] = {
  231. "MULTI",
  232. "MEMORY",
  233. "SERIAL",
  234. "PARALLEL",
  235. "FIXED",
  236. "VIDEO",
  237. "NETWORK",
  238. "AIMS",
  239. "SCSI",
  240. };
  241. void
  242. tfuncid(int, int)
  243. {
  244. uchar func;
  245. readc(&func);
  246. print("Function %s\n",
  247. (func >= nelem(funcids))? "unknown function": funcids[func]);
  248. }
  249. void
  250. tvers1(int ttype, int len)
  251. {
  252. uchar c, major, minor;
  253. int i;
  254. char string[512];
  255. USED(ttype);
  256. if(readc(&major) != 1)
  257. return;
  258. len--;
  259. if(readc(&minor) != 1)
  260. return;
  261. len--;
  262. print("version %d.%d\n", major, minor);
  263. while(len > 0){
  264. for(i = 0; len > 0 && i < sizeof(string); i++){
  265. if(readc(&string[i]) != 1)
  266. return;
  267. len--;
  268. c = string[i];
  269. if(c == 0)
  270. break;
  271. if(c == 0xff){
  272. if(i != 0){
  273. string[i] = 0;
  274. print("\t%s<missing null>\n", string);
  275. }
  276. return;
  277. }
  278. }
  279. string[i] = 0;
  280. print("\t%s\n", string);
  281. }
  282. }
  283. void
  284. tcfig(int ttype, int len)
  285. {
  286. uchar size, rasize, rmsize;
  287. uchar last;
  288. ulong caddr;
  289. ulong cregs;
  290. int i;
  291. USED(ttype, len);
  292. if(readc(&size) != 1)
  293. return;
  294. rasize = (size&0x3) + 1;
  295. rmsize = ((size>>2)&0xf) + 1;
  296. if(readc(&last) != 1)
  297. return;
  298. caddr = getlong(rasize);
  299. cregs = getlong(rmsize);
  300. print("configuration registers at");
  301. for(i = 0; i < 16; i++)
  302. if((1<<i) & cregs)
  303. print(" (%d)0x%lux", i, caddr + i*2);
  304. print("\n");
  305. }
  306. char *intrname[16] =
  307. {
  308. [0] "memory",
  309. [1] "I/O",
  310. [4] "Custom 0",
  311. [5] "Custom 1",
  312. [6] "Custom 2",
  313. [7] "Custom 3",
  314. };
  315. ulong vexp[8] =
  316. {
  317. 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
  318. };
  319. ulong vmant[16] =
  320. {
  321. 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,
  322. };
  323. void
  324. volt(char *name)
  325. {
  326. uchar c;
  327. ulong microv;
  328. ulong exp;
  329. if(readc(&c) != 1)
  330. return;
  331. exp = vexp[c&0x7];
  332. microv = vmant[(c>>3)&0xf]*exp;
  333. while(c & 0x80){
  334. if(readc(&c) != 1)
  335. return;
  336. switch(c){
  337. case 0x7d:
  338. break; /* high impedence when sleeping */
  339. case 0x7e:
  340. case 0x7f:
  341. microv = 0; /* no connection */
  342. break;
  343. default:
  344. exp /= 10;
  345. microv += exp*(c&0x7f);
  346. }
  347. }
  348. print(" V%s %lduV", name, microv);
  349. }
  350. void
  351. amps(char *name)
  352. {
  353. uchar c;
  354. ulong amps;
  355. if(readc(&c) != 1)
  356. return;
  357. amps = vexp[c&0x7]*vmant[(c>>3)&0xf];
  358. while(c & 0x80){
  359. if(readc(&c) != 1)
  360. return;
  361. if(c == 0x7d || c == 0x7e || c == 0x7f)
  362. amps = 0;
  363. }
  364. if(amps >= 1000000)
  365. print(" I%s %ldmA", name, amps/100000);
  366. else if(amps >= 1000)
  367. print(" I%s %lduA", name, amps/100);
  368. else
  369. print(" I%s %ldnA", name, amps*10);
  370. }
  371. void
  372. power(char *name)
  373. {
  374. uchar feature;
  375. print("\t%s: ", name);
  376. if(readc(&feature) != 1)
  377. return;
  378. if(feature & 1)
  379. volt("nominal");
  380. if(feature & 2)
  381. volt("min");
  382. if(feature & 4)
  383. volt("max");
  384. if(feature & 8)
  385. amps("static");
  386. if(feature & 0x10)
  387. amps("avg");
  388. if(feature & 0x20)
  389. amps("peak");
  390. if(feature & 0x40)
  391. amps("powerdown");
  392. print("\n");
  393. }
  394. void
  395. ttiming(char *name, int scale)
  396. {
  397. uchar unscaled;
  398. ulong scaled;
  399. if(readc(&unscaled) != 1)
  400. return;
  401. scaled = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10;
  402. scaled = scaled * vexp[scale];
  403. print("\t%s %ldns\n", name, scaled);
  404. }
  405. void
  406. timing(void)
  407. {
  408. uchar c, i;
  409. if(readc(&c) != 1)
  410. return;
  411. i = c&0x3;
  412. if(i != 3)
  413. ttiming("max wait", i);
  414. i = (c>>2)&0x7;
  415. if(i != 7)
  416. ttiming("max ready/busy wait", i);
  417. i = (c>>5)&0x7;
  418. if(i != 7)
  419. ttiming("reserved wait", i);
  420. }
  421. void
  422. range(int asize, int lsize)
  423. {
  424. ulong address, len;
  425. address = getlong(asize);
  426. len = getlong(lsize);
  427. print("\t\t%lux - %lux\n", address, address+len);
  428. }
  429. char *ioaccess[4] =
  430. {
  431. " no access",
  432. " 8bit access only",
  433. " 8bit or 16bit access",
  434. " selectable 8bit or 8&16bit access",
  435. };
  436. int
  437. iospace(uchar c)
  438. {
  439. int i;
  440. print("\tIO space %d address lines%s\n", c&0x1f, ioaccess[(c>>5)&3]);
  441. if((c & 0x80) == 0)
  442. return -1;
  443. if(readc(&c) != 1)
  444. return -1;
  445. for(i = (c&0xf)+1; i; i--)
  446. range((c>>4)&0x3, (c>>6)&0x3);
  447. return 0;
  448. }
  449. void
  450. iospaces(void)
  451. {
  452. uchar c;
  453. if(readc(&c) != 1)
  454. return;
  455. iospace(c);
  456. }
  457. void
  458. irq(void)
  459. {
  460. uchar c;
  461. uchar irq1, irq2;
  462. ushort i, irqs;
  463. if(readc(&c) != 1)
  464. return;
  465. if(c & 0x10){
  466. if(readc(&irq1) != 1)
  467. return;
  468. if(readc(&irq2) != 1)
  469. return;
  470. irqs = irq1|(irq2<<8);
  471. } else
  472. irqs = 1<<(c&0xf);
  473. print("\tinterrupts%s%s%s", (c&0x20)?":level":"", (c&0x40)?":pulse":"",
  474. (c&0x80)?":shared":"");
  475. for(i = 0; i < 16; i++)
  476. if(irqs & (1<<i))
  477. print(", %d", i);
  478. print("\n");
  479. }
  480. void
  481. memspace(int asize, int lsize, int host)
  482. {
  483. ulong haddress, address, len;
  484. len = getlong(lsize)*256;
  485. address = getlong(asize)*256;
  486. if(host){
  487. haddress = getlong(asize)*256;
  488. print("\tmemory address range 0x%lux - 0x%lux hostaddr 0x%lux\n",
  489. address, address+len, haddress);
  490. } else
  491. print("\tmemory address range 0x%lux - 0x%lux\n", address, address+len);
  492. }
  493. void
  494. misc(void)
  495. {
  496. }
  497. void
  498. tentry(int ttype, int len)
  499. {
  500. uchar c, i, feature;
  501. char *tname;
  502. char buf[16];
  503. USED(ttype, len);
  504. if(readc(&c) != 1)
  505. return;
  506. print("configuration %d%s\n", c&0x3f, (c&0x40)?" (default)":"");
  507. if(c & 0x80){
  508. if(readc(&i) != 1)
  509. return;
  510. tname = intrname[i & 0xf];
  511. if(tname == 0){
  512. tname = buf;
  513. sprint(buf, "type %d", i & 0xf);
  514. }
  515. print("\t%s device, %s%s%s%s\n", tname,
  516. (i&0x10)?" Battery status active":"",
  517. (i&0x20)?" Write Protect active":"",
  518. (i&0x40)?" Ready/Busy active":"",
  519. (i&0x80)?" Memory Wait required":"");
  520. }
  521. if(readc(&feature) != 1)
  522. return;
  523. switch(feature&0x3){
  524. case 1:
  525. power("Vcc");
  526. break;
  527. case 2:
  528. power("Vcc");
  529. power("Vpp");
  530. break;
  531. case 3:
  532. power("Vcc");
  533. power("Vpp1");
  534. power("Vpp2");
  535. break;
  536. }
  537. if(feature&0x4)
  538. timing();
  539. if(feature&0x8)
  540. iospaces();
  541. if(feature&0x10)
  542. irq();
  543. switch((feature>>5)&0x3){
  544. case 1:
  545. memspace(0, 2, 0);
  546. break;
  547. case 2:
  548. memspace(2, 2, 0);
  549. break;
  550. case 3:
  551. if(readc(&c) != 1)
  552. return;
  553. for(i = 0; i <= (c&0x7); i++)
  554. memspace((c>>5)&0x3, (c>>3)&0x3, c&0x80);
  555. break;
  556. }
  557. if(feature&0x80)
  558. misc();
  559. }