xref: /netbsd/sys/dev/mvme/lpt_pcctwo.c (revision bf9ec67e)
1 /*	$NetBSD: lpt_pcctwo.c,v 1.1 2002/02/12 20:38:44 scw 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 struct cfattach lpt_pcctwo_ca = {
63 	sizeof(struct lpt_softc), lpt_pcctwo_match, lpt_pcctwo_attach
64 };
65 
66 extern struct cfdriver lpt_cd;
67 
68 
69 int lpt_pcctwo_intr __P((void *));
70 void lpt_pcctwo_open __P((struct lpt_softc *, int));
71 void lpt_pcctwo_close __P((struct lpt_softc *));
72 void lpt_pcctwo_iprime __P((struct lpt_softc *));
73 void lpt_pcctwo_speed __P((struct lpt_softc *, int));
74 int lpt_pcctwo_notrdy __P((struct lpt_softc *, int));
75 void lpt_pcctwo_wr_data __P((struct lpt_softc *, u_char));
76 
77 struct lpt_funcs lpt_pcctwo_funcs = {
78 	lpt_pcctwo_open,
79 	lpt_pcctwo_close,
80 	lpt_pcctwo_iprime,
81 	lpt_pcctwo_speed,
82 	lpt_pcctwo_notrdy,
83 	lpt_pcctwo_wr_data
84 };
85 
86 /* ARGSUSED */
87 int
88 lpt_pcctwo_match(parent, cf, args)
89 	struct device *parent;
90 	struct cfdata *cf;
91 	void *args;
92 {
93 	struct pcctwo_attach_args *pa;
94 
95 	pa = args;
96 
97 	if (strcmp(pa->pa_name, lpt_cd.cd_name))
98 		return (0);
99 
100 #ifdef MVME68K
101 	if (machineid != MVME_167 && machineid != MVME_177)
102 		return (0);
103 #endif
104 
105 #ifdef MVME88K
106 	if (machineid != MVME_187)
107 		return (0);
108 #endif
109 
110 	pa->pa_ipl = cf->pcctwocf_ipl;
111 
112 	return (1);
113 }
114 
115 /* ARGSUSED */
116 void
117 lpt_pcctwo_attach(parent, self, args)
118 	struct device *parent;
119 	struct device *self;
120 	void *args;
121 {
122 	struct pcctwo_attach_args *pa;
123 	struct lpt_softc *sc;
124 
125 	pa = (struct pcctwo_attach_args *) args;
126 	sc = (struct lpt_softc *) self;
127 
128 	/* The printer registers are part of the PCCChip2's own registers. */
129 	sc->sc_bust = pa->pa_bust;
130 	bus_space_map(pa->pa_bust, pa->pa_offset, PCC2REG_SIZE, 0,
131 	    &sc->sc_bush);
132 
133 	sc->sc_ipl = pa->pa_ipl & PCCTWO_ICR_LEVEL_MASK;
134 	sc->sc_laststatus = 0;
135 	sc->sc_funcs = &lpt_pcctwo_funcs;
136 
137 	printf(": PCCchip2 Parallel Printer\n");
138 
139 	/*
140 	 * Disable interrupts until device is opened
141 	 */
142 	pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR, 0);
143 	pcc2_reg_write(sc, PCC2REG_PRT_FAULT_ICSR, 0);
144 	pcc2_reg_write(sc, PCC2REG_PRT_SEL_ICSR, 0);
145 	pcc2_reg_write(sc, PCC2REG_PRT_PE_ICSR, 0);
146 	pcc2_reg_write(sc, PCC2REG_PRT_BUSY_ICSR, 0);
147 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, 0);
148 
149 	/*
150 	 * Main attachment code
151 	 */
152 	lpt_attach_subr(sc);
153 
154 	/* Register the event counter */
155 	evcnt_attach_dynamic(&sc->sc_evcnt, EVCNT_TYPE_INTR,
156 	    pcctwointr_evcnt(sc->sc_ipl), "printer", sc->sc_dev.dv_xname);
157 
158 	/*
159 	 * Hook into the printer interrupt
160 	 */
161 	pcctwointr_establish(PCCTWOV_PRT_ACK, lpt_pcctwo_intr, sc->sc_ipl, sc,
162 	    &sc->sc_evcnt);
163 }
164 
165 /*
166  * Handle printer interrupts
167  */
168 int
169 lpt_pcctwo_intr(arg)
170 	void *arg;
171 {
172 	struct lpt_softc *sc;
173 	int i;
174 
175 	sc = (struct lpt_softc *) arg;
176 
177 	/* is printer online and ready for output */
178 	if (lpt_pcctwo_notrdy(sc, 0) || lpt_pcctwo_notrdy(sc, 1))
179 		return (0);
180 
181 	i = lpt_intr(sc);
182 
183 	if (pcc2_reg_read(sc, PCC2REG_PRT_INPUT_STATUS) & PCCTWO_PRT_IN_SR_PINT)
184 		pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR,
185 		    sc->sc_icr | PCCTWO_ICR_ICLR);
186 
187 	return (i);
188 }
189 
190 void
191 lpt_pcctwo_open(sc, int_ena)
192 	struct lpt_softc *sc;
193 	int int_ena;
194 {
195 	int sps;
196 
197 	pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR,
198 	    PCCTWO_ICR_ICLR | PCCTWO_ICR_EDGE);
199 
200 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL,
201 	    pcc2_reg_read(sc, PCC2REG_PRT_CONTROL) | PCCTWO_PRT_CTRL_DOEN);
202 
203 	if (int_ena == 0) {
204 		sps = splhigh();
205 		sc->sc_icr = sc->sc_ipl | PCCTWO_ICR_EDGE;
206 		pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR, sc->sc_icr);
207 		splx(sps);
208 	}
209 }
210 
211 void
212 lpt_pcctwo_close(sc)
213 	struct lpt_softc *sc;
214 {
215 
216 	pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR,
217 	    PCCTWO_ICR_ICLR | PCCTWO_ICR_EDGE);
218 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, 0);
219 }
220 
221 void
222 lpt_pcctwo_iprime(sc)
223 	struct lpt_softc *sc;
224 {
225 
226 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL,
227 	    pcc2_reg_read(sc, PCC2REG_PRT_CONTROL) | PCCTWO_PRT_CTRL_INP);
228 
229 	delay(100);
230 
231 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL,
232 	    pcc2_reg_read(sc, PCC2REG_PRT_CONTROL) & ~PCCTWO_PRT_CTRL_INP);
233 
234 	delay(100);
235 }
236 
237 void
238 lpt_pcctwo_speed(sc, speed)
239 	struct lpt_softc *sc;
240 	int speed;
241 {
242 	u_int8_t reg;
243 
244 	reg = pcc2_reg_read(sc, PCC2REG_PRT_CONTROL);
245 
246 	if (speed == LPT_STROBE_FAST)
247 		reg |= PCCTWO_PRT_CTRL_FAST;
248 	else
249 		reg &= ~PCCTWO_PRT_CTRL_FAST;
250 
251 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, reg);
252 }
253 
254 int
255 lpt_pcctwo_notrdy(sc, err)
256 	struct lpt_softc *sc;
257 	int err;
258 {
259 	u_int8_t status;
260 	u_int8_t new;
261 
262 #define	LPS_INVERT	(PCCTWO_PRT_IN_SR_SEL)
263 #define	LPS_MASK	(PCCTWO_PRT_IN_SR_SEL | PCCTWO_PRT_IN_SR_FLT | \
264 			 PCCTWO_PRT_IN_SR_BSY | PCCTWO_PRT_IN_SR_PE)
265 
266 	status = pcc2_reg_read(sc, PCC2REG_PRT_INPUT_STATUS) ^ LPS_INVERT;
267 	status &= LPS_MASK;
268 
269 	if (err) {
270 		new = status & ~sc->sc_laststatus;
271 		sc->sc_laststatus = status;
272 
273 		if (new & PCCTWO_PRT_IN_SR_SEL)
274 			log(LOG_NOTICE, "%s: offline\n",
275 			    sc->sc_dev.dv_xname);
276 		else if (new & PCCTWO_PRT_IN_SR_PE)
277 			log(LOG_NOTICE, "%s: out of paper\n",
278 			    sc->sc_dev.dv_xname);
279 		else if (new & PCCTWO_PRT_IN_SR_FLT)
280 			log(LOG_NOTICE, "%s: output error\n",
281 			    sc->sc_dev.dv_xname);
282 	}
283 
284 	return (status);
285 }
286 
287 void
288 lpt_pcctwo_wr_data(sc, data)
289 	struct lpt_softc *sc;
290 	u_char data;
291 {
292 
293 	pcc2_reg_write16(sc, PCC2REG_PRT_DATA, (u_int16_t) data);
294 }
295