xref: /freebsd/sys/dev/ppbus/ppb_base.c (revision 6e8394b8baa7d5d9153ab90de6824bcd19b3b4e1)
1 /*-
2  * Copyright (c) 1997, 1998 Nicolas Souchu
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *	$Id: ppb_base.c,v 1.6 1999/01/10 12:04:54 nsouch Exp $
27  *
28  */
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <machine/clock.h>
33 
34 #include <dev/ppbus/ppbconf.h>
35 
36 /*
37  * ppb_intr()
38  *
39  * Function called by ppcintr() when an intr occurs.
40  */
41 void
42 ppb_intr(struct ppb_link *pl)
43 {
44 	struct ppb_data *ppb = pl->ppbus;
45 
46 	/*
47 	 * Call chipset dependent code.
48 	 * Should be filled at chipset initialisation if needed.
49 	 */
50 	if (pl->adapter->intr_handler)
51 		(*pl->adapter->intr_handler)(pl->adapter_unit);
52 
53 	/*
54 	 * Call upper handler iff the bus is owned by a device and
55 	 * this device has specified an interrupt handler.
56 	 */
57 	if (ppb->ppb_owner && ppb->ppb_owner->intr)
58 		(*ppb->ppb_owner->intr)(ppb->ppb_owner->id_unit);
59 
60 	return;
61 }
62 
63 /*
64  * ppb_poll_device()
65  *
66  * Polls the device
67  *
68  * max is a delay in 10-milliseconds
69  */
70 int
71 ppb_poll_device(struct ppb_device *dev, int max,
72 		char mask, char status, int how)
73 {
74 	int i, j, error;
75 	char r;
76 
77 	/* try at least up to 10ms */
78 	for (j = 0; j < ((how & PPB_POLL) ? max : 1); j++) {
79 		for (i = 0; i < 10000; i++) {
80 			r = ppb_rstr(dev);
81 			DELAY(1);
82 			if ((r & mask) == status)
83 				return (0);
84 		}
85 	}
86 
87 	if (!(how & PPB_POLL)) {
88 	   for (i = 0; max == PPB_FOREVER || i < max-1; i++) {
89 		if ((ppb_rstr(dev) & mask) == status)
90 			return (0);
91 
92 		switch (how) {
93 		case PPB_NOINTR:
94 			/* wait 10 ms */
95 			tsleep((caddr_t)dev, PPBPRI, "ppbpoll", hz/100);
96 			break;
97 
98 		case PPB_INTR:
99 		default:
100 			/* wait 10 ms */
101 			if (((error = tsleep((caddr_t)dev, PPBPRI | PCATCH,
102 			    "ppbpoll", hz/100)) != EWOULDBLOCK) != 0) {
103 				return (error);
104 			}
105 			break;
106 		}
107 	   }
108 	}
109 
110 	return (EWOULDBLOCK);
111 }
112 
113 /*
114  * ppb_set_mode()
115  *
116  * Set the operating mode of the chipset
117  */
118 int
119 ppb_set_mode(struct ppb_device *dev, int mode)
120 {
121 	struct ppb_data *ppb = dev->ppb;
122 	int old_mode = ppb_get_mode(dev);
123 
124 	if ((*ppb->ppb_link->adapter->setmode)(
125 			ppb->ppb_link->adapter_unit, mode))
126 		return (-1);
127 
128 	/* XXX yet device mode = ppbus mode = chipset mode */
129 	dev->mode = ppb->mode = (mode & PPB_MASK);
130 
131 	return (old_mode);
132 }
133 
134 /*
135  * ppb_write()
136  *
137  * Write charaters to the port
138  */
139 int
140 ppb_write(struct ppb_device *dev, char *buf, int len, int how)
141 {
142 	struct ppb_data *ppb = dev->ppb;
143 
144 	return (ppb->ppb_link->adapter->write(ppb->ppb_link->adapter_unit,
145 						buf, len, how));
146 }
147 
148 /*
149  * ppb_reset_epp_timeout()
150  *
151  * Reset the EPP timeout bit in the status register
152  */
153 int
154 ppb_reset_epp_timeout(struct ppb_device *dev)
155 {
156 	struct ppb_data *ppb = dev->ppb;
157 
158 	if (ppb->ppb_owner != dev)
159 		return (EACCES);
160 
161 	(*ppb->ppb_link->adapter->reset_epp_timeout)(ppb->ppb_link->adapter_unit);
162 
163 	return (0);
164 }
165 
166 /*
167  * ppb_ecp_sync()
168  *
169  * Wait for the ECP FIFO to be empty
170  */
171 int
172 ppb_ecp_sync(struct ppb_device *dev)
173 {
174 	struct ppb_data *ppb = dev->ppb;
175 
176 	if (ppb->ppb_owner != dev)
177 		return (EACCES);
178 
179 	(*ppb->ppb_link->adapter->ecp_sync)(ppb->ppb_link->adapter_unit);
180 
181 	return (0);
182 }
183 
184 /*
185  * ppb_get_status()
186  *
187  * Read the status register and update the status info
188  */
189 int
190 ppb_get_status(struct ppb_device *dev, struct ppb_status *status)
191 {
192 	struct ppb_data *ppb = dev->ppb;
193 	register char r;
194 
195 	if (ppb->ppb_owner != dev)
196 		return (EACCES);
197 
198 	r = status->status = ppb_rstr(dev);
199 
200 	status->timeout	= r & TIMEOUT;
201 	status->error	= !(r & nFAULT);
202 	status->select	= r & SELECT;
203 	status->paper_end = r & PERROR;
204 	status->ack	= !(r & nACK);
205 	status->busy	= !(r & nBUSY);
206 
207 	return (0);
208 }
209