pcmcia.c 9.5 KB

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