devpcmcia.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  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. * BUG: insertion events are detected by polling.
  10. * Should look into the compaq docs to see if
  11. * there's an interrupt for card insertion
  12. * there's probably one.
  13. */
  14. static PCMslot slot[2];
  15. int nslot = 2;
  16. struct {
  17. Ref;
  18. Rendez event; // where to wait for card events
  19. int evreader; // there's a reader for events
  20. } pcmcia;
  21. enum
  22. {
  23. Qdir,
  24. Qmem,
  25. Qattr,
  26. Qctl,
  27. Qevs,
  28. Nents = 3,
  29. };
  30. enum
  31. {
  32. /*
  33. * configuration registers - they start at an offset in attribute
  34. * memory found in the CIS.
  35. */
  36. Rconfig= 0,
  37. Creset= (1<<7), /* reset device */
  38. Clevel= (1<<6), /* level sensitive interrupt line */
  39. };
  40. static void increfp(PCMslot*);
  41. static void decrefp(PCMslot*);
  42. static void slotmap(int, ulong, ulong, ulong);
  43. static void slottiming(int, int, int, int, int);
  44. static void slotinfo(Ureg*, void*);
  45. #define TYPE(c) (((ulong)c->qid.path)&0xff)
  46. #define PATH(s,t) (((s)<<8)|(t))
  47. static PCMslot*
  48. slotof(Chan *c)
  49. {
  50. ulong x;
  51. x = c->qid.path;
  52. return slot + ((x>>8)&0xff);
  53. }
  54. static int
  55. pcmgen(Chan *c, char *, Dirtab * , int, int i, Dir *dp)
  56. {
  57. int slotno;
  58. Qid qid;
  59. long len;
  60. PCMslot *sp;
  61. if(i == DEVDOTDOT){
  62. mkqid(&qid, Qdir, 0, QTDIR);
  63. devdir(c, qid, "#y", 0, eve, 0555, dp);
  64. return 1;
  65. }
  66. if(i >= Nents*nslot + 1)
  67. return -1;
  68. if(i == Nents*nslot){
  69. len = 0;
  70. qid.path = PATH(0, Qevs);
  71. snprint(up->genbuf, sizeof up->genbuf, "pcmevs");
  72. goto found;
  73. }
  74. slotno = i/Nents;
  75. sp = slot + slotno;
  76. len = 0;
  77. switch(i%Nents){
  78. case 0:
  79. qid.path = PATH(slotno, Qmem);
  80. snprint(up->genbuf, sizeof up->genbuf, "pcm%dmem", slotno);
  81. len = sp->memlen;
  82. break;
  83. case 1:
  84. qid.path = PATH(slotno, Qattr);
  85. snprint(up->genbuf, sizeof up->genbuf, "pcm%dattr", slotno);
  86. len = sp->memlen;
  87. break;
  88. case 2:
  89. qid.path = PATH(slotno, Qctl);
  90. snprint(up->genbuf, sizeof up->genbuf, "pcm%dctl", slotno);
  91. break;
  92. }
  93. found:
  94. qid.vers = 0;
  95. qid.type = QTFILE;
  96. devdir(c, qid, up->genbuf, len, eve, 0660, dp);
  97. return 1;
  98. }
  99. static int
  100. bitno(ulong x)
  101. {
  102. int i;
  103. for(i = 0; i < 8*sizeof(x); i++)
  104. if((1<<i) & x)
  105. break;
  106. return i;
  107. }
  108. /*
  109. * set up the cards, default timing is 300 ns
  110. */
  111. static void
  112. pcmciareset(void)
  113. {
  114. /* staticly map the whole area */
  115. slotmap(0, PHYSPCM0REGS, PYHSPCM0ATTR, PYHSPCM0MEM);
  116. slotmap(1, PHYSPCM1REGS, PYHSPCM1ATTR, PYHSPCM1MEM);
  117. /* set timing to the default, 300 */
  118. slottiming(0, 300, 300, 300, 0);
  119. slottiming(1, 300, 300, 300, 0);
  120. /* if there's no pcmcia sleave, no interrupts */
  121. if(gpioregs->level & GPIO_OPT_IND_i)
  122. return;
  123. /* sleave there, interrupt on card removal */
  124. intrenable(GPIOrising, bitno(GPIO_CARD_IND1_i), slotinfo, nil, "pcmcia slot1 status");
  125. intrenable(GPIOrising, bitno(GPIO_CARD_IND0_i), slotinfo, nil, "pcmcia slot0 status");
  126. }
  127. static Chan*
  128. pcmciaattach(char *spec)
  129. {
  130. return devattach('y', spec);
  131. }
  132. static Walkqid*
  133. pcmciawalk(Chan *c, Chan *nc, char **name, int nname)
  134. {
  135. return devwalk(c, nc, name, nname, 0, 0, pcmgen);
  136. }
  137. static int
  138. pcmciastat(Chan *c, uchar *db, int n)
  139. {
  140. return devstat(c, db, n, 0, 0, pcmgen);
  141. }
  142. static Chan*
  143. pcmciaopen(Chan *c, int omode)
  144. {
  145. PCMslot *slotp;
  146. if(c->qid.type & QTDIR){
  147. if(omode != OREAD)
  148. error(Eperm);
  149. } else {
  150. slotp = slotof(c);
  151. increfp(slotp);
  152. }
  153. c->mode = openmode(omode);
  154. c->flag |= COPEN;
  155. c->offset = 0;
  156. return c;
  157. }
  158. static void
  159. pcmciaclose(Chan *c)
  160. {
  161. if(c->flag & COPEN)
  162. if((c->qid.type & QTDIR) == 0)
  163. decrefp(slotof(c));
  164. }
  165. /* a memmove using only bytes */
  166. static void
  167. memmoveb(uchar *to, uchar *from, int n)
  168. {
  169. while(n-- > 0)
  170. *to++ = *from++;
  171. }
  172. /* a memmove using only shorts & bytes */
  173. static void
  174. memmoves(uchar *to, uchar *from, int n)
  175. {
  176. ushort *t, *f;
  177. if((((ulong)to) & 1) || (((ulong)from) & 1) || (n & 1)){
  178. while(n-- > 0)
  179. *to++ = *from++;
  180. } else {
  181. n = n/2;
  182. t = (ushort*)to;
  183. f = (ushort*)from;
  184. while(n-- > 0)
  185. *t++ = *f++;
  186. }
  187. }
  188. static long
  189. pcmread(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len)
  190. {
  191. rlock(sp);
  192. if(waserror()){
  193. runlock(sp);
  194. nexterror();
  195. }
  196. if(off > len)
  197. return 0;
  198. if(off + n > len)
  199. n = len - off;
  200. memmoveb(a, start+off, n);
  201. runlock(sp);
  202. poperror();
  203. return n;
  204. }
  205. static long
  206. pcmctlread(void *a, long n, ulong off, PCMslot *sp)
  207. {
  208. char *p, *buf, *e;
  209. buf = p = malloc(READSTR);
  210. if(waserror()){
  211. free(buf);
  212. nexterror();
  213. }
  214. e = p + READSTR;
  215. buf[0] = 0;
  216. if(sp->occupied){
  217. p = seprint(p, e, "occupied\n");
  218. if(sp->verstr[0])
  219. p = seprint(p, e, "version %s\n", sp->verstr);
  220. }
  221. USED(p);
  222. n = readstr(off, a, n, buf);
  223. free(buf);
  224. poperror();
  225. return n;
  226. }
  227. static int
  228. inserted(void *)
  229. {
  230. if (slot[0].inserted)
  231. return 1;
  232. if (slot[1].inserted)
  233. return 2;
  234. return 0;
  235. }
  236. static long
  237. pcmevsread(void *a, long n, ulong off)
  238. {
  239. int i;
  240. char *buf = nil;
  241. char *e;
  242. if (pcmcia.evreader)
  243. error("At most one reader");
  244. off = 0;
  245. pcmcia.evreader++;
  246. if (waserror()){
  247. free(buf);
  248. pcmcia.evreader--;
  249. nexterror();
  250. }
  251. while((i = inserted(nil)) == 0){
  252. slotinfo(nil, nil);
  253. tsleep(&pcmcia.event, inserted, nil, 500);
  254. }
  255. pcmcia.evreader--;
  256. slot[i-1].inserted = 0;
  257. buf = malloc(READSTR);
  258. e = buf + READSTR;
  259. buf[0] = 0;
  260. seprint(buf, e, "#y/pcm%dctl\n", i-1);
  261. n = readstr(off, a, n, buf);
  262. free(buf);
  263. poperror();
  264. return n;
  265. }
  266. static long
  267. pcmciaread(Chan *c, void *a, long n, vlong off)
  268. {
  269. PCMslot *sp;
  270. ulong offset = off;
  271. sp = slotof(c);
  272. switch(TYPE(c)){
  273. case Qdir:
  274. return devdirread(c, a, n, 0, 0, pcmgen);
  275. case Qmem:
  276. if(!sp->occupied)
  277. error(Eio);
  278. return pcmread(a, n, offset, sp, sp->mem, 64*OneMeg);
  279. case Qattr:
  280. if(!sp->occupied)
  281. error(Eio);
  282. return pcmread(a, n, offset, sp, sp->attr, OneMeg);
  283. case Qevs:
  284. return pcmevsread(a, n, offset);
  285. case Qctl:
  286. return pcmctlread(a, n, offset, sp);
  287. }
  288. error(Ebadarg);
  289. return -1; /* not reached */
  290. }
  291. static long
  292. pcmwrite(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len)
  293. {
  294. rlock(sp);
  295. if(waserror()){
  296. runlock(sp);
  297. nexterror();
  298. }
  299. if(off > len)
  300. error(Eio);
  301. if(off + n > len)
  302. error(Eio);
  303. memmoveb(start+off, a, n);
  304. poperror();
  305. runlock(sp);
  306. return n;
  307. }
  308. static long
  309. pcmctlwrite(char *p, long n, ulong, PCMslot *sp)
  310. {
  311. Cmdbuf *cmd;
  312. uchar *cp;
  313. int index, i, dtx;
  314. Rune r;
  315. DevConf cf;
  316. Devport port;
  317. cmd = parsecmd(p, n);
  318. if(strcmp(cmd->f[0], "configure") == 0){
  319. wlock(sp);
  320. if(waserror()){
  321. wunlock(sp);
  322. nexterror();
  323. }
  324. /* see if driver exists and is configurable */
  325. if(cmd->nf < 3)
  326. error(Ebadarg);
  327. p = cmd->f[1];
  328. if(*p++ != '#')
  329. error(Ebadarg);
  330. p += chartorune(&r, p);
  331. dtx = devno(r, 1);
  332. if(dtx < 0)
  333. error("no such device type");
  334. if(devtab[dtx]->config == nil)
  335. error("not a dynamicly configurable device");
  336. /* set pcmcia card configuration */
  337. index = 0;
  338. if(sp->def != nil)
  339. index = sp->def->index;
  340. if(cmd->nf > 3){
  341. i = atoi(cmd->f[3]);
  342. if(i < 0 || i >= sp->nctab)
  343. error("bad configuration index");
  344. index = i;
  345. }
  346. if(sp->cfg[0].cpresent & (1<<Rconfig)){
  347. cp = sp->attr;
  348. cp += sp->cfg[0].caddr + Rconfig;
  349. *cp = index;
  350. }
  351. /* configure device */
  352. memset(&cf, 0, sizeof cf);
  353. kstrdup(&cf.type, cmd->f[2]);
  354. cf.mem = (ulong)sp->mem;
  355. cf.ports = &port;
  356. cf.ports[0].port = (ulong)sp->regs;
  357. cf.ports[0].size = 0;
  358. cf.nports = 1;
  359. cf.itype = GPIOfalling;
  360. cf.intnum = bitno(sp == slot ? GPIO_CARD_IRQ0_i : GPIO_CARD_IRQ1_i);
  361. if(devtab[dtx]->config(1, p, &cf) < 0)
  362. error("couldn't configure device");
  363. sp->dev = devtab[dtx];
  364. free(cf.type);
  365. wunlock(sp);
  366. poperror();
  367. /* don't let the power turn off */
  368. increfp(sp);
  369. }else if(strcmp(cmd->f[0], "remove") == 0){
  370. /* see if driver exists and is configurable */
  371. if(cmd->nf != 2)
  372. error(Ebadarg);
  373. p = cmd->f[1];
  374. if(*p++ != '#')
  375. error(Ebadarg);
  376. p += chartorune(&r, p);
  377. dtx = devno(r, 1);
  378. if(dtx < 0)
  379. error("no such device type");
  380. if(devtab[dtx]->config == nil)
  381. error("not a dynamicly configurable device");
  382. if(devtab[dtx]->config(0, p, nil) < 0)
  383. error("couldn't unconfigure device");
  384. /* let the power turn off */
  385. decrefp(sp);
  386. }
  387. free(cmd);
  388. return 0;
  389. }
  390. static long
  391. pcmciawrite(Chan *c, void *a, long n, vlong off)
  392. {
  393. PCMslot *sp;
  394. ulong offset = off;
  395. sp = slotof(c);
  396. switch(TYPE(c)){
  397. case Qmem:
  398. if(!sp->occupied)
  399. error(Eio);
  400. return pcmwrite(a, n, offset, sp, sp->mem, 64*OneMeg);
  401. case Qattr:
  402. if(!sp->occupied)
  403. error(Eio);
  404. return pcmwrite(a, n, offset, sp, sp->attr, OneMeg);
  405. case Qevs:
  406. break;
  407. case Qctl:
  408. if(!sp->occupied)
  409. error(Eio);
  410. return pcmctlwrite(a, n, offset, sp);
  411. }
  412. error(Ebadarg);
  413. return -1; /* not reached */
  414. }
  415. /*
  416. * power up/down pcmcia
  417. */
  418. void
  419. pcmciapower(int on)
  420. {
  421. PCMslot *sp;
  422. /* if there's no pcmcia sleave, no interrupts */
  423. iprint("pcmciapower %d\n", on);
  424. if (on){
  425. /* set timing to the default, 300 */
  426. slottiming(0, 300, 300, 300, 0);
  427. slottiming(1, 300, 300, 300, 0);
  428. /* if there's no pcmcia sleave, no interrupts */
  429. if(gpioregs->level & GPIO_OPT_IND_i){
  430. iprint("pcmciapower: no sleeve\n");
  431. return;
  432. }
  433. for (sp = slot; sp < slot + nslot; sp++){
  434. if (sp->dev){
  435. increfp(sp);
  436. iprint("pcmciapower: %s\n", sp->verstr);
  437. delay(10000);
  438. if (sp->dev->power)
  439. sp->dev->power(on);
  440. }
  441. }
  442. }else{
  443. if(gpioregs->level & GPIO_OPT_IND_i){
  444. iprint("pcmciapower: no sleeve\n");
  445. return;
  446. }
  447. for (sp = slot; sp < slot + nslot; sp++){
  448. if (sp->dev){
  449. if (sp->dev->power)
  450. sp->dev->power(on);
  451. decrefp(sp);
  452. }
  453. sp->occupied = 0;
  454. sp->cisread = 0;
  455. }
  456. egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 0);
  457. }
  458. }
  459. Dev pcmciadevtab = {
  460. 'y',
  461. "pcmcia",
  462. pcmciareset,
  463. devinit,
  464. devshutdown,
  465. pcmciaattach,
  466. pcmciawalk,
  467. pcmciastat,
  468. pcmciaopen,
  469. devcreate,
  470. pcmciaclose,
  471. pcmciaread,
  472. devbread,
  473. pcmciawrite,
  474. devbwrite,
  475. devremove,
  476. devwstat,
  477. pcmciapower,
  478. };
  479. /* see what's there */
  480. static void
  481. slotinfo(Ureg*, void*)
  482. {
  483. ulong x = gpioregs->level;
  484. if(x & GPIO_OPT_IND_i){
  485. /* no expansion pack */
  486. slot[0].occupied = slot[0].inserted = 0;
  487. slot[1].occupied = slot[1].inserted = 0;
  488. } else {
  489. if(x & GPIO_CARD_IND0_i){
  490. slot[0].occupied = slot[0].inserted = 0;
  491. slot[0].cisread = 0;
  492. } else {
  493. if(slot[0].occupied == 0){
  494. slot[0].inserted = 1;
  495. slot[0].cisread = 0;
  496. }
  497. slot[0].occupied = 1;
  498. }
  499. if(x & GPIO_CARD_IND1_i){
  500. slot[1].occupied = slot[1].inserted = 0;
  501. slot[1].cisread = 0;
  502. } else {
  503. if(slot[1].occupied == 0){
  504. slot[1].inserted = 1;
  505. slot[1].cisread = 0;
  506. }
  507. slot[1].occupied = 1;
  508. }
  509. if (inserted(nil))
  510. wakeup(&pcmcia.event);
  511. }
  512. }
  513. /* use reference card to turn cards on and off */
  514. static void
  515. increfp(PCMslot *sp)
  516. {
  517. wlock(sp);
  518. if(waserror()){
  519. wunlock(sp);
  520. nexterror();
  521. }
  522. iprint("increfp %ld\n", sp - slot);
  523. if(incref(&pcmcia) == 1){
  524. iprint("increfp full power\n");
  525. egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 1);
  526. delay(200);
  527. egpiobits(EGPIO_pcmcia_reset, 1);
  528. delay(100);
  529. egpiobits(EGPIO_pcmcia_reset, 0);
  530. delay(500);
  531. }
  532. incref(&sp->ref);
  533. slotinfo(nil, nil);
  534. if(sp->occupied && sp->cisread == 0) {
  535. pcmcisread(sp);
  536. }
  537. wunlock(sp);
  538. poperror();
  539. }
  540. static void
  541. decrefp(PCMslot *sp)
  542. {
  543. iprint("decrefp %ld\n", sp - slot);
  544. decref(&sp->ref);
  545. if(decref(&pcmcia) == 0){
  546. iprint("increfp power down\n");
  547. egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 0);
  548. }
  549. }
  550. /*
  551. * the regions are staticly mapped
  552. */
  553. static void
  554. slotmap(int slotno, ulong regs, ulong attr, ulong mem)
  555. {
  556. PCMslot *sp;
  557. sp = &slot[slotno];
  558. sp->slotno = slotno;
  559. sp->memlen = 64*OneMeg;
  560. sp->verstr[0] = 0;
  561. sp->mem = mapmem(mem, 64*OneMeg, 0);
  562. sp->memmap.ca = 0;
  563. sp->memmap.cea = 64*MB;
  564. sp->memmap.isa = (ulong)mem;
  565. sp->memmap.len = 64*OneMeg;
  566. sp->memmap.attr = 0;
  567. sp->attr = mapmem(attr, OneMeg, 0);
  568. sp->attrmap.ca = 0;
  569. sp->attrmap.cea = MB;
  570. sp->attrmap.isa = (ulong)attr;
  571. sp->attrmap.len = OneMeg;
  572. sp->attrmap.attr = 1;
  573. sp->regs = mapspecial(regs, 32*1024);
  574. }
  575. PCMmap*
  576. pcmmap(int slotno, ulong, int, int attr)
  577. {
  578. if(slotno > nslot)
  579. panic("pcmmap");
  580. if(attr)
  581. return &slot[slotno].attrmap;
  582. else
  583. return &slot[slotno].memmap;
  584. }
  585. void
  586. pcmunmap(int, PCMmap*)
  587. {
  588. }
  589. /*
  590. * setup card timings
  591. * times are in ns
  592. * count = ceiling[access-time/(2*3*T)] - 1, where T is a processor cycle
  593. *
  594. */
  595. static int
  596. ns2count(int ns)
  597. {
  598. ulong y;
  599. /* get 100 times cycle time */
  600. y = 100000000/(conf.hz/1000);
  601. /* get 10 times ns/(cycle*6) */
  602. y = (1000*ns)/(6*y);
  603. /* round up */
  604. y += 9;
  605. y /= 10;
  606. /* subtract 1 */
  607. return y-1;
  608. }
  609. static void
  610. slottiming(int slotno, int tio, int tattr, int tmem, int fast)
  611. {
  612. ulong x;
  613. x = 0;
  614. if(fast)
  615. x |= 1<<MECR_fast0;
  616. x |= ns2count(tio) << MECR_io0;
  617. x |= ns2count(tattr) << MECR_attr0;
  618. x |= ns2count(tmem) << MECR_mem0;
  619. if(slotno == 0){
  620. x |= memconfregs->mecr & 0xffff0000;
  621. } else {
  622. x <<= 16;
  623. x |= memconfregs->mecr & 0xffff;
  624. }
  625. memconfregs->mecr = x;
  626. }
  627. /* For compat with ../pc devices. Don't use it for the bitsy
  628. */
  629. int
  630. pcmspecial(char*, ISAConf*)
  631. {
  632. return -1;
  633. }