xref: /netbsd-src/sys/arch/mvme68k/dev/lpt_pcc.c (revision ce099b40997c43048fb78bd578195f81d2456523)
1 /*	$NetBSD: lpt_pcc.c,v 1.12 2008/04/28 20:23:29 martin Exp $ */
2 
3 /*-
4  * Copyright (c) 1999 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  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Device Driver back-end for the MVME147's parallel printer port
34  */
35 
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: lpt_pcc.c,v 1.12 2008/04/28 20:23:29 martin Exp $");
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/device.h>
43 #include <sys/syslog.h>
44 
45 #include <machine/bus.h>
46 
47 #include <dev/mvme/lptvar.h>
48 
49 #include <mvme68k/dev/lpt_pccreg.h>
50 #include <mvme68k/dev/pccreg.h>
51 #include <mvme68k/dev/pccvar.h>
52 
53 #include "ioconf.h"
54 
55 
56 static int lpt_pcc_intr(void *);
57 static void lpt_pcc_open(struct lpt_softc *, int);
58 static void lpt_pcc_close(struct lpt_softc *);
59 static void lpt_pcc_iprime(struct lpt_softc *);
60 static void lpt_pcc_speed(struct lpt_softc *, int);
61 static int lpt_pcc_notrdy(struct lpt_softc *, int);
62 static void lpt_pcc_wr_data(struct lpt_softc *, u_char);
63 
64 struct lpt_funcs lpt_pcc_funcs = {
65 	lpt_pcc_open,
66 	lpt_pcc_close,
67 	lpt_pcc_iprime,
68 	lpt_pcc_speed,
69 	lpt_pcc_notrdy,
70 	lpt_pcc_wr_data
71 };
72 
73 /*
74  * Autoconfig stuff
75  */
76 static int lpt_pcc_match(device_t, cfdata_t , void *);
77 static void lpt_pcc_attach(device_t, device_t, void *);
78 
79 CFATTACH_DECL_NEW(lpt_pcc, sizeof(struct lpt_softc),
80     lpt_pcc_match, lpt_pcc_attach, NULL, NULL);
81 
82 
83 /*ARGSUSED*/
84 static int
lpt_pcc_match(device_t parent,cfdata_t cf,void * args)85 lpt_pcc_match(device_t parent, cfdata_t cf, void *args)
86 {
87 	struct pcc_attach_args *pa;
88 
89 	pa = args;
90 
91 	if (strcmp(pa->pa_name, lpt_cd.cd_name))
92 		return 0;
93 
94 	pa->pa_ipl = cf->pcccf_ipl;
95 	return 1;
96 }
97 
98 /*ARGSUSED*/
99 static void
lpt_pcc_attach(device_t parent,device_t self,void * args)100 lpt_pcc_attach(device_t parent, device_t self, void *args)
101 {
102 	struct lpt_softc *sc;
103 	struct pcc_attach_args *pa;
104 
105 	sc = device_private(self);
106 	sc->sc_dev = self;
107 	pa = args;
108 
109 	sc->sc_bust = pa->pa_bust;
110 	bus_space_map(pa->pa_bust, pa->pa_offset, LPREG_SIZE, 0, &sc->sc_bush);
111 
112 	sc->sc_ipl = pa->pa_ipl & PCC_IMASK;
113 	sc->sc_funcs = &lpt_pcc_funcs;
114 	sc->sc_laststatus = 0;
115 
116 	aprint_normal(": PCC Parallel Printer\n");
117 
118 	/*
119 	 * Disable interrupts until device is opened
120 	 */
121 	pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, 0);
122 
123 	/*
124 	 * Main attachment code
125 	 */
126 	lpt_attach_subr(sc);
127 
128 	/* Register the event counter */
129 	evcnt_attach_dynamic(&sc->sc_evcnt, EVCNT_TYPE_INTR,
130 	    pccintr_evcnt(sc->sc_ipl), "printer", device_xname(sc->sc_dev));
131 
132 	/*
133 	 * Hook into the printer interrupt
134 	 */
135 	pccintr_establish(PCCV_PRINTER, lpt_pcc_intr, sc->sc_ipl, sc,
136 	    &sc->sc_evcnt);
137 }
138 
139 /*
140  * Handle printer interrupts which occur when the printer is ready to accept
141  * another char.
142  */
143 int
lpt_pcc_intr(void * arg)144 lpt_pcc_intr(void *arg)
145 {
146 	struct lpt_softc *sc;
147 	int i;
148 
149 	sc = arg;
150 
151 	/* is printer online and ready for output */
152 	if (lpt_pcc_notrdy(sc, 0) && lpt_pcc_notrdy(sc, 1))
153 		return 0;
154 
155 	i = lpt_intr(sc);
156 
157 	if (pcc_reg_read(sys_pcc, PCCREG_PRNT_INTR_CTRL) & LPI_ACKINT) {
158 		pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL,
159 		    sc->sc_icr | LPI_ACKINT);
160 	}
161 
162 	return i;
163 }
164 
165 
166 static void
lpt_pcc_open(struct lpt_softc * sc,int int_ena)167 lpt_pcc_open(struct lpt_softc *sc, int int_ena)
168 {
169 	int sps;
170 
171 	pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL,
172 	    LPI_ACKINT | LPI_FAULTINT);
173 
174 	if (int_ena == 0) {
175 		sps = splhigh();
176 		sc->sc_icr = sc->sc_ipl | LPI_ENABLE;
177 		pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, sc->sc_icr);
178 		splx(sps);
179 	}
180 }
181 
182 static void
lpt_pcc_close(struct lpt_softc * sc)183 lpt_pcc_close(struct lpt_softc *sc)
184 {
185 
186 	pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, 0);
187 	sc->sc_icr = sc->sc_ipl;
188 	pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, sc->sc_icr);
189 }
190 
191 /* ARGSUSED */
192 static void
lpt_pcc_iprime(struct lpt_softc * sc)193 lpt_pcc_iprime(struct lpt_softc *sc)
194 {
195 
196 	lpt_control_write(LPC_INPUT_PRIME);
197 	delay(100);
198 }
199 
200 /* ARGSUSED */
201 static void
lpt_pcc_speed(struct lpt_softc * sc,int speed)202 lpt_pcc_speed(struct lpt_softc *sc, int speed)
203 {
204 
205 	if (speed == LPT_STROBE_FAST)
206 		lpt_control_write(LPC_FAST_STROBE);
207 	else
208 		lpt_control_write(0);
209 }
210 
211 static int
lpt_pcc_notrdy(struct lpt_softc * sc,int err)212 lpt_pcc_notrdy(struct lpt_softc *sc, int err)
213 {
214 	u_char status;
215 	u_char new;
216 
217 #define	LPS_INVERT	(LPS_SELECT)
218 #define	LPS_MASK	(LPS_SELECT|LPS_FAULT|LPS_BUSY|LPS_PAPER_EMPTY)
219 
220 	status = (lpt_status_read(sc) ^ LPS_INVERT) & LPS_MASK;
221 
222 	if (err) {
223 		new = status & ~sc->sc_laststatus;
224 		sc->sc_laststatus = status;
225 
226 		if (new & LPS_SELECT)
227 			log(LOG_NOTICE, "%s: offline\n",
228 			    device_xname(sc->sc_dev));
229 		else if (new & LPS_PAPER_EMPTY)
230 			log(LOG_NOTICE, "%s: out of paper\n",
231 			    device_xname(sc->sc_dev));
232 		else if (new & LPS_FAULT)
233 			log(LOG_NOTICE, "%s: output error\n",
234 			    device_xname(sc->sc_dev));
235 	}
236 
237 	pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL,
238 	    sc->sc_icr | LPI_FAULTINT);
239 
240 	return status;
241 }
242 
243 static void
lpt_pcc_wr_data(struct lpt_softc * sc,u_char data)244 lpt_pcc_wr_data(struct lpt_softc *sc, u_char data)
245 {
246 
247 	lpt_data_write(sc, data);
248 }
249