devlpt.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "../port/error.h"
  8. /* Centronix parallel (printer) port */
  9. /* base addresses */
  10. static int lptbase[] = {
  11. 0x378, /* lpt1 */
  12. 0x3bc, /* lpt2 */
  13. 0x278 /* lpt3 (sic) */
  14. };
  15. #define NDEV nelem(lptbase)
  16. static int lptallocd[NDEV];
  17. /* offsets, and bits in the registers */
  18. enum
  19. {
  20. Qdir= 0x8000,
  21. /* data latch register */
  22. Qdlr= 0x0,
  23. /* printer status register */
  24. Qpsr= 0x1,
  25. Fnotbusy= 0x80,
  26. Fack= 0x40,
  27. Fpe= 0x20,
  28. Fselect= 0x10,
  29. Fnoerror= 0x08,
  30. /* printer control register */
  31. Qpcr= 0x2,
  32. Fie= 0x10,
  33. Fselectin= 0x08,
  34. Finitbar= 0x04,
  35. Faf= 0x02,
  36. Fstrobe= 0x01,
  37. /* fake `data register' */
  38. Qdata= 0x3,
  39. };
  40. static int lptready(void*);
  41. static void outch(int, int);
  42. static void lptintr(Ureg*, void*);
  43. static Rendez lptrendez;
  44. Dirtab lptdir[]={
  45. ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
  46. "dlr", {Qdlr}, 1, 0666,
  47. "psr", {Qpsr}, 5, 0444,
  48. "pcr", {Qpcr}, 0, 0222,
  49. "data", {Qdata}, 0, 0222,
  50. };
  51. static int
  52. lptgen(Chan *c, char*, Dirtab *tab, int ntab, int i, Dir *dp)
  53. {
  54. Qid qid;
  55. if(i == DEVDOTDOT){
  56. mkqid(&qid, Qdir, 0, QTDIR);
  57. devdir(c, qid, ".", 0, eve, 0555, dp);
  58. return 1;
  59. }
  60. i++; /* skip first element for . itself */
  61. if(tab==0 || i>=ntab)
  62. return -1;
  63. tab += i;
  64. qid = tab->qid;
  65. qid.path &= ~Qdir;
  66. if(qid.path < Qdata)
  67. qid.path += lptbase[c->dev];
  68. qid.vers = c->dev;
  69. sprint(up->genbuf, "lpt%lud%s", c->dev+1, tab->name);
  70. devdir(c, qid, up->genbuf, tab->length, eve, tab->perm, dp);
  71. return 1;
  72. }
  73. static Chan*
  74. lptattach(char *spec)
  75. {
  76. Chan *c;
  77. int i = (spec && *spec) ? strtol(spec, 0, 0) : 1;
  78. char name[5];
  79. static int set;
  80. if(!set){
  81. outb(lptbase[i-1]+Qpcr, 0); /* turn off interrupts */
  82. set = 1;
  83. intrenable(IrqLPT, lptintr, 0, BUSUNKNOWN, "lpt");
  84. }
  85. if(i < 1 || i > NDEV)
  86. error(Ebadarg);
  87. if(lptallocd[i-1] == 0){
  88. int ecr;
  89. sprint(name, "lpt%d", i-1);
  90. if(ioalloc(lptbase[i-1], 3, 0, name) < 0)
  91. error("lpt port space in use");
  92. lptallocd[i-1] = 1;
  93. /* Detect ECP - if found, put into PS/2 mode to suit style of driver */
  94. ecr = lptbase[i-1] + 0x402;
  95. if ((inb(ecr) & 3) == 1) {
  96. outb(ecr, 0x34);
  97. if (inb(ecr) == 0x35) {
  98. outb(ecr, (inb(ecr) & 0x1f) | (1 << 5));
  99. if(ioalloc(ecr, 1, 0, name) < 0)
  100. error("lpt ecr port space in use");
  101. }
  102. }
  103. }
  104. c = devattach('L', spec);
  105. c->qid.path = Qdir;
  106. c->dev = i-1;
  107. return c;
  108. }
  109. static Walkqid*
  110. lptwalk(Chan *c, Chan *nc, char **name, int nname)
  111. {
  112. return devwalk(c, nc, name, nname, lptdir, nelem(lptdir), lptgen);
  113. }
  114. static int
  115. lptstat(Chan *c, uchar *dp, int n)
  116. {
  117. return devstat(c, dp, n, lptdir, nelem(lptdir), lptgen);
  118. }
  119. static Chan*
  120. lptopen(Chan *c, int omode)
  121. {
  122. return devopen(c, omode, lptdir, nelem(lptdir), lptgen);
  123. }
  124. static void
  125. lptclose(Chan *)
  126. {
  127. }
  128. static long
  129. lptread(Chan *c, void *a, long n, vlong)
  130. {
  131. char str[16];
  132. int size;
  133. ulong o;
  134. if(c->qid.path == Qdir)
  135. return devdirread(c, a, n, lptdir, nelem(lptdir), lptgen);
  136. size = sprint(str, "0x%2.2ux\n", inb(c->qid.path));
  137. o = c->offset;
  138. if(o >= size)
  139. return 0;
  140. if(o+n > size)
  141. n = size-c->offset;
  142. memmove(a, str+o, n);
  143. return n;
  144. }
  145. static long
  146. lptwrite(Chan *c, void *a, long n, vlong)
  147. {
  148. char str[16], *p;
  149. long base, k;
  150. if(n <= 0)
  151. return 0;
  152. if(c->qid.path != Qdata){
  153. if(n > sizeof str-1)
  154. n = sizeof str-1;
  155. memmove(str, a, n);
  156. str[n] = 0;
  157. outb(c->qid.path, strtoul(str, 0, 0));
  158. return n;
  159. }
  160. p = a;
  161. k = n;
  162. base = lptbase[c->dev];
  163. if(waserror()){
  164. outb(base+Qpcr, Finitbar);
  165. nexterror();
  166. }
  167. while(--k >= 0)
  168. outch(base, *p++);
  169. poperror();
  170. return n;
  171. }
  172. static void
  173. outch(int base, int c)
  174. {
  175. int status, tries;
  176. for(tries=0;; tries++) {
  177. status = inb(base+Qpsr);
  178. if(status&Fnotbusy)
  179. break;
  180. if((status&Fpe)==0 && (status&(Fselect|Fnoerror)) != (Fselect|Fnoerror))
  181. error(Eio);
  182. if(tries < 10)
  183. tsleep(&lptrendez, return0, nil, 1);
  184. else {
  185. outb(base+Qpcr, Finitbar|Fie);
  186. tsleep(&lptrendez, lptready, (void *)base, 100);
  187. }
  188. }
  189. outb(base+Qdlr, c);
  190. outb(base+Qpcr, Finitbar|Fstrobe);
  191. outb(base+Qpcr, Finitbar);
  192. }
  193. static int
  194. lptready(void *base)
  195. {
  196. return inb((int)base+Qpsr)&Fnotbusy;
  197. }
  198. static void
  199. lptintr(Ureg *, void *)
  200. {
  201. wakeup(&lptrendez);
  202. }
  203. Dev lptdevtab = {
  204. 'L',
  205. "lpt",
  206. devreset,
  207. devinit,
  208. devshutdown,
  209. lptattach,
  210. lptwalk,
  211. lptstat,
  212. lptopen,
  213. devcreate,
  214. lptclose,
  215. lptread,
  216. devbread,
  217. lptwrite,
  218. devbwrite,
  219. devremove,
  220. devwstat,
  221. };