cis.c 7.9 KB

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