devi82365.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023
  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. * Intel 82365SL PCIC controller and compatibles.
  10. */
  11. enum
  12. {
  13. /*
  14. * registers indices
  15. */
  16. Rid= 0x0, /* identification and revision */
  17. Ris= 0x1, /* interface status */
  18. Rpc= 0x2, /* power control */
  19. Foutena= (1<<7), /* output enable */
  20. Fautopower= (1<<5), /* automatic power switching */
  21. Fcardena= (1<<4), /* PC card enable */
  22. Rigc= 0x3, /* interrupt and general control */
  23. Fiocard= (1<<5), /* I/O card (vs memory) */
  24. Fnotreset= (1<<6), /* reset if not set */
  25. FSMIena= (1<<4), /* enable change interrupt on SMI */
  26. Rcsc= 0x4, /* card status change */
  27. Rcscic= 0x5, /* card status change interrupt config */
  28. Fchangeena= (1<<3), /* card changed */
  29. Fbwarnena= (1<<1), /* card battery warning */
  30. Fbdeadena= (1<<0), /* card battery dead */
  31. Rwe= 0x6, /* address window enable */
  32. Fmem16= (1<<5), /* use A23-A12 to decode address */
  33. Rio= 0x7, /* I/O control */
  34. Fwidth16= (1<<0), /* 16 bit data width */
  35. Fiocs16= (1<<1), /* IOCS16 determines data width */
  36. Fzerows= (1<<2), /* zero wait state */
  37. Ftiming= (1<<3), /* timing register to use */
  38. Riobtm0lo= 0x8, /* I/O address 0 start low byte */
  39. Riobtm0hi= 0x9, /* I/O address 0 start high byte */
  40. Riotop0lo= 0xa, /* I/O address 0 stop low byte */
  41. Riotop0hi= 0xb, /* I/O address 0 stop high byte */
  42. Riobtm1lo= 0xc, /* I/O address 1 start low byte */
  43. Riobtm1hi= 0xd, /* I/O address 1 start high byte */
  44. Riotop1lo= 0xe, /* I/O address 1 stop low byte */
  45. Riotop1hi= 0xf, /* I/O address 1 stop high byte */
  46. Rmap= 0x10, /* map 0 */
  47. /*
  48. * CL-PD67xx extension registers
  49. */
  50. Rmisc1= 0x16, /* misc control 1 */
  51. F5Vdetect= (1<<0),
  52. Fvcc3V= (1<<1),
  53. Fpmint= (1<<2),
  54. Fpsirq= (1<<3),
  55. Fspeaker= (1<<4),
  56. Finpack= (1<<7),
  57. Rfifo= 0x17, /* fifo control */
  58. Fflush= (1<<7), /* flush fifo */
  59. Rmisc2= 0x1E, /* misc control 2 */
  60. Flowpow= (1<<1), /* low power mode */
  61. Rchipinfo= 0x1F, /* chip information */
  62. Ratactl= 0x26, /* ATA control */
  63. /*
  64. * offsets into the system memory address maps
  65. */
  66. Mbtmlo= 0x0, /* System mem addr mapping start low byte */
  67. Mbtmhi= 0x1, /* System mem addr mapping start high byte */
  68. F16bit= (1<<7), /* 16-bit wide data path */
  69. Mtoplo= 0x2, /* System mem addr mapping stop low byte */
  70. Mtophi= 0x3, /* System mem addr mapping stop high byte */
  71. Ftimer1= (1<<6), /* timer set 1 */
  72. Mofflo= 0x4, /* Card memory offset address low byte */
  73. Moffhi= 0x5, /* Card memory offset address high byte */
  74. Fregactive= (1<<6), /* attribute memory */
  75. /*
  76. * configuration registers - they start at an offset in attribute
  77. * memory found in the CIS.
  78. */
  79. Rconfig= 0,
  80. Creset= (1<<7), /* reset device */
  81. Clevel= (1<<6), /* level sensitive interrupt line */
  82. };
  83. #define MAP(x,o) (Rmap + (x)*0x8 + o)
  84. typedef struct I82365 I82365;
  85. /* a controller */
  86. enum
  87. {
  88. Ti82365,
  89. Tpd6710,
  90. Tpd6720,
  91. Tvg46x,
  92. };
  93. struct I82365
  94. {
  95. int type;
  96. int dev;
  97. int nslot;
  98. int xreg; /* index register address */
  99. int dreg; /* data register address */
  100. int irq;
  101. };
  102. static I82365 *controller[4];
  103. static int ncontroller;
  104. static PCMslot *slot;
  105. static PCMslot *lastslot;
  106. static nslot;
  107. static void i82365intr(Ureg*, void*);
  108. static int pcmio(int, ISAConf*);
  109. static long pcmread(int, int, void*, long, vlong);
  110. static long pcmwrite(int, int, void*, long, vlong);
  111. static void i82365dump(PCMslot*);
  112. /*
  113. * reading and writing card registers
  114. */
  115. static uchar
  116. rdreg(PCMslot *pp, int index)
  117. {
  118. outb(((I82365*)pp->cp)->xreg, pp->base + index);
  119. return inb(((I82365*)pp->cp)->dreg);
  120. }
  121. static void
  122. wrreg(PCMslot *pp, int index, uchar val)
  123. {
  124. outb(((I82365*)pp->cp)->xreg, pp->base + index);
  125. outb(((I82365*)pp->cp)->dreg, val);
  126. }
  127. /*
  128. * get info about card
  129. */
  130. static void
  131. slotinfo(PCMslot *pp)
  132. {
  133. uchar isr;
  134. isr = rdreg(pp, Ris);
  135. pp->occupied = (isr & (3<<2)) == (3<<2);
  136. pp->powered = isr & (1<<6);
  137. pp->battery = (isr & 3) == 3;
  138. pp->wrprot = isr & (1<<4);
  139. pp->busy = isr & (1<<5);
  140. pp->msec = TK2MS(MACHP(0)->ticks);
  141. }
  142. static int
  143. vcode(int volt)
  144. {
  145. switch(volt){
  146. case 5:
  147. return 1;
  148. case 12:
  149. return 2;
  150. default:
  151. return 0;
  152. }
  153. }
  154. /*
  155. * enable the slot card
  156. */
  157. static void
  158. slotena(PCMslot *pp)
  159. {
  160. if(pp->enabled)
  161. return;
  162. /* power up and unreset, wait's are empirical (???) */
  163. wrreg(pp, Rpc, Fautopower|Foutena|Fcardena);
  164. delay(300);
  165. wrreg(pp, Rigc, 0);
  166. delay(100);
  167. wrreg(pp, Rigc, Fnotreset);
  168. delay(500);
  169. /* get configuration */
  170. slotinfo(pp);
  171. if(pp->occupied){
  172. pcmcisread(pp);
  173. pp->enabled = 1;
  174. } else
  175. wrreg(pp, Rpc, Fautopower);
  176. }
  177. /*
  178. * disable the slot card
  179. */
  180. static void
  181. slotdis(PCMslot *pp)
  182. {
  183. wrreg(pp, Rpc, 0); /* turn off card power */
  184. wrreg(pp, Rwe, 0); /* no windows */
  185. pp->enabled = 0;
  186. }
  187. /*
  188. * status change interrupt
  189. */
  190. static void
  191. i82365intr(Ureg *, void *)
  192. {
  193. uchar csc, was;
  194. PCMslot *pp;
  195. if(slot == 0)
  196. return;
  197. for(pp = slot; pp < lastslot; pp++){
  198. csc = rdreg(pp, Rcsc);
  199. was = pp->occupied;
  200. slotinfo(pp);
  201. if(csc & (1<<3) && was != pp->occupied){
  202. if(!pp->occupied)
  203. slotdis(pp);
  204. }
  205. }
  206. }
  207. enum
  208. {
  209. Mshift= 12,
  210. Mgran= (1<<Mshift), /* granularity of maps */
  211. Mmask= ~(Mgran-1), /* mask for address bits important to the chip */
  212. };
  213. /*
  214. * get a map for pc card region, return corrected len
  215. */
  216. PCMmap*
  217. pcmmap(int slotno, ulong offset, int len, int attr)
  218. {
  219. PCMslot *pp;
  220. uchar we, bit;
  221. PCMmap *m, *nm;
  222. int i;
  223. ulong e;
  224. pp = slot + slotno;
  225. lock(&pp->mlock);
  226. /* convert offset to granularity */
  227. if(len <= 0)
  228. len = 1;
  229. e = ROUND(offset+len, Mgran);
  230. offset &= Mmask;
  231. len = e - offset;
  232. /* look for a map that covers the right area */
  233. we = rdreg(pp, Rwe);
  234. bit = 1;
  235. nm = 0;
  236. for(m = pp->mmap; m < &pp->mmap[nelem(pp->mmap)]; m++){
  237. if((we & bit))
  238. if(m->attr == attr)
  239. if(offset >= m->ca && e <= m->cea){
  240. m->ref++;
  241. unlock(&pp->mlock);
  242. return m;
  243. }
  244. bit <<= 1;
  245. if(nm == 0 && m->ref == 0)
  246. nm = m;
  247. }
  248. m = nm;
  249. if(m == 0){
  250. unlock(&pp->mlock);
  251. return 0;
  252. }
  253. /* if isa space isn't big enough, free it and get more */
  254. if(m->len < len){
  255. if(m->isa){
  256. umbfree(m->isa, m->len);
  257. m->len = 0;
  258. }
  259. m->isa = PADDR(umbmalloc(0, len, Mgran));
  260. if(m->isa == 0){
  261. print("pcmmap: out of isa space\n");
  262. unlock(&pp->mlock);
  263. return 0;
  264. }
  265. m->len = len;
  266. }
  267. /* set up new map */
  268. m->ca = offset;
  269. m->cea = m->ca + m->len;
  270. m->attr = attr;
  271. i = m-pp->mmap;
  272. bit = 1<<i;
  273. wrreg(pp, Rwe, we & ~bit); /* disable map before changing it */
  274. wrreg(pp, MAP(i, Mbtmlo), m->isa>>Mshift);
  275. wrreg(pp, MAP(i, Mbtmhi), (m->isa>>(Mshift+8)) | F16bit);
  276. wrreg(pp, MAP(i, Mtoplo), (m->isa+m->len-1)>>Mshift);
  277. wrreg(pp, MAP(i, Mtophi), ((m->isa+m->len-1)>>(Mshift+8)));
  278. offset -= m->isa;
  279. offset &= (1<<25)-1;
  280. offset >>= Mshift;
  281. wrreg(pp, MAP(i, Mofflo), offset);
  282. wrreg(pp, MAP(i, Moffhi), (offset>>8) | (attr ? Fregactive : 0));
  283. wrreg(pp, Rwe, we | bit); /* enable map */
  284. m->ref = 1;
  285. unlock(&pp->mlock);
  286. return m;
  287. }
  288. void
  289. pcmunmap(int slotno, PCMmap* m)
  290. {
  291. PCMslot *pp;
  292. pp = slot + slotno;
  293. lock(&pp->mlock);
  294. m->ref--;
  295. unlock(&pp->mlock);
  296. }
  297. static void
  298. increfp(PCMslot *pp)
  299. {
  300. lock(pp);
  301. if(pp->ref++ == 0)
  302. slotena(pp);
  303. unlock(pp);
  304. }
  305. static void
  306. decrefp(PCMslot *pp)
  307. {
  308. lock(pp);
  309. if(pp->ref-- == 1)
  310. slotdis(pp);
  311. unlock(pp);
  312. }
  313. /*
  314. * look for a card whose version contains 'idstr'
  315. */
  316. static int
  317. pcmcia_pcmspecial(char *idstr, ISAConf *isa)
  318. {
  319. PCMslot *pp;
  320. extern char *strstr(char*, char*);
  321. int enabled;
  322. for(pp = slot; pp < lastslot; pp++){
  323. if(pp->special)
  324. continue; /* already taken */
  325. /*
  326. * make sure we don't power on cards when we already know what's
  327. * in them. We'll reread every two minutes if necessary
  328. */
  329. enabled = 0;
  330. if (pp->msec == ~0 || TK2MS(MACHP(0)->ticks) - pp->msec > 120000){
  331. increfp(pp);
  332. enabled++;
  333. }
  334. if(pp->occupied) {
  335. if(strstr(pp->verstr, idstr)){
  336. if (!enabled){
  337. enabled = 1;
  338. increfp(pp);
  339. }
  340. if(isa == 0 || pcmio(pp->slotno, isa) == 0){
  341. pp->special = 1;
  342. return pp->slotno;
  343. }
  344. }
  345. } else
  346. pp->special = 1;
  347. if (enabled)
  348. decrefp(pp);
  349. }
  350. return -1;
  351. }
  352. static void
  353. pcmcia_pcmspecialclose(int slotno)
  354. {
  355. PCMslot *pp;
  356. if(slotno >= nslot)
  357. panic("pcmspecialclose");
  358. pp = slot + slotno;
  359. pp->special = 0;
  360. decrefp(pp);
  361. }
  362. enum
  363. {
  364. Qdir,
  365. Qmem,
  366. Qattr,
  367. Qctl,
  368. Nents = 3,
  369. };
  370. #define SLOTNO(c) ((ulong)((c->qid.path>>8)&0xff))
  371. #define TYPE(c) ((ulong)(c->qid.path&0xff))
  372. #define QID(s,t) (((s)<<8)|(t))
  373. static int
  374. pcmgen(Chan *c, char*, Dirtab *, int , int i, Dir *dp)
  375. {
  376. int slotno;
  377. Qid qid;
  378. long len;
  379. PCMslot *pp;
  380. if(i == DEVDOTDOT){
  381. mkqid(&qid, Qdir, 0, QTDIR);
  382. devdir(c, qid, "#y", 0, eve, 0555, dp);
  383. return 1;
  384. }
  385. if(i >= Nents*nslot)
  386. return -1;
  387. slotno = i/Nents;
  388. pp = slot + slotno;
  389. len = 0;
  390. switch(i%Nents){
  391. case 0:
  392. qid.path = QID(slotno, Qmem);
  393. snprint(up->genbuf, sizeof up->genbuf, "pcm%dmem", slotno);
  394. len = pp->memlen;
  395. break;
  396. case 1:
  397. qid.path = QID(slotno, Qattr);
  398. snprint(up->genbuf, sizeof up->genbuf, "pcm%dattr", slotno);
  399. len = pp->memlen;
  400. break;
  401. case 2:
  402. qid.path = QID(slotno, Qctl);
  403. snprint(up->genbuf, sizeof up->genbuf, "pcm%dctl", slotno);
  404. break;
  405. }
  406. qid.vers = 0;
  407. qid.type = QTFILE;
  408. devdir(c, qid, up->genbuf, len, eve, 0660, dp);
  409. return 1;
  410. }
  411. static char *chipname[] =
  412. {
  413. [Ti82365] "Intel 82365SL",
  414. [Tpd6710] "Cirrus Logic CL-PD6710",
  415. [Tpd6720] "Cirrus Logic CL-PD6720",
  416. [Tvg46x] "Vadem VG-46x",
  417. };
  418. static I82365*
  419. i82365probe(int x, int d, int dev)
  420. {
  421. uchar c, id;
  422. I82365 *cp;
  423. ISAConf isa;
  424. int i, nslot;
  425. outb(x, Rid + (dev<<7));
  426. id = inb(d);
  427. if((id & 0xf0) != 0x80)
  428. return 0; /* not a memory & I/O card */
  429. if((id & 0x0f) == 0x00)
  430. return 0; /* no revision number, not possible */
  431. cp = xalloc(sizeof(I82365));
  432. cp->xreg = x;
  433. cp->dreg = d;
  434. cp->dev = dev;
  435. cp->type = Ti82365;
  436. cp->nslot = 2;
  437. switch(id){
  438. case 0x82:
  439. case 0x83:
  440. case 0x84:
  441. /* could be a cirrus */
  442. outb(x, Rchipinfo + (dev<<7));
  443. outb(d, 0);
  444. c = inb(d);
  445. if((c & 0xc0) != 0xc0)
  446. break;
  447. c = inb(d);
  448. if((c & 0xc0) != 0x00)
  449. break;
  450. if(c & 0x20){
  451. cp->type = Tpd6720;
  452. } else {
  453. cp->type = Tpd6710;
  454. cp->nslot = 1;
  455. }
  456. /* low power mode */
  457. outb(x, Rmisc2 + (dev<<7));
  458. c = inb(d);
  459. outb(d, c & ~Flowpow);
  460. break;
  461. }
  462. /* if it's not a Cirrus, it could be a Vadem... */
  463. if(cp->type == Ti82365){
  464. /* unlock the Vadem extended regs */
  465. outb(x, 0x0E + (dev<<7));
  466. outb(x, 0x37 + (dev<<7));
  467. /* make the id register show the Vadem id */
  468. outb(x, 0x3A + (dev<<7));
  469. c = inb(d);
  470. outb(d, c|0xC0);
  471. outb(x, Rid + (dev<<7));
  472. c = inb(d);
  473. if(c & 0x08)
  474. cp->type = Tvg46x;
  475. /* go back to Intel compatible id */
  476. outb(x, 0x3A + (dev<<7));
  477. c = inb(d);
  478. outb(d, c & ~0xC0);
  479. }
  480. memset(&isa, 0, sizeof(ISAConf));
  481. if(isaconfig("pcmcia", ncontroller, &isa) && isa.irq)
  482. cp->irq = isa.irq;
  483. else
  484. cp->irq = IrqPCMCIA;
  485. for(i = 0; i < isa.nopt; i++){
  486. if(cistrncmp(isa.opt[i], "nslot=", 6))
  487. continue;
  488. nslot = strtol(&isa.opt[i][6], nil, 0);
  489. if(nslot > 0 && nslot <= 2)
  490. cp->nslot = nslot;
  491. }
  492. controller[ncontroller++] = cp;
  493. return cp;
  494. }
  495. static void
  496. i82365dump(PCMslot *pp)
  497. {
  498. int i;
  499. for(i = 0; i < 0x40; i++){
  500. if((i&0x0F) == 0)
  501. print("\n%2.2uX: ", i);
  502. print("%2.2uX ", rdreg(pp, i));
  503. if(((i+1) & 0x0F) == 0x08)
  504. print(" - ");
  505. }
  506. print("\n");
  507. }
  508. /*
  509. * set up for slot cards
  510. */
  511. void
  512. devi82365link(void)
  513. {
  514. static int already;
  515. int i, j;
  516. I82365 *cp;
  517. PCMslot *pp;
  518. char buf[32], *p;
  519. if(already)
  520. return;
  521. already = 1;
  522. if((p=getconf("pcmcia0")) && strncmp(p, "disabled", 8)==0)
  523. return;
  524. if(_pcmspecial)
  525. return;
  526. /* look for controllers if the ports aren't already taken */
  527. if(ioalloc(0x3E0, 2, 0, "i82365.0") >= 0){
  528. i82365probe(0x3E0, 0x3E1, 0);
  529. i82365probe(0x3E0, 0x3E1, 1);
  530. if(ncontroller == 0)
  531. iofree(0x3E0);
  532. }
  533. if(ioalloc(0x3E2, 2, 0, "i82365.1") >= 0){
  534. i = ncontroller;
  535. i82365probe(0x3E2, 0x3E3, 0);
  536. i82365probe(0x3E2, 0x3E3, 1);
  537. if(ncontroller == i)
  538. iofree(0x3E2);
  539. }
  540. if(ncontroller == 0)
  541. return;
  542. _pcmspecial = pcmcia_pcmspecial;
  543. _pcmspecialclose = pcmcia_pcmspecialclose;
  544. for(i = 0; i < ncontroller; i++)
  545. nslot += controller[i]->nslot;
  546. slot = xalloc(nslot * sizeof(PCMslot));
  547. lastslot = slot;
  548. for(i = 0; i < ncontroller; i++){
  549. cp = controller[i];
  550. print("#y%d: %d slot %s: port 0x%uX irq %d\n",
  551. i, cp->nslot, chipname[cp->type], cp->xreg, cp->irq);
  552. for(j = 0; j < cp->nslot; j++){
  553. pp = lastslot++;
  554. pp->slotno = pp - slot;
  555. pp->memlen = 64*MB;
  556. pp->base = (cp->dev<<7) | (j<<6);
  557. pp->cp = cp;
  558. pp->msec = ~0;
  559. pp->verstr[0] = 0;
  560. slotdis(pp);
  561. /* interrupt on status change */
  562. wrreg(pp, Rcscic, (cp->irq<<4) | Fchangeena);
  563. rdreg(pp, Rcsc);
  564. }
  565. /* for card management interrupts */
  566. snprint(buf, sizeof buf, "i82365.%d", i);
  567. intrenable(cp->irq, i82365intr, 0, BUSUNKNOWN, buf);
  568. }
  569. }
  570. static Chan*
  571. i82365attach(char *spec)
  572. {
  573. return devattach('y', spec);
  574. }
  575. static Walkqid*
  576. i82365walk(Chan *c, Chan *nc, char **name, int nname)
  577. {
  578. return devwalk(c, nc, name, nname, 0, 0, pcmgen);
  579. }
  580. static int
  581. i82365stat(Chan *c, uchar *db, int n)
  582. {
  583. return devstat(c, db, n, 0, 0, pcmgen);
  584. }
  585. static Chan*
  586. i82365open(Chan *c, int omode)
  587. {
  588. if(c->qid.type & QTDIR){
  589. if(omode != OREAD)
  590. error(Eperm);
  591. } else
  592. increfp(slot + SLOTNO(c));
  593. c->mode = openmode(omode);
  594. c->flag |= COPEN;
  595. c->offset = 0;
  596. return c;
  597. }
  598. static void
  599. i82365close(Chan *c)
  600. {
  601. if(c->flag & COPEN)
  602. if((c->qid.type & QTDIR) == 0)
  603. decrefp(slot+SLOTNO(c));
  604. }
  605. /* a memmove using only bytes */
  606. static void
  607. memmoveb(uchar *to, uchar *from, int n)
  608. {
  609. while(n-- > 0)
  610. *to++ = *from++;
  611. }
  612. /* a memmove using only shorts & bytes */
  613. static void
  614. memmoves(uchar *to, uchar *from, int n)
  615. {
  616. ushort *t, *f;
  617. if((((ulong)to) & 1) || (((ulong)from) & 1) || (n & 1)){
  618. while(n-- > 0)
  619. *to++ = *from++;
  620. } else {
  621. n = n/2;
  622. t = (ushort*)to;
  623. f = (ushort*)from;
  624. while(n-- > 0)
  625. *t++ = *f++;
  626. }
  627. }
  628. static long
  629. pcmread(int slotno, int attr, void *a, long n, vlong off)
  630. {
  631. int i, len;
  632. PCMmap *m;
  633. uchar *ac;
  634. PCMslot *pp;
  635. ulong offset = off;
  636. pp = slot + slotno;
  637. if(pp->memlen < offset)
  638. return 0;
  639. if(pp->memlen < offset + n)
  640. n = pp->memlen - offset;
  641. m = 0;
  642. if(waserror()){
  643. if(m)
  644. pcmunmap(pp->slotno, m);
  645. nexterror();
  646. }
  647. ac = a;
  648. for(len = n; len > 0; len -= i){
  649. m = pcmmap(pp->slotno, offset, 0, attr);
  650. if(m == 0)
  651. error("can't map PCMCIA card");
  652. if(offset + len > m->cea)
  653. i = m->cea - offset;
  654. else
  655. i = len;
  656. memmoveb(ac, KADDR(m->isa + offset - m->ca), i);
  657. pcmunmap(pp->slotno, m);
  658. offset += i;
  659. ac += i;
  660. }
  661. poperror();
  662. return n;
  663. }
  664. static long
  665. i82365read(Chan *c, void *a, long n, vlong off)
  666. {
  667. char *p, *buf, *e;
  668. PCMslot *pp;
  669. ulong offset = off;
  670. switch(TYPE(c)){
  671. case Qdir:
  672. return devdirread(c, a, n, 0, 0, pcmgen);
  673. case Qmem:
  674. case Qattr:
  675. return pcmread(SLOTNO(c), TYPE(c) == Qattr, a, n, off);
  676. case Qctl:
  677. buf = p = malloc(READSTR);
  678. e = p + READSTR;
  679. pp = slot + SLOTNO(c);
  680. buf[0] = 0;
  681. if(pp->occupied){
  682. p = seprint(p, e, "occupied\n");
  683. if(pp->verstr[0])
  684. p = seprint(p, e, "version %s\n", pp->verstr);
  685. }
  686. if(pp->enabled)
  687. p = seprint(p, e, "enabled\n");
  688. if(pp->powered)
  689. p = seprint(p, e, "powered\n");
  690. if(pp->configed)
  691. p = seprint(p, e, "configed\n");
  692. if(pp->wrprot)
  693. p = seprint(p, e, "write protected\n");
  694. if(pp->busy)
  695. p = seprint(p, e, "busy\n");
  696. seprint(p, e, "battery lvl %d\n", pp->battery);
  697. n = readstr(offset, a, n, buf);
  698. free(buf);
  699. return n;
  700. }
  701. error(Ebadarg);
  702. return -1; /* not reached */
  703. }
  704. static long
  705. pcmwrite(int dev, int attr, void *a, long n, vlong off)
  706. {
  707. int i, len;
  708. PCMmap *m;
  709. uchar *ac;
  710. PCMslot *pp;
  711. ulong offset = off;
  712. pp = slot + dev;
  713. if(pp->memlen < offset)
  714. return 0;
  715. if(pp->memlen < offset + n)
  716. n = pp->memlen - offset;
  717. m = 0;
  718. if(waserror()){
  719. if(m)
  720. pcmunmap(pp->slotno, m);
  721. nexterror();
  722. }
  723. ac = a;
  724. for(len = n; len > 0; len -= i){
  725. m = pcmmap(pp->slotno, offset, 0, attr);
  726. if(m == 0)
  727. error("can't map PCMCIA card");
  728. if(offset + len > m->cea)
  729. i = m->cea - offset;
  730. else
  731. i = len;
  732. memmoveb(KADDR(m->isa + offset - m->ca), ac, i);
  733. pcmunmap(pp->slotno, m);
  734. offset += i;
  735. ac += i;
  736. }
  737. poperror();
  738. return n;
  739. }
  740. static long
  741. i82365write(Chan *c, void *a, long n, vlong off)
  742. {
  743. PCMslot *pp;
  744. char buf[32];
  745. switch(TYPE(c)){
  746. case Qctl:
  747. if(n >= sizeof(buf))
  748. n = sizeof(buf) - 1;
  749. strncpy(buf, a, n);
  750. buf[n] = 0;
  751. pp = slot + SLOTNO(c);
  752. if(!pp->occupied)
  753. error(Eio);
  754. /* set vpp on card */
  755. if(strncmp(buf, "vpp", 3) == 0)
  756. wrreg(pp, Rpc, vcode(atoi(buf+3))|Fautopower|Foutena|Fcardena);
  757. return n;
  758. case Qmem:
  759. case Qattr:
  760. pp = slot + SLOTNO(c);
  761. if(pp->occupied == 0 || pp->enabled == 0)
  762. error(Eio);
  763. n = pcmwrite(pp->slotno, TYPE(c) == Qattr, a, n, off);
  764. if(n < 0)
  765. error(Eio);
  766. return n;
  767. }
  768. error(Ebadarg);
  769. return -1; /* not reached */
  770. }
  771. Dev i82365devtab = {
  772. 'y',
  773. "i82365",
  774. devreset,
  775. devinit,
  776. devshutdown,
  777. i82365attach,
  778. i82365walk,
  779. i82365stat,
  780. i82365open,
  781. devcreate,
  782. i82365close,
  783. i82365read,
  784. devbread,
  785. i82365write,
  786. devbwrite,
  787. devremove,
  788. devwstat,
  789. };
  790. /*
  791. * configure the PCMslot for IO. We assume very heavily that we can read
  792. * configuration info from the CIS. If not, we won't set up correctly.
  793. */
  794. static int
  795. pcmio(int slotno, ISAConf *isa)
  796. {
  797. uchar we, x, *p;
  798. PCMslot *pp;
  799. PCMconftab *ct, *et, *t;
  800. PCMmap *m;
  801. int i, index, irq;
  802. char *cp;
  803. irq = isa->irq;
  804. if(irq == 2)
  805. irq = 9;
  806. if(slotno > nslot)
  807. return -1;
  808. pp = slot + slotno;
  809. if(!pp->occupied)
  810. return -1;
  811. et = &pp->ctab[pp->nctab];
  812. ct = 0;
  813. for(i = 0; i < isa->nopt; i++){
  814. if(strncmp(isa->opt[i], "index=", 6))
  815. continue;
  816. index = strtol(&isa->opt[i][6], &cp, 0);
  817. if(cp == &isa->opt[i][6] || index >= pp->nctab)
  818. return -1;
  819. ct = &pp->ctab[index];
  820. }
  821. if(ct == 0){
  822. /* assume default is right */
  823. if(pp->def)
  824. ct = pp->def;
  825. else
  826. ct = pp->ctab;
  827. /* try for best match */
  828. if(ct->nio == 0
  829. || ct->io[0].start != isa->port || ((1<<irq) & ct->irqs) == 0){
  830. for(t = pp->ctab; t < et; t++)
  831. if(t->nio
  832. && t->io[0].start == isa->port
  833. && ((1<<irq) & t->irqs)){
  834. ct = t;
  835. break;
  836. }
  837. }
  838. if(ct->nio == 0 || ((1<<irq) & ct->irqs) == 0){
  839. for(t = pp->ctab; t < et; t++)
  840. if(t->nio && ((1<<irq) & t->irqs)){
  841. ct = t;
  842. break;
  843. }
  844. }
  845. if(ct->nio == 0){
  846. for(t = pp->ctab; t < et; t++)
  847. if(t->nio){
  848. ct = t;
  849. break;
  850. }
  851. }
  852. }
  853. if(ct == et || ct->nio == 0)
  854. return -1;
  855. if(isa->port == 0 && ct->io[0].start == 0)
  856. return -1;
  857. /* route interrupts */
  858. isa->irq = irq;
  859. wrreg(pp, Rigc, irq | Fnotreset | Fiocard);
  860. /* set power and enable device */
  861. x = vcode(ct->vpp1);
  862. wrreg(pp, Rpc, x|Fautopower|Foutena|Fcardena);
  863. /* 16-bit data path */
  864. if(ct->bit16)
  865. x = Ftiming|Fiocs16|Fwidth16;
  866. else
  867. x = Ftiming;
  868. if(ct->nio == 2 && ct->io[1].start)
  869. x |= x<<4;
  870. wrreg(pp, Rio, x);
  871. /*
  872. * enable io port map 0
  873. * the 'top' register value includes the last valid address
  874. */
  875. if(isa->port == 0)
  876. isa->port = ct->io[0].start;
  877. we = rdreg(pp, Rwe);
  878. wrreg(pp, Riobtm0lo, isa->port);
  879. wrreg(pp, Riobtm0hi, isa->port>>8);
  880. i = isa->port+ct->io[0].len-1;
  881. wrreg(pp, Riotop0lo, i);
  882. wrreg(pp, Riotop0hi, i>>8);
  883. we |= 1<<6;
  884. if(ct->nio == 2 && ct->io[1].start){
  885. wrreg(pp, Riobtm1lo, ct->io[1].start);
  886. wrreg(pp, Riobtm1hi, ct->io[1].start>>8);
  887. i = ct->io[1].start+ct->io[1].len-1;
  888. wrreg(pp, Riotop1lo, i);
  889. wrreg(pp, Riotop1hi, i>>8);
  890. we |= 1<<7;
  891. }
  892. wrreg(pp, Rwe, we);
  893. /* only touch Rconfig if it is present */
  894. if(pp->cpresent & (1<<Rconfig)){
  895. /* Reset adapter */
  896. m = pcmmap(slotno, pp->caddr + Rconfig, 1, 1);
  897. p = KADDR(m->isa + pp->caddr + Rconfig - m->ca);
  898. /* set configuration and interrupt type.
  899. * if level is possible on the card, use it.
  900. */
  901. x = ct->index;
  902. if(ct->irqtype & 0x20)
  903. x |= Clevel;
  904. *p = x;
  905. delay(5);
  906. pcmunmap(slotno, m);
  907. }
  908. return 0;
  909. }