xref: /netbsd/sys/dev/mvme/lpt_pcctwo.c (revision c4a72b64)
1 /*	$NetBSD: lpt_pcctwo.c,v 1.4 2002/10/02 16:34:26 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Steve C. Woodford.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Device Driver back-end for the PCCChip2's parallel printer port
41  */
42 
43 #include <sys/param.h>
44 #include <sys/kernel.h>
45 #include <sys/systm.h>
46 #include <sys/device.h>
47 #include <sys/syslog.h>
48 
49 #include <machine/cpu.h>
50 #include <machine/bus.h>
51 
52 #include <dev/mvme/lptvar.h>
53 #include <dev/mvme/pcctworeg.h>
54 #include <dev/mvme/pcctwovar.h>
55 
56 /*
57  * Autoconfig stuff
58  */
59 int lpt_pcctwo_match __P((struct device *, struct cfdata *, void *));
60 void lpt_pcctwo_attach __P((struct device *, struct device *, void *));
61 
62 CFATTACH_DECL(lpt_pcctwo, sizeof(struct lpt_softc),
63     lpt_pcctwo_match, lpt_pcctwo_attach, NULL, NULL);
64 
65 extern struct cfdriver lpt_cd;
66 
67 
68 int lpt_pcctwo_intr __P((void *));
69 void lpt_pcctwo_open __P((struct lpt_softc *, int));
70 void lpt_pcctwo_close __P((struct lpt_softc *));
71 void lpt_pcctwo_iprime __P((struct lpt_softc *));
72 void lpt_pcctwo_speed __P((struct lpt_softc *, int));
73 int lpt_pcctwo_notrdy __P((struct lpt_softc *, int));
74 void lpt_pcctwo_wr_data __P((struct lpt_softc *, u_char));
75 
76 struct lpt_funcs lpt_pcctwo_funcs = {
77 	lpt_pcctwo_open,
78 	lpt_pcctwo_close,
79 	lpt_pcctwo_iprime,
80 	lpt_pcctwo_speed,
81 	lpt_pcctwo_notrdy,
82 	lpt_pcctwo_wr_data
83 };
84 
85 /* ARGSUSED */
86 int
87 lpt_pcctwo_match(parent, cf, args)
88 	struct device *parent;
89 	struct cfdata *cf;
90 	void *args;
91 {
92 	struct pcctwo_attach_args *pa;
93 
94 	pa = args;
95 
96 	if (strcmp(pa->pa_name, lpt_cd.cd_name))
97 		return (0);
98 
99 #ifdef MVME68K
100 	if (machineid != MVME_167 && machineid != MVME_177)
101 		return (0);
102 #endif
103 
104 #ifdef MVME88K
105 	if (machineid != MVME_187)
106 		return (0);
107 #endif
108 
109 	pa->pa_ipl = cf->pcctwocf_ipl;
110 
111 	return (1);
112 }
113 
114 /* ARGSUSED */
115 void
116 lpt_pcctwo_attach(parent, self, args)
117 	struct device *parent;
118 	struct device *self;
119 	void *args;
120 {
121 	struct pcctwo_attach_args *pa;
122 	struct lpt_softc *sc;
123 
124 	pa = (struct pcctwo_attach_args *) args;
125 	sc = (struct lpt_softc *) self;
126 
127 	/* The printer registers are part of the PCCChip2's own registers. */
128 	sc->sc_bust = pa->pa_bust;
129 	bus_space_map(pa->pa_bust, pa->pa_offset, PCC2REG_SIZE, 0,
130 	    &sc->sc_bush);
131 
132 	sc->sc_ipl = pa->pa_ipl & PCCTWO_ICR_LEVEL_MASK;
133 	sc->sc_laststatus = 0;
134 	sc->sc_funcs = &lpt_pcctwo_funcs;
135 
136 	printf(": PCCchip2 Parallel Printer\n");
137 
138 	/*
139 	 * Disable interrupts until device is opened
140 	 */
141 	pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR, 0);
142 	pcc2_reg_write(sc, PCC2REG_PRT_FAULT_ICSR, 0);
143 	pcc2_reg_write(sc, PCC2REG_PRT_SEL_ICSR, 0);
144 	pcc2_reg_write(sc, PCC2REG_PRT_PE_ICSR, 0);
145 	pcc2_reg_write(sc, PCC2REG_PRT_BUSY_ICSR, 0);
146 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, 0);
147 
148 	/*
149 	 * Main attachment code
150 	 */
151 	lpt_attach_subr(sc);
152 
153 	/* Register the event counter */
154 	evcnt_attach_dynamic(&sc->sc_evcnt, EVCNT_TYPE_INTR,
155 	    pcctwointr_evcnt(sc->sc_ipl), "printer", sc->sc_dev.dv_xname);
156 
157 	/*
158 	 * Hook into the printer interrupt
159 	 */
160 	pcctwointr_establish(PCCTWOV_PRT_ACK, lpt_pcctwo_intr, sc->sc_ipl, sc,
161 	    &sc->sc_evcnt);
162 }
163 
164 /*
165  * Handle printer interrupts
166  */
167 int
168 lpt_pcctwo_intr(arg)
169 	void *arg;
170 {
171 	struct lpt_softc *sc;
172 	int i;
173 
174 	sc = (struct lpt_softc *) arg;
175 
176 	/* is printer online and ready for output */
177 	if (lpt_pcctwo_notrdy(sc, 0) || lpt_pcctwo_notrdy(sc, 1))
178 		return (0);
179 
180 	i = lpt_intr(sc);
181 
182 	if (pcc2_reg_read(sc, PCC2REG_PRT_INPUT_STATUS) & PCCTWO_PRT_IN_SR_PINT)
183 		pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR,
184 		    sc->sc_icr | PCCTWO_ICR_ICLR);
185 
186 	return (i);
187 }
188 
189 void
190 lpt_pcctwo_open(sc, int_ena)
191 	struct lpt_softc *sc;
192 	int int_ena;
193 {
194 	int sps;
195 
196 	pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR,
197 	    PCCTWO_ICR_ICLR | PCCTWO_ICR_EDGE);
198 
199 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL,
200 	    pcc2_reg_read(sc, PCC2REG_PRT_CONTROL) | PCCTWO_PRT_CTRL_DOEN);
201 
202 	if (int_ena == 0) {
203 		sps = splhigh();
204 		sc->sc_icr = sc->sc_ipl | PCCTWO_ICR_EDGE;
205 		pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR, sc->sc_icr);
206 		splx(sps);
207 	}
208 }
209 
210 void
211 lpt_pcctwo_close(sc)
212 	struct lpt_softc *sc;
213 {
214 
215 	pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR,
216 	    PCCTWO_ICR_ICLR | PCCTWO_ICR_EDGE);
217 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, 0);
218 }
219 
220 void
221 lpt_pcctwo_iprime(sc)
222 	struct lpt_softc *sc;
223 {
224 
225 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL,
226 	    pcc2_reg_read(sc, PCC2REG_PRT_CONTROL) | PCCTWO_PRT_CTRL_INP);
227 
228 	delay(100);
229 
230 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL,
231 	    pcc2_reg_read(sc, PCC2REG_PRT_CONTROL) & ~PCCTWO_PRT_CTRL_INP);
232 
233 	delay(100);
234 }
235 
236 void
237 lpt_pcctwo_speed(sc, speed)
238 	struct lpt_softc *sc;
239 	int speed;
240 {
241 	u_int8_t reg;
242 
243 	reg = pcc2_reg_read(sc, PCC2REG_PRT_CONTROL);
244 
245 	if (speed == LPT_STROBE_FAST)
246 		reg |= PCCTWO_PRT_CTRL_FAST;
247 	else
248 		reg &= ~PCCTWO_PRT_CTRL_FAST;
249 
250 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, reg);
251 }
252 
253 int
254 lpt_pcctwo_notrdy(sc, err)
255 	struct lpt_softc *sc;
256 	int err;
257 {
258 	u_int8_t status;
259 	u_int8_t new;
260 
261 #define	LPS_INVERT	(PCCTWO_PRT_IN_SR_SEL)
262 #define	LPS_MASK	(PCCTWO_PRT_IN_SR_SEL | PCCTWO_PRT_IN_SR_FLT | \
263 			 PCCTWO_PRT_IN_SR_BSY | PCCTWO_PRT_IN_SR_PE)
264 
265 	status = pcc2_reg_read(sc, PCC2REG_PRT_INPUT_STATUS) ^ LPS_INVERT;
266 	status &= LPS_MASK;
267 
268 	if (err) {
269 		new = status & ~sc->sc_laststatus;
270 		sc->sc_laststatus = status;
271 
272 		if (new & PCCTWO_PRT_IN_SR_SEL)
273 			log(LOG_NOTICE, "%s: offline\n",
274 			    sc->sc_dev.dv_xname);
275 		else if (new & PCCTWO_PRT_IN_SR_PE)
276 			log(LOG_NOTICE, "%s: out of paper\n",
277 			    sc->sc_dev.dv_xname);
278 		else if (new & PCCTWO_PRT_IN_SR_FLT)
279 			log(LOG_NOTICE, "%s: output error\n",
280 			    sc->sc_dev.dv_xname);
281 	}
282 
283 	return (status);
284 }
285 
286 void
287 lpt_pcctwo_wr_data(sc, data)
288 	struct lpt_softc *sc;
289 	u_char data;
290 {
291 
292 	pcc2_reg_write16(sc, PCC2REG_PRT_DATA, (u_int16_t) data);
293 }
294