devpcmcia.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  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. wunlock(sp);
  365. poperror();
  366. /* don't let the power turn off */
  367. increfp(sp);
  368. }else if(strcmp(cmd->f[0], "remove") == 0){
  369. /* see if driver exists and is configurable */
  370. if(cmd->nf != 2)
  371. error(Ebadarg);
  372. p = cmd->f[1];
  373. if(*p++ != '#')
  374. error(Ebadarg);
  375. p += chartorune(&r, p);
  376. dtx = devno(r, 1);
  377. if(dtx < 0)
  378. error("no such device type");
  379. if(devtab[dtx]->config == nil)
  380. error("not a dynamicly configurable device");
  381. if(devtab[dtx]->config(0, p, nil) < 0)
  382. error("couldn't unconfigure device");
  383. /* let the power turn off */
  384. decrefp(sp);
  385. }
  386. free(cmd);
  387. return 0;
  388. }
  389. static long
  390. pcmciawrite(Chan *c, void *a, long n, vlong off)
  391. {
  392. PCMslot *sp;
  393. ulong offset = off;
  394. sp = slotof(c);
  395. switch(TYPE(c)){
  396. case Qmem:
  397. if(!sp->occupied)
  398. error(Eio);
  399. return pcmwrite(a, n, offset, sp, sp->mem, 64*OneMeg);
  400. case Qattr:
  401. if(!sp->occupied)
  402. error(Eio);
  403. return pcmwrite(a, n, offset, sp, sp->attr, OneMeg);
  404. case Qevs:
  405. break;
  406. case Qctl:
  407. if(!sp->occupied)
  408. error(Eio);
  409. return pcmctlwrite(a, n, offset, sp);
  410. }
  411. error(Ebadarg);
  412. return -1; /* not reached */
  413. }
  414. /*
  415. * power up/down pcmcia
  416. */
  417. void
  418. pcmciapower(int on)
  419. {
  420. PCMslot *sp;
  421. /* if there's no pcmcia sleave, no interrupts */
  422. iprint("pcmciapower %d\n", on);
  423. if (on){
  424. /* set timing to the default, 300 */
  425. slottiming(0, 300, 300, 300, 0);
  426. slottiming(1, 300, 300, 300, 0);
  427. /* if there's no pcmcia sleave, no interrupts */
  428. if(gpioregs->level & GPIO_OPT_IND_i){
  429. iprint("pcmciapower: no sleeve\n");
  430. return;
  431. }
  432. for (sp = slot; sp < slot + nslot; sp++){
  433. if (sp->dev){
  434. increfp(sp);
  435. iprint("pcmciapower: %s\n", sp->verstr);
  436. delay(10000);
  437. if (sp->dev->power)
  438. sp->dev->power(on);
  439. }
  440. }
  441. }else{
  442. if(gpioregs->level & GPIO_OPT_IND_i){
  443. iprint("pcmciapower: no sleeve\n");
  444. return;
  445. }
  446. for (sp = slot; sp < slot + nslot; sp++){
  447. if (sp->dev){
  448. if (sp->dev->power)
  449. sp->dev->power(on);
  450. decrefp(sp);
  451. }
  452. sp->occupied = 0;
  453. sp->cisread = 0;
  454. }
  455. egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 0);
  456. }
  457. }
  458. Dev pcmciadevtab = {
  459. 'y',
  460. "pcmcia",
  461. pcmciareset,
  462. devinit,
  463. devshutdown,
  464. pcmciaattach,
  465. pcmciawalk,
  466. pcmciastat,
  467. pcmciaopen,
  468. devcreate,
  469. pcmciaclose,
  470. pcmciaread,
  471. devbread,
  472. pcmciawrite,
  473. devbwrite,
  474. devremove,
  475. devwstat,
  476. pcmciapower,
  477. };
  478. /* see what's there */
  479. static void
  480. slotinfo(Ureg*, void*)
  481. {
  482. ulong x = gpioregs->level;
  483. if(x & GPIO_OPT_IND_i){
  484. /* no expansion pack */
  485. slot[0].occupied = slot[0].inserted = 0;
  486. slot[1].occupied = slot[1].inserted = 0;
  487. } else {
  488. if(x & GPIO_CARD_IND0_i){
  489. slot[0].occupied = slot[0].inserted = 0;
  490. slot[0].cisread = 0;
  491. } else {
  492. if(slot[0].occupied == 0){
  493. slot[0].inserted = 1;
  494. slot[0].cisread = 0;
  495. }
  496. slot[0].occupied = 1;
  497. }
  498. if(x & GPIO_CARD_IND1_i){
  499. slot[1].occupied = slot[1].inserted = 0;
  500. slot[1].cisread = 0;
  501. } else {
  502. if(slot[1].occupied == 0){
  503. slot[1].inserted = 1;
  504. slot[1].cisread = 0;
  505. }
  506. slot[1].occupied = 1;
  507. }
  508. if (inserted(nil))
  509. wakeup(&pcmcia.event);
  510. }
  511. }
  512. /* use reference card to turn cards on and off */
  513. static void
  514. increfp(PCMslot *sp)
  515. {
  516. wlock(sp);
  517. if(waserror()){
  518. wunlock(sp);
  519. nexterror();
  520. }
  521. iprint("increfp %ld\n", sp - slot);
  522. if(incref(&pcmcia) == 1){
  523. iprint("increfp full power\n");
  524. egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 1);
  525. delay(200);
  526. egpiobits(EGPIO_pcmcia_reset, 1);
  527. delay(100);
  528. egpiobits(EGPIO_pcmcia_reset, 0);
  529. delay(500);
  530. }
  531. incref(&sp->ref);
  532. slotinfo(nil, nil);
  533. if(sp->occupied && sp->cisread == 0) {
  534. pcmcisread(sp);
  535. }
  536. wunlock(sp);
  537. poperror();
  538. }
  539. static void
  540. decrefp(PCMslot *sp)
  541. {
  542. iprint("decrefp %ld\n", sp - slot);
  543. decref(&sp->ref);
  544. if(decref(&pcmcia) == 0){
  545. iprint("increfp power down\n");
  546. egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 0);
  547. }
  548. }
  549. /*
  550. * the regions are staticly mapped
  551. */
  552. static void
  553. slotmap(int slotno, ulong regs, ulong attr, ulong mem)
  554. {
  555. PCMslot *sp;
  556. sp = &slot[slotno];
  557. sp->slotno = slotno;
  558. sp->memlen = 64*OneMeg;
  559. sp->verstr[0] = 0;
  560. sp->mem = mapmem(mem, 64*OneMeg, 0);
  561. sp->memmap.ca = 0;
  562. sp->memmap.cea = 64*MB;
  563. sp->memmap.isa = (ulong)mem;
  564. sp->memmap.len = 64*OneMeg;
  565. sp->memmap.attr = 0;
  566. sp->attr = mapmem(attr, OneMeg, 0);
  567. sp->attrmap.ca = 0;
  568. sp->attrmap.cea = MB;
  569. sp->attrmap.isa = (ulong)attr;
  570. sp->attrmap.len = OneMeg;
  571. sp->attrmap.attr = 1;
  572. sp->regs = mapspecial(regs, 32*1024);
  573. }
  574. PCMmap*
  575. pcmmap(int slotno, ulong, int, int attr)
  576. {
  577. if(slotno > nslot)
  578. panic("pcmmap");
  579. if(attr)
  580. return &slot[slotno].attrmap;
  581. else
  582. return &slot[slotno].memmap;
  583. }
  584. void
  585. pcmunmap(int, PCMmap*)
  586. {
  587. }
  588. /*
  589. * setup card timings
  590. * times are in ns
  591. * count = ceiling[access-time/(2*3*T)] - 1, where T is a processor cycle
  592. *
  593. */
  594. static int
  595. ns2count(int ns)
  596. {
  597. ulong y;
  598. /* get 100 times cycle time */
  599. y = 100000000/(conf.hz/1000);
  600. /* get 10 times ns/(cycle*6) */
  601. y = (1000*ns)/(6*y);
  602. /* round up */
  603. y += 9;
  604. y /= 10;
  605. /* subtract 1 */
  606. return y-1;
  607. }
  608. static void
  609. slottiming(int slotno, int tio, int tattr, int tmem, int fast)
  610. {
  611. ulong x;
  612. x = 0;
  613. if(fast)
  614. x |= 1<<MECR_fast0;
  615. x |= ns2count(tio) << MECR_io0;
  616. x |= ns2count(tattr) << MECR_attr0;
  617. x |= ns2count(tmem) << MECR_mem0;
  618. if(slotno == 0){
  619. x |= memconfregs->mecr & 0xffff0000;
  620. } else {
  621. x <<= 16;
  622. x |= memconfregs->mecr & 0xffff;
  623. }
  624. memconfregs->mecr = x;
  625. }
  626. /* For compat with ../pc devices. Don't use it for the bitsy
  627. */
  628. int
  629. pcmspecial(char*, ISAConf*)
  630. {
  631. return -1;
  632. }