cis.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "../port/error.h"
  7. #include "io.h"
  8. enum{
  9. Linktarget = 0x13,
  10. };
  11. /*
  12. * read and crack the card information structure enough to set
  13. * important parameters like power
  14. */
  15. /* cis memory walking */
  16. typedef struct Cisdat {
  17. uchar *cisbase;
  18. int cispos;
  19. int cisskip;
  20. int cislen;
  21. } Cisdat;
  22. static void tcfig(PCMslot*, Cisdat*, int);
  23. static void tentry(PCMslot*, Cisdat*, int);
  24. static void tvers1(PCMslot*, Cisdat*, int);
  25. static void tlonglnkmfc(PCMslot*, Cisdat*, int);
  26. static int
  27. readc(Cisdat *cis, uchar *x)
  28. {
  29. if(cis->cispos >= cis->cislen)
  30. return 0;
  31. *x = cis->cisbase[cis->cisskip*cis->cispos];
  32. cis->cispos++;
  33. return 1;
  34. }
  35. static int
  36. xcistuple(int slotno, int tuple, int subtuple, void *v, int nv, int attr)
  37. {
  38. PCMmap *m;
  39. Cisdat cis;
  40. int i, l;
  41. uchar *p;
  42. uchar type, link, n, c;
  43. int this, subtype;
  44. m = pcmmap(slotno, 0, 0, attr);
  45. if(m == 0)
  46. return -1;
  47. cis.cisbase = KADDR(m->isa);
  48. cis.cispos = 0;
  49. cis.cisskip = attr ? 2 : 1;
  50. cis.cislen = m->len;
  51. /* loop through all the tuples */
  52. for(i = 0; i < 1000; i++){
  53. this = cis.cispos;
  54. if(readc(&cis, &type) != 1)
  55. break;
  56. if(type == 0xFF)
  57. break;
  58. if(readc(&cis, &link) != 1)
  59. break;
  60. if(link == 0xFF)
  61. break;
  62. n = link;
  63. if(link > 1 && subtuple != -1){
  64. if(readc(&cis, &c) != 1)
  65. break;
  66. subtype = c;
  67. n--;
  68. }else
  69. subtype = -1;
  70. if(type == tuple && subtype == subtuple){
  71. p = v;
  72. for(l=0; l<nv && l<n; l++)
  73. if(readc(&cis, p++) != 1)
  74. break;
  75. pcmunmap(slotno, m);
  76. return nv;
  77. }
  78. cis.cispos = this + (2+link);
  79. }
  80. pcmunmap(slotno, m);
  81. return -1;
  82. }
  83. int
  84. pcmcistuple(int slotno, int tuple, int subtuple, void *v, int nv)
  85. {
  86. int n;
  87. /* try attribute space, then memory */
  88. if((n = xcistuple(slotno, tuple, subtuple, v, nv, 1)) >= 0)
  89. return n;
  90. return xcistuple(slotno, tuple, subtuple, v, nv, 0);
  91. }
  92. void
  93. pcmcisread(PCMslot *pp)
  94. {
  95. int this;
  96. Cisdat cis;
  97. PCMmap *m;
  98. uchar type, link;
  99. memset(pp->ctab, 0, sizeof(pp->ctab));
  100. pp->ncfg = 0;
  101. memset(pp->cfg, 0, sizeof(pp->cfg));
  102. pp->configed = 0;
  103. pp->nctab = 0;
  104. pp->verstr[0] = 0;
  105. /*
  106. * Read all tuples in attribute space.
  107. */
  108. m = pcmmap(pp->slotno, 0, 0, 1);
  109. if(m == 0)
  110. return;
  111. cis.cisbase = KADDR(m->isa);
  112. cis.cispos = 0;
  113. cis.cisskip = 2;
  114. cis.cislen = m->len;
  115. /* loop through all the tuples */
  116. for(;;){
  117. this = cis.cispos;
  118. if(readc(&cis, &type) != 1)
  119. break;
  120. if(type == 0xFF)
  121. break;
  122. if(readc(&cis, &link) != 1)
  123. break;
  124. switch(type){
  125. default:
  126. break;
  127. case 6:
  128. tlonglnkmfc(pp, &cis, type);
  129. break;
  130. case 0x15:
  131. tvers1(pp, &cis, type);
  132. break;
  133. case 0x1A:
  134. tcfig(pp, &cis, type);
  135. break;
  136. case 0x1B:
  137. tentry(pp, &cis, type);
  138. break;
  139. }
  140. if(link == 0xFF)
  141. break;
  142. cis.cispos = this + (2+link);
  143. }
  144. pcmunmap(pp->slotno, m);
  145. }
  146. static ulong
  147. getlong(Cisdat *cis, int size)
  148. {
  149. uchar c;
  150. int i;
  151. ulong x;
  152. x = 0;
  153. for(i = 0; i < size; i++){
  154. if(readc(cis, &c) != 1)
  155. break;
  156. x |= c<<(i*8);
  157. }
  158. return x;
  159. }
  160. static void
  161. tcfig(PCMslot *pp, Cisdat *cis, int )
  162. {
  163. uchar size, rasize, rmsize;
  164. uchar last;
  165. if(readc(cis, &size) != 1)
  166. return;
  167. rasize = (size&0x3) + 1;
  168. rmsize = ((size>>2)&0xf) + 1;
  169. if(readc(cis, &last) != 1)
  170. return;
  171. if(pp->ncfg >= 8){
  172. print("tcfig: too many configuration registers\n");
  173. return;
  174. }
  175. pp->cfg[pp->ncfg].caddr = getlong(cis, rasize);
  176. pp->cfg[pp->ncfg].cpresent = getlong(cis, rmsize);
  177. pp->ncfg++;
  178. }
  179. static ulong vexp[8] =
  180. {
  181. 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
  182. };
  183. static ulong vmant[16] =
  184. {
  185. 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,
  186. };
  187. static ulong
  188. microvolt(Cisdat *cis)
  189. {
  190. uchar c;
  191. ulong microvolts;
  192. ulong exp;
  193. if(readc(cis, &c) != 1)
  194. return 0;
  195. exp = vexp[c&0x7];
  196. microvolts = vmant[(c>>3)&0xf]*exp;
  197. while(c & 0x80){
  198. if(readc(cis, &c) != 1)
  199. return 0;
  200. switch(c){
  201. case 0x7d:
  202. break; /* high impedence when sleeping */
  203. case 0x7e:
  204. case 0x7f:
  205. microvolts = 0; /* no connection */
  206. break;
  207. default:
  208. exp /= 10;
  209. microvolts += exp*(c&0x7f);
  210. }
  211. }
  212. return microvolts;
  213. }
  214. static ulong
  215. nanoamps(Cisdat *cis)
  216. {
  217. uchar c;
  218. ulong nanoamps;
  219. if(readc(cis, &c) != 1)
  220. return 0;
  221. nanoamps = vexp[c&0x7]*vmant[(c>>3)&0xf];
  222. while(c & 0x80){
  223. if(readc(cis, &c) != 1)
  224. return 0;
  225. if(c == 0x7d || c == 0x7e || c == 0x7f)
  226. nanoamps = 0;
  227. }
  228. return nanoamps;
  229. }
  230. /*
  231. * only nominal voltage (feature 1) is important for config,
  232. * other features must read card to stay in sync.
  233. */
  234. static ulong
  235. power(Cisdat *cis)
  236. {
  237. uchar feature;
  238. ulong mv;
  239. mv = 0;
  240. if(readc(cis, &feature) != 1)
  241. return 0;
  242. if(feature & 1)
  243. mv = microvolt(cis);
  244. if(feature & 2)
  245. microvolt(cis);
  246. if(feature & 4)
  247. microvolt(cis);
  248. if(feature & 8)
  249. nanoamps(cis);
  250. if(feature & 0x10)
  251. nanoamps(cis);
  252. if(feature & 0x20)
  253. nanoamps(cis);
  254. if(feature & 0x40)
  255. nanoamps(cis);
  256. return mv/1000000;
  257. }
  258. static ulong mantissa[16] =
  259. { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, };
  260. static ulong exponent[8] =
  261. { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, };
  262. static ulong
  263. ttiming(Cisdat *cis, int scale)
  264. {
  265. uchar unscaled;
  266. ulong nanosecs;
  267. if(readc(cis, &unscaled) != 1)
  268. return 0;
  269. nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10;
  270. nanosecs = nanosecs * vexp[scale];
  271. return nanosecs;
  272. }
  273. static void
  274. timing(Cisdat *cis, PCMconftab *ct)
  275. {
  276. uchar c, i;
  277. if(readc(cis, &c) != 1)
  278. return;
  279. i = c&0x3;
  280. if(i != 3)
  281. ct->maxwait = ttiming(cis, i); /* max wait */
  282. i = (c>>2)&0x7;
  283. if(i != 7)
  284. ct->readywait = ttiming(cis, i); /* max ready/busy wait */
  285. i = (c>>5)&0x7;
  286. if(i != 7)
  287. ct->otherwait = ttiming(cis, i); /* reserved wait */
  288. }
  289. static void
  290. iospaces(Cisdat *cis, PCMconftab *ct)
  291. {
  292. uchar c;
  293. int i, nio;
  294. ct->nio = 0;
  295. if(readc(cis, &c) != 1)
  296. return;
  297. ct->bit16 = ((c>>5)&3) >= 2;
  298. if(!(c & 0x80)){
  299. ct->io[0].start = 0;
  300. ct->io[0].len = 1<<(c&0x1f);
  301. ct->nio = 1;
  302. return;
  303. }
  304. if(readc(cis, &c) != 1)
  305. return;
  306. /*
  307. * For each of the range descriptions read the
  308. * start address and the length (value is length-1).
  309. */
  310. nio = (c&0xf)+1;
  311. for(i = 0; i < nio; i++){
  312. ct->io[i].start = getlong(cis, (c>>4)&0x3);
  313. ct->io[i].len = getlong(cis, (c>>6)&0x3)+1;
  314. }
  315. ct->nio = nio;
  316. }
  317. static void
  318. irq(Cisdat *cis, PCMconftab *ct)
  319. {
  320. uchar c;
  321. if(readc(cis, &c) != 1)
  322. return;
  323. ct->irqtype = c & 0xe0;
  324. if(c & 0x10)
  325. ct->irqs = getlong(cis, 2);
  326. else
  327. ct->irqs = 1<<(c&0xf);
  328. ct->irqs &= 0xDEB8; /* levels available to card */
  329. }
  330. static void
  331. memspace(Cisdat *cis, int asize, int lsize, int host)
  332. {
  333. ulong haddress, address, len;
  334. len = getlong(cis, lsize)*256;
  335. address = getlong(cis, asize)*256;
  336. USED(len, address);
  337. if(host){
  338. haddress = getlong(cis, asize)*256;
  339. USED(haddress);
  340. }
  341. }
  342. static void
  343. tentry(PCMslot *pp, Cisdat *cis, int )
  344. {
  345. uchar c, i, feature;
  346. PCMconftab *ct;
  347. if(pp->nctab >= nelem(pp->ctab))
  348. return;
  349. if(readc(cis, &c) != 1)
  350. return;
  351. ct = &pp->ctab[pp->nctab++];
  352. /* copy from last default config */
  353. if(pp->def)
  354. *ct = *pp->def;
  355. ct->index = c & 0x3f;
  356. /* is this the new default? */
  357. if(c & 0x40)
  358. pp->def = ct;
  359. /* memory wait specified? */
  360. if(c & 0x80){
  361. if(readc(cis, &i) != 1)
  362. return;
  363. if(i&0x80)
  364. ct->memwait = 1;
  365. }
  366. if(readc(cis, &feature) != 1)
  367. return;
  368. switch(feature&0x3){
  369. case 1:
  370. ct->vpp1 = ct->vpp2 = power(cis);
  371. break;
  372. case 2:
  373. power(cis);
  374. ct->vpp1 = ct->vpp2 = power(cis);
  375. break;
  376. case 3:
  377. power(cis);
  378. ct->vpp1 = power(cis);
  379. ct->vpp2 = power(cis);
  380. break;
  381. default:
  382. break;
  383. }
  384. if(feature&0x4)
  385. timing(cis, ct);
  386. if(feature&0x8)
  387. iospaces(cis, ct);
  388. if(feature&0x10)
  389. irq(cis, ct);
  390. switch((feature>>5)&0x3){
  391. case 1:
  392. memspace(cis, 0, 2, 0);
  393. break;
  394. case 2:
  395. memspace(cis, 2, 2, 0);
  396. break;
  397. case 3:
  398. if(readc(cis, &c) != 1)
  399. return;
  400. for(i = 0; i <= (c&0x7); i++)
  401. memspace(cis, (c>>5)&0x3, (c>>3)&0x3, c&0x80);
  402. break;
  403. }
  404. pp->configed++;
  405. }
  406. static void
  407. tvers1(PCMslot *pp, Cisdat *cis, int )
  408. {
  409. uchar c, major, minor, last;
  410. int i;
  411. if(readc(cis, &major) != 1)
  412. return;
  413. if(readc(cis, &minor) != 1)
  414. return;
  415. last = 0;
  416. for(i = 0; i < sizeof(pp->verstr)-1; i++){
  417. if(readc(cis, &c) != 1)
  418. return;
  419. if(c == 0)
  420. c = ';';
  421. if(c == '\n')
  422. c = ';';
  423. if(c == 0xff)
  424. break;
  425. if(c == ';' && last == ';')
  426. continue;
  427. pp->verstr[i] = c;
  428. last = c;
  429. }
  430. pp->verstr[i] = 0;
  431. }
  432. static void
  433. tlonglnkmfc(PCMslot *pp, Cisdat *cis, int)
  434. {
  435. int i, npos, opos;
  436. uchar nfn, space, expect, type, this, link;
  437. readc(cis, &nfn);
  438. for(i = 0; i < nfn; i++){
  439. readc(cis, &space);
  440. npos = getlong(cis, 4);
  441. opos = cis->cispos;
  442. cis->cispos = npos;
  443. expect = Linktarget;
  444. while(1){
  445. this = cis->cispos;
  446. if(readc(cis, &type) != 1)
  447. break;
  448. if(type == 0xFF)
  449. break;
  450. if(readc(cis, &link) != 1)
  451. break;
  452. if(expect && expect != type){
  453. print("tlonglnkmfc: expected %X found %X\n",
  454. expect, type);
  455. break;
  456. }
  457. expect = 0;
  458. switch(type){
  459. default:
  460. break;
  461. case 0x15:
  462. tvers1(pp, cis, type);
  463. break;
  464. case 0x1A:
  465. tcfig(pp, cis, type);
  466. break;
  467. case 0x1B:
  468. tentry(pp, cis, type);
  469. break;
  470. }
  471. if(link == 0xFF)
  472. break;
  473. cis->cispos = this + (2+link);
  474. }
  475. cis->cispos = opos;
  476. }
  477. }