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