1*ce099b40Smartin /* $NetBSD: lpt_pcc.c,v 1.12 2008/04/28 20:23:29 martin Exp $ */
2a72d37c4Sscw
3a72d37c4Sscw /*-
4a72d37c4Sscw * Copyright (c) 1999 The NetBSD Foundation, Inc.
5a72d37c4Sscw * All rights reserved.
6a72d37c4Sscw *
7a72d37c4Sscw * This code is derived from software contributed to The NetBSD Foundation
8a72d37c4Sscw * by Steve C. Woodford.
9a72d37c4Sscw *
10a72d37c4Sscw * Redistribution and use in source and binary forms, with or without
11a72d37c4Sscw * modification, are permitted provided that the following conditions
12a72d37c4Sscw * are met:
13a72d37c4Sscw * 1. Redistributions of source code must retain the above copyright
14a72d37c4Sscw * notice, this list of conditions and the following disclaimer.
15a72d37c4Sscw * 2. Redistributions in binary form must reproduce the above copyright
16a72d37c4Sscw * notice, this list of conditions and the following disclaimer in the
17a72d37c4Sscw * documentation and/or other materials provided with the distribution.
18a72d37c4Sscw *
19a72d37c4Sscw * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20a72d37c4Sscw * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21a72d37c4Sscw * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22a72d37c4Sscw * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23a72d37c4Sscw * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24a72d37c4Sscw * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25a72d37c4Sscw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26a72d37c4Sscw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27a72d37c4Sscw * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28a72d37c4Sscw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29a72d37c4Sscw * POSSIBILITY OF SUCH DAMAGE.
30a72d37c4Sscw */
31a72d37c4Sscw
32a72d37c4Sscw /*
33a72d37c4Sscw * Device Driver back-end for the MVME147's parallel printer port
34a72d37c4Sscw */
35a72d37c4Sscw
364b2744bfSlukem #include <sys/cdefs.h>
37*ce099b40Smartin __KERNEL_RCSID(0, "$NetBSD: lpt_pcc.c,v 1.12 2008/04/28 20:23:29 martin Exp $");
384b2744bfSlukem
39a72d37c4Sscw #include <sys/param.h>
40a72d37c4Sscw #include <sys/systm.h>
41a72d37c4Sscw #include <sys/kernel.h>
42a72d37c4Sscw #include <sys/device.h>
43a72d37c4Sscw #include <sys/syslog.h>
44a72d37c4Sscw
459c745dbdSscw #include <machine/bus.h>
46a72d37c4Sscw
475bd17a12Sscw #include <dev/mvme/lptvar.h>
485bd17a12Sscw
49a72d37c4Sscw #include <mvme68k/dev/lpt_pccreg.h>
50a72d37c4Sscw #include <mvme68k/dev/pccreg.h>
51a72d37c4Sscw #include <mvme68k/dev/pccvar.h>
52a72d37c4Sscw
53a07f7c80Stsutsui #include "ioconf.h"
54a72d37c4Sscw
55a72d37c4Sscw
56a07f7c80Stsutsui static int lpt_pcc_intr(void *);
57a07f7c80Stsutsui static void lpt_pcc_open(struct lpt_softc *, int);
58a07f7c80Stsutsui static void lpt_pcc_close(struct lpt_softc *);
59a07f7c80Stsutsui static void lpt_pcc_iprime(struct lpt_softc *);
60a07f7c80Stsutsui static void lpt_pcc_speed(struct lpt_softc *, int);
61a07f7c80Stsutsui static int lpt_pcc_notrdy(struct lpt_softc *, int);
62a07f7c80Stsutsui static void lpt_pcc_wr_data(struct lpt_softc *, u_char);
63a72d37c4Sscw
64a72d37c4Sscw struct lpt_funcs lpt_pcc_funcs = {
65a72d37c4Sscw lpt_pcc_open,
66a72d37c4Sscw lpt_pcc_close,
67a72d37c4Sscw lpt_pcc_iprime,
68a72d37c4Sscw lpt_pcc_speed,
69a72d37c4Sscw lpt_pcc_notrdy,
70a72d37c4Sscw lpt_pcc_wr_data
71a72d37c4Sscw };
72a72d37c4Sscw
73a72d37c4Sscw /*
74a72d37c4Sscw * Autoconfig stuff
75a72d37c4Sscw */
768ecf8999Scube static int lpt_pcc_match(device_t, cfdata_t , void *);
778ecf8999Scube static void lpt_pcc_attach(device_t, device_t, void *);
78a72d37c4Sscw
798ecf8999Scube CFATTACH_DECL_NEW(lpt_pcc, sizeof(struct lpt_softc),
80c5e91d44Sthorpej lpt_pcc_match, lpt_pcc_attach, NULL, NULL);
81a72d37c4Sscw
82a72d37c4Sscw
83a72d37c4Sscw /*ARGSUSED*/
84a72d37c4Sscw static int
lpt_pcc_match(device_t parent,cfdata_t cf,void * args)858ecf8999Scube lpt_pcc_match(device_t parent, cfdata_t cf, void *args)
86a72d37c4Sscw {
879c745dbdSscw struct pcc_attach_args *pa;
889c745dbdSscw
899c745dbdSscw pa = args;
90a72d37c4Sscw
91a72d37c4Sscw if (strcmp(pa->pa_name, lpt_cd.cd_name))
92a07f7c80Stsutsui return 0;
93a72d37c4Sscw
94a72d37c4Sscw pa->pa_ipl = cf->pcccf_ipl;
95a07f7c80Stsutsui return 1;
96a72d37c4Sscw }
97a72d37c4Sscw
98a72d37c4Sscw /*ARGSUSED*/
99a72d37c4Sscw static void
lpt_pcc_attach(device_t parent,device_t self,void * args)1008ecf8999Scube lpt_pcc_attach(device_t parent, device_t self, void *args)
101a72d37c4Sscw {
1029c745dbdSscw struct lpt_softc *sc;
1039c745dbdSscw struct pcc_attach_args *pa;
104a72d37c4Sscw
1058ecf8999Scube sc = device_private(self);
1068ecf8999Scube sc->sc_dev = self;
1079c745dbdSscw pa = args;
1089c745dbdSscw
1099c745dbdSscw sc->sc_bust = pa->pa_bust;
1109c745dbdSscw bus_space_map(pa->pa_bust, pa->pa_offset, LPREG_SIZE, 0, &sc->sc_bush);
1119c745dbdSscw
112a72d37c4Sscw sc->sc_ipl = pa->pa_ipl & PCC_IMASK;
113a72d37c4Sscw sc->sc_funcs = &lpt_pcc_funcs;
1149c745dbdSscw sc->sc_laststatus = 0;
115a72d37c4Sscw
1168ecf8999Scube aprint_normal(": PCC Parallel Printer\n");
117a72d37c4Sscw
118a72d37c4Sscw /*
119a72d37c4Sscw * Disable interrupts until device is opened
120a72d37c4Sscw */
1219c745dbdSscw pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, 0);
122a72d37c4Sscw
123a72d37c4Sscw /*
124a72d37c4Sscw * Main attachment code
125a72d37c4Sscw */
126a72d37c4Sscw lpt_attach_subr(sc);
127a72d37c4Sscw
12859ba4788Sscw /* Register the event counter */
12959ba4788Sscw evcnt_attach_dynamic(&sc->sc_evcnt, EVCNT_TYPE_INTR,
1308ecf8999Scube pccintr_evcnt(sc->sc_ipl), "printer", device_xname(sc->sc_dev));
13159ba4788Sscw
132a72d37c4Sscw /*
133a72d37c4Sscw * Hook into the printer interrupt
134a72d37c4Sscw */
13559ba4788Sscw pccintr_establish(PCCV_PRINTER, lpt_pcc_intr, sc->sc_ipl, sc,
13659ba4788Sscw &sc->sc_evcnt);
137a72d37c4Sscw }
138a72d37c4Sscw
139a72d37c4Sscw /*
140a72d37c4Sscw * Handle printer interrupts which occur when the printer is ready to accept
141a72d37c4Sscw * another char.
142a72d37c4Sscw */
143a72d37c4Sscw int
lpt_pcc_intr(void * arg)144a07f7c80Stsutsui lpt_pcc_intr(void *arg)
145a72d37c4Sscw {
1469c745dbdSscw struct lpt_softc *sc;
147a72d37c4Sscw int i;
148a72d37c4Sscw
1499c745dbdSscw sc = arg;
1509c745dbdSscw
151a72d37c4Sscw /* is printer online and ready for output */
152a72d37c4Sscw if (lpt_pcc_notrdy(sc, 0) && lpt_pcc_notrdy(sc, 1))
153a72d37c4Sscw return 0;
154a72d37c4Sscw
155a72d37c4Sscw i = lpt_intr(sc);
156a72d37c4Sscw
1579c745dbdSscw if (pcc_reg_read(sys_pcc, PCCREG_PRNT_INTR_CTRL) & LPI_ACKINT) {
1589c745dbdSscw pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL,
1599c745dbdSscw sc->sc_icr | LPI_ACKINT);
1609c745dbdSscw }
161a72d37c4Sscw
162a07f7c80Stsutsui return i;
163a72d37c4Sscw }
164a72d37c4Sscw
165a72d37c4Sscw
166a72d37c4Sscw static void
lpt_pcc_open(struct lpt_softc * sc,int int_ena)167a07f7c80Stsutsui lpt_pcc_open(struct lpt_softc *sc, int int_ena)
168a72d37c4Sscw {
169a72d37c4Sscw int sps;
170a72d37c4Sscw
1719c745dbdSscw pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL,
1729c745dbdSscw LPI_ACKINT | LPI_FAULTINT);
173a72d37c4Sscw
174a72d37c4Sscw if (int_ena == 0) {
175a72d37c4Sscw sps = splhigh();
176a72d37c4Sscw sc->sc_icr = sc->sc_ipl | LPI_ENABLE;
1779c745dbdSscw pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, sc->sc_icr);
178a72d37c4Sscw splx(sps);
179a72d37c4Sscw }
180a72d37c4Sscw }
181a72d37c4Sscw
182a72d37c4Sscw static void
lpt_pcc_close(struct lpt_softc * sc)183a07f7c80Stsutsui lpt_pcc_close(struct lpt_softc *sc)
184a72d37c4Sscw {
1859c745dbdSscw
1869c745dbdSscw pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, 0);
187a72d37c4Sscw sc->sc_icr = sc->sc_ipl;
1889c745dbdSscw pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, sc->sc_icr);
189a72d37c4Sscw }
190a72d37c4Sscw
1919c745dbdSscw /* ARGSUSED */
192a72d37c4Sscw static void
lpt_pcc_iprime(struct lpt_softc * sc)193a07f7c80Stsutsui lpt_pcc_iprime(struct lpt_softc *sc)
194a72d37c4Sscw {
1959c745dbdSscw
1969c745dbdSscw lpt_control_write(LPC_INPUT_PRIME);
197a72d37c4Sscw delay(100);
198a72d37c4Sscw }
199a72d37c4Sscw
2009c745dbdSscw /* ARGSUSED */
201a72d37c4Sscw static void
lpt_pcc_speed(struct lpt_softc * sc,int speed)202a07f7c80Stsutsui lpt_pcc_speed(struct lpt_softc *sc, int speed)
203a72d37c4Sscw {
2049c745dbdSscw
205a72d37c4Sscw if (speed == LPT_STROBE_FAST)
2069c745dbdSscw lpt_control_write(LPC_FAST_STROBE);
207a72d37c4Sscw else
2089c745dbdSscw lpt_control_write(0);
209a72d37c4Sscw }
210a72d37c4Sscw
211a72d37c4Sscw static int
lpt_pcc_notrdy(struct lpt_softc * sc,int err)212a07f7c80Stsutsui lpt_pcc_notrdy(struct lpt_softc *sc, int err)
213a72d37c4Sscw {
214a72d37c4Sscw u_char status;
215a72d37c4Sscw u_char new;
216a72d37c4Sscw
217a72d37c4Sscw #define LPS_INVERT (LPS_SELECT)
218a72d37c4Sscw #define LPS_MASK (LPS_SELECT|LPS_FAULT|LPS_BUSY|LPS_PAPER_EMPTY)
219a72d37c4Sscw
2209c745dbdSscw status = (lpt_status_read(sc) ^ LPS_INVERT) & LPS_MASK;
221a72d37c4Sscw
222a72d37c4Sscw if (err) {
223a72d37c4Sscw new = status & ~sc->sc_laststatus;
224a72d37c4Sscw sc->sc_laststatus = status;
225a72d37c4Sscw
226a72d37c4Sscw if (new & LPS_SELECT)
227a72d37c4Sscw log(LOG_NOTICE, "%s: offline\n",
2288ecf8999Scube device_xname(sc->sc_dev));
229a72d37c4Sscw else if (new & LPS_PAPER_EMPTY)
230a72d37c4Sscw log(LOG_NOTICE, "%s: out of paper\n",
2318ecf8999Scube device_xname(sc->sc_dev));
232a72d37c4Sscw else if (new & LPS_FAULT)
233a72d37c4Sscw log(LOG_NOTICE, "%s: output error\n",
2348ecf8999Scube device_xname(sc->sc_dev));
235a72d37c4Sscw }
236a72d37c4Sscw
2379c745dbdSscw pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL,
2389c745dbdSscw sc->sc_icr | LPI_FAULTINT);
239a72d37c4Sscw
240a07f7c80Stsutsui return status;
241a72d37c4Sscw }
242a72d37c4Sscw
243a72d37c4Sscw static void
lpt_pcc_wr_data(struct lpt_softc * sc,u_char data)244a07f7c80Stsutsui lpt_pcc_wr_data(struct lpt_softc *sc, u_char data)
245a72d37c4Sscw {
246a72d37c4Sscw
2479c745dbdSscw lpt_data_write(sc, data);
248a72d37c4Sscw }
249