1/*	$NetBSD: lpt_pcc.c,v 1.11 2008/03/07 17:15:51 cube 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.11 2008/03/07 17:15:51 cube 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
56static int lpt_pcc_intr(void *);
57static void lpt_pcc_open(struct lpt_softc *, int);
58static void lpt_pcc_close(struct lpt_softc *);
59static void lpt_pcc_iprime(struct lpt_softc *);
60static void lpt_pcc_speed(struct lpt_softc *, int);
61static int lpt_pcc_notrdy(struct lpt_softc *, int);
62static void lpt_pcc_wr_data(struct lpt_softc *, u_char);
63
64struct 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 */
76static int lpt_pcc_match(device_t, cfdata_t , void *);
77static void lpt_pcc_attach(device_t, device_t, void *);
78
79CFATTACH_DECL_NEW(lpt_pcc, sizeof(struct lpt_softc),
80    lpt_pcc_match, lpt_pcc_attach, NULL, NULL);
81
82
83/*ARGSUSED*/
84static int
85lpt_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*/
99static void
100lpt_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 */
143int
144lpt_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
166static void
167lpt_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
182static void
183lpt_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 */
192static void
193lpt_pcc_iprime(struct lpt_softc *sc)
194{
195
196	lpt_control_write(LPC_INPUT_PRIME);
197	delay(100);
198}
199
200/* ARGSUSED */
201static void
202lpt_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
211static int
212lpt_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
243static void
244lpt_pcc_wr_data(struct lpt_softc *sc, u_char data)
245{
246
247	lpt_data_write(sc, data);
248}
249