xref: /minix3/minix/drivers/printer/printer/printer.c (revision 1aad172900a22f403baf366fb7db7ee4560c7544)
1433d6423SLionel Sambuc /* This file contains the printer driver. It is a fairly simple driver,
2433d6423SLionel Sambuc  * supporting only one printer.  Characters that are written to the driver
3433d6423SLionel Sambuc  * are written to the printer without any changes at all.
4433d6423SLionel Sambuc  *
5433d6423SLionel Sambuc  * Changes:
6433d6423SLionel Sambuc  *	May 07, 2004	fix: wait until printer is ready  (Jorrit N. Herder)
7433d6423SLionel Sambuc  *	May 06, 2004	printer driver moved to user-space  (Jorrit N. Herder)
8433d6423SLionel Sambuc  *
9433d6423SLionel Sambuc  * Note: since only 1 printer is supported, minor dev is not used at present.
10433d6423SLionel Sambuc  */
11433d6423SLionel Sambuc 
12433d6423SLionel Sambuc #include <minix/endpoint.h>
13433d6423SLionel Sambuc #include <minix/drivers.h>
14433d6423SLionel Sambuc #include <minix/chardriver.h>
15433d6423SLionel Sambuc 
16433d6423SLionel Sambuc /* Control bits (in port_base + 2).  "+" means positive logic and "-" means
17433d6423SLionel Sambuc  * negative logic.  Most of the signals are negative logic on the pins but
18433d6423SLionel Sambuc  * many are converted to positive logic in the ports.  Some manuals are
19433d6423SLionel Sambuc  * misleading because they only document the pin logic.
20433d6423SLionel Sambuc  *
21433d6423SLionel Sambuc  *	+0x01	Pin 1	-Strobe
22433d6423SLionel Sambuc  *	+0x02	Pin 14	-Auto Feed
23433d6423SLionel Sambuc  *	-0x04	Pin 16	-Initialize Printer
24433d6423SLionel Sambuc  *	+0x08	Pin 17	-Select Printer
25433d6423SLionel Sambuc  *	+0x10	IRQ7 Enable
26433d6423SLionel Sambuc  *
27433d6423SLionel Sambuc  * Auto Feed and Select Printer are always enabled. Strobe is enabled briefly
28433d6423SLionel Sambuc  * when characters are output.  Initialize Printer is enabled briefly when
29433d6423SLionel Sambuc  * the task is started.  IRQ7 is enabled when the first character is output
30433d6423SLionel Sambuc  * and left enabled until output is completed (or later after certain
31433d6423SLionel Sambuc  * abnormal completions).
32433d6423SLionel Sambuc  */
33433d6423SLionel Sambuc #define ASSERT_STROBE   0x1D	/* strobe a character to the interface */
34433d6423SLionel Sambuc #define NEGATE_STROBE   0x1C	/* enable interrupt on interface */
35433d6423SLionel Sambuc #define PR_SELECT          0x0C	/* select printer bit */
36433d6423SLionel Sambuc #define INIT_PRINTER    0x08	/* init printer bits */
37433d6423SLionel Sambuc 
38433d6423SLionel Sambuc /* Status bits (in port_base + 2).
39433d6423SLionel Sambuc  *
40433d6423SLionel Sambuc  *	-0x08	Pin 15	-Error
41433d6423SLionel Sambuc  *	+0x10	Pin 13	+Select Status
42433d6423SLionel Sambuc  *	+0x20	Pin 12	+Out of Paper
43433d6423SLionel Sambuc  *	-0x40	Pin 10	-Acknowledge
44433d6423SLionel Sambuc  *	-0x80	Pin 11	+Busy
45433d6423SLionel Sambuc  */
46433d6423SLionel Sambuc #define BUSY_STATUS     0x10	/* printer gives this status when busy */
47433d6423SLionel Sambuc #define NO_PAPER        0x20	/* status bit saying that paper is out */
48433d6423SLionel Sambuc #define NORMAL_STATUS   0x90	/* printer gives this status when idle */
49433d6423SLionel Sambuc #define ON_LINE         0x10	/* status bit saying that printer is online */
50433d6423SLionel Sambuc #define STATUS_MASK	0xB0	/* mask to filter out status bits */
51433d6423SLionel Sambuc 
52433d6423SLionel Sambuc #define MAX_ONLINE_RETRIES 120  /* about 60s: waits 0.5s after each retry */
53433d6423SLionel Sambuc 
54433d6423SLionel Sambuc /* Centronics interface timing that must be met by software (in microsec).
55433d6423SLionel Sambuc  *
56433d6423SLionel Sambuc  * Strobe length:	0.5u to 100u (not sure about the upper limit).
57433d6423SLionel Sambuc  * Data set up:		0.5u before strobe.
58433d6423SLionel Sambuc  * Data hold:		0.5u after strobe.
59433d6423SLionel Sambuc  * Init pulse length:	over 200u (not sure).
60433d6423SLionel Sambuc  *
61433d6423SLionel Sambuc  * The strobe length is about 50u with the code here and function calls for
62433d6423SLionel Sambuc  * sys_outb() - not much to spare.  The 0.5u minimums will not be violated
63433d6423SLionel Sambuc  * with the sys_outb() messages exchanged.
64433d6423SLionel Sambuc  */
65433d6423SLionel Sambuc 
66433d6423SLionel Sambuc static endpoint_t caller;	/* process to tell when printing done (FS) */
67433d6423SLionel Sambuc static int done_status;	/* status of last output completion */
68433d6423SLionel Sambuc static int oleft;		/* bytes of output left in obuf */
69433d6423SLionel Sambuc static unsigned char obuf[128];	/* output buffer */
70433d6423SLionel Sambuc static unsigned const char *optr;	/* ptr to next char in obuf to print */
71433d6423SLionel Sambuc static int orig_count;		/* original byte count */
72433d6423SLionel Sambuc static int port_base;		/* I/O port for printer */
73433d6423SLionel Sambuc static cp_grant_id_t grant_nr;	/* grant on which print happens */
74433d6423SLionel Sambuc static int user_left;		/* bytes of output left in user buf */
75433d6423SLionel Sambuc static vir_bytes user_vir_d;	/* offset in user buf */
76433d6423SLionel Sambuc int writing;		/* nonzero while write is in progress */
77433d6423SLionel Sambuc static cdev_id_t write_id;	/* request ID of ongoing write */
78433d6423SLionel Sambuc static int irq_hook_id;	/* id of irq hook at kernel */
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc static void output_done(void);
81433d6423SLionel Sambuc static void prepare_output(void);
82433d6423SLionel Sambuc static int do_probe(void);
83433d6423SLionel Sambuc static void do_initialize(void);
84433d6423SLionel Sambuc static int printer_open(devminor_t minor, int access, endpoint_t user_endpt);
85433d6423SLionel Sambuc static ssize_t printer_write(devminor_t minor, u64_t position,
86433d6423SLionel Sambuc 	endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
87433d6423SLionel Sambuc 	cdev_id_t id);
88433d6423SLionel Sambuc static int printer_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id);
89433d6423SLionel Sambuc static void printer_intr(unsigned int mask);
90433d6423SLionel Sambuc 
91433d6423SLionel Sambuc /* SEF functions and variables. */
92433d6423SLionel Sambuc static void sef_local_startup(void);
93433d6423SLionel Sambuc static int sef_cb_init_fresh(int type, sef_init_info_t *info);
94433d6423SLionel Sambuc EXTERN int sef_cb_lu_prepare(int state);
95*e1f889d2SCristiano Giuffrida EXTERN int sef_cb_lu_state_isvalid(int state, int flags);
96433d6423SLionel Sambuc EXTERN void sef_cb_lu_state_dump(int state);
97433d6423SLionel Sambuc 
98433d6423SLionel Sambuc /* Entry points to this driver. */
99433d6423SLionel Sambuc static struct chardriver printer_tab = {
100433d6423SLionel Sambuc   .cdr_open	= printer_open,
101433d6423SLionel Sambuc   .cdr_write	= printer_write,
102433d6423SLionel Sambuc   .cdr_cancel	= printer_cancel,
103433d6423SLionel Sambuc   .cdr_intr	= printer_intr
104433d6423SLionel Sambuc };
105433d6423SLionel Sambuc 
106433d6423SLionel Sambuc /*===========================================================================*
107433d6423SLionel Sambuc  *				printer_task				     *
108433d6423SLionel Sambuc  *===========================================================================*/
main(void)109433d6423SLionel Sambuc int main(void)
110433d6423SLionel Sambuc {
111433d6423SLionel Sambuc /* Main routine of the printer task. */
112433d6423SLionel Sambuc 
113433d6423SLionel Sambuc   /* SEF local startup. */
114433d6423SLionel Sambuc   sef_local_startup();
115433d6423SLionel Sambuc 
116433d6423SLionel Sambuc   chardriver_task(&printer_tab);
117433d6423SLionel Sambuc }
118433d6423SLionel Sambuc 
119433d6423SLionel Sambuc /*===========================================================================*
120433d6423SLionel Sambuc  *			       sef_local_startup			     *
121433d6423SLionel Sambuc  *===========================================================================*/
sef_local_startup()122433d6423SLionel Sambuc static void sef_local_startup()
123433d6423SLionel Sambuc {
124433d6423SLionel Sambuc   /* Register init callbacks. */
125433d6423SLionel Sambuc   sef_setcb_init_fresh(sef_cb_init_fresh);
126433d6423SLionel Sambuc   sef_setcb_init_restart(sef_cb_init_fresh);
127433d6423SLionel Sambuc 
128433d6423SLionel Sambuc   /* Register live update callbacks. */
129433d6423SLionel Sambuc   sef_setcb_lu_prepare(sef_cb_lu_prepare);
130433d6423SLionel Sambuc   sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid);
131433d6423SLionel Sambuc   sef_setcb_lu_state_dump(sef_cb_lu_state_dump);
132433d6423SLionel Sambuc 
133433d6423SLionel Sambuc   /* Register signal callbacks. */
134433d6423SLionel Sambuc   sef_setcb_signal_handler(sef_cb_signal_handler_term);
135433d6423SLionel Sambuc 
136433d6423SLionel Sambuc   /* Let SEF perform startup. */
137433d6423SLionel Sambuc   sef_startup();
138433d6423SLionel Sambuc }
139433d6423SLionel Sambuc 
140433d6423SLionel Sambuc /*===========================================================================*
141433d6423SLionel Sambuc  *		            sef_cb_init_fresh                                *
142433d6423SLionel Sambuc  *===========================================================================*/
sef_cb_init_fresh(int UNUSED (type),sef_init_info_t * UNUSED (info))143433d6423SLionel Sambuc static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
144433d6423SLionel Sambuc {
145433d6423SLionel Sambuc /* Initialize the printer driver. */
146433d6423SLionel Sambuc 
147433d6423SLionel Sambuc   /* If no printer is present, do not start. */
148433d6423SLionel Sambuc   if (!do_probe())
149433d6423SLionel Sambuc 	return ENODEV;	/* arbitrary error code */
150433d6423SLionel Sambuc 
151433d6423SLionel Sambuc   /* Announce we are up! */
152433d6423SLionel Sambuc   chardriver_announce();
153433d6423SLionel Sambuc 
154433d6423SLionel Sambuc   return OK;
155433d6423SLionel Sambuc }
156433d6423SLionel Sambuc 
157433d6423SLionel Sambuc /*===========================================================================*
158433d6423SLionel Sambuc  *				do_write				     *
159433d6423SLionel Sambuc  *===========================================================================*/
printer_write(devminor_t UNUSED (minor),u64_t UNUSED (position),endpoint_t endpt,cp_grant_id_t grant,size_t size,int flags,cdev_id_t id)160433d6423SLionel Sambuc static ssize_t printer_write(devminor_t UNUSED(minor), u64_t UNUSED(position),
161433d6423SLionel Sambuc 	endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
162433d6423SLionel Sambuc 	cdev_id_t id)
163433d6423SLionel Sambuc {
164433d6423SLionel Sambuc /* The printer is used by sending write requests to it. Process one. */
165433d6423SLionel Sambuc   int retries;
166433d6423SLionel Sambuc   u32_t status;
167433d6423SLionel Sambuc 
168433d6423SLionel Sambuc   /* Reject command if last write is not yet finished, the count is not
169433d6423SLionel Sambuc    * positive, or we're asked not to block.
170433d6423SLionel Sambuc    */
171433d6423SLionel Sambuc   if (writing)			return EIO;
172433d6423SLionel Sambuc   if (size <= 0)		return EINVAL;
173433d6423SLionel Sambuc   if (flags & CDEV_NONBLOCK)	return EAGAIN;	/* not supported */
174433d6423SLionel Sambuc 
175433d6423SLionel Sambuc   /* If no errors occurred, continue printing with the caller.
176433d6423SLionel Sambuc    * First wait until the printer is online to prevent stupid errors.
177433d6423SLionel Sambuc    */
178433d6423SLionel Sambuc   caller = endpt;
179433d6423SLionel Sambuc   user_left = size;
180433d6423SLionel Sambuc   orig_count = size;
181433d6423SLionel Sambuc   user_vir_d = 0;	/* Offset. */
182433d6423SLionel Sambuc   writing = TRUE;
183433d6423SLionel Sambuc   grant_nr = grant;
184433d6423SLionel Sambuc   write_id = id;
185433d6423SLionel Sambuc 
186433d6423SLionel Sambuc   retries = MAX_ONLINE_RETRIES + 1;
187433d6423SLionel Sambuc   while (--retries > 0) {
188433d6423SLionel Sambuc         if (sys_inb(port_base + 1, &status) != OK) {
189433d6423SLionel Sambuc 		printf("printer: sys_inb of %x failed\n", port_base+1);
190433d6423SLionel Sambuc 		panic("sys_inb failed");
191433d6423SLionel Sambuc 	}
192433d6423SLionel Sambuc 	if (status & ON_LINE) {		/* printer online! */
193433d6423SLionel Sambuc 		prepare_output();
194433d6423SLionel Sambuc 		printer_intr(0);
195433d6423SLionel Sambuc 		return EDONTREPLY;	/* we may already have sent a reply */
196433d6423SLionel Sambuc 	}
197433d6423SLionel Sambuc 	micro_delay(500000);		/* wait before retry */
198433d6423SLionel Sambuc   }
199433d6423SLionel Sambuc   /* If we reach this point, the printer was not online in time. */
200433d6423SLionel Sambuc   done_status = status;
201433d6423SLionel Sambuc   output_done();
202433d6423SLionel Sambuc   return EDONTREPLY;
203433d6423SLionel Sambuc }
204433d6423SLionel Sambuc 
205433d6423SLionel Sambuc /*===========================================================================*
206433d6423SLionel Sambuc  *				output_done				     *
207433d6423SLionel Sambuc  *===========================================================================*/
output_done()208433d6423SLionel Sambuc static void output_done()
209433d6423SLionel Sambuc {
210433d6423SLionel Sambuc /* Previous chunk of printing is finished.  Continue if OK and more.
211433d6423SLionel Sambuc  * Otherwise, reply to caller (FS).
212433d6423SLionel Sambuc  */
213433d6423SLionel Sambuc   int status;
214433d6423SLionel Sambuc 
215433d6423SLionel Sambuc   if (!writing) return;	  	/* probably leftover interrupt */
216433d6423SLionel Sambuc   if (done_status != OK) {      	/* printer error occurred */
217433d6423SLionel Sambuc 	status = EIO;
218433d6423SLionel Sambuc 	if ((done_status & ON_LINE) == 0) {
219433d6423SLionel Sambuc 	    printf("Printer is not on line\n");
220433d6423SLionel Sambuc 	} else if ((done_status & NO_PAPER)) {
221433d6423SLionel Sambuc 	    printf("Printer is out of paper\n");
222433d6423SLionel Sambuc 	    status = EAGAIN;
223433d6423SLionel Sambuc 	} else {
224433d6423SLionel Sambuc 	    printf("Printer error, status is 0x%02X\n", done_status);
225433d6423SLionel Sambuc 	}
226433d6423SLionel Sambuc 	/* Some characters have been printed, tell how many. */
227433d6423SLionel Sambuc 	if (status == EAGAIN && user_left < orig_count) {
228433d6423SLionel Sambuc 		status = orig_count - user_left;
229433d6423SLionel Sambuc 	}
230433d6423SLionel Sambuc 	oleft = 0;			/* cancel further output */
231433d6423SLionel Sambuc   } else if (user_left != 0) {		/* not yet done, continue! */
232433d6423SLionel Sambuc 	prepare_output();
233433d6423SLionel Sambuc 	return;
234433d6423SLionel Sambuc   } else {				/* done! report back to FS */
235433d6423SLionel Sambuc 	status = orig_count;
236433d6423SLionel Sambuc   }
237433d6423SLionel Sambuc 
238433d6423SLionel Sambuc   chardriver_reply_task(caller, write_id, status);
239433d6423SLionel Sambuc 
240433d6423SLionel Sambuc   writing = FALSE;			/* unmark event */
241433d6423SLionel Sambuc }
242433d6423SLionel Sambuc 
243433d6423SLionel Sambuc /*===========================================================================*
244433d6423SLionel Sambuc  *				printer_cancel				     *
245433d6423SLionel Sambuc  *===========================================================================*/
printer_cancel(devminor_t UNUSED (minor),endpoint_t endpt,cdev_id_t id)246433d6423SLionel Sambuc static int printer_cancel(devminor_t UNUSED(minor), endpoint_t endpt,
247433d6423SLionel Sambuc 	cdev_id_t id)
248433d6423SLionel Sambuc {
249433d6423SLionel Sambuc /* Cancel a print request that has already started.  Usually this means that
250433d6423SLionel Sambuc  * the process doing the printing has been killed by a signal.  It is not
251433d6423SLionel Sambuc  * clear if there are race conditions.  Try not to cancel the wrong process,
252433d6423SLionel Sambuc  * but rely on VFS to handle the EINTR reply and de-suspension properly.
253433d6423SLionel Sambuc  */
254433d6423SLionel Sambuc 
255433d6423SLionel Sambuc   if (writing && caller == endpt && write_id == id) {
256433d6423SLionel Sambuc 	oleft = 0;		/* cancel output by interrupt handler */
257433d6423SLionel Sambuc 	writing = FALSE;
258433d6423SLionel Sambuc 	return EINTR;
259433d6423SLionel Sambuc   }
260433d6423SLionel Sambuc   return EDONTREPLY;
261433d6423SLionel Sambuc }
262433d6423SLionel Sambuc 
263433d6423SLionel Sambuc /*===========================================================================*
264433d6423SLionel Sambuc  *				do_probe				     *
265433d6423SLionel Sambuc  *===========================================================================*/
do_probe(void)266433d6423SLionel Sambuc static int do_probe(void)
267433d6423SLionel Sambuc {
268433d6423SLionel Sambuc /* See if there is a printer at all. */
269433d6423SLionel Sambuc 
270433d6423SLionel Sambuc   /* Get the base port for first printer. */
271433d6423SLionel Sambuc   if(sys_readbios(LPT1_IO_PORT_ADDR, &port_base, LPT1_IO_PORT_SIZE) != OK) {
272433d6423SLionel Sambuc 	panic("do_probe: sys_readbios failed");
273433d6423SLionel Sambuc   }
274433d6423SLionel Sambuc 
275433d6423SLionel Sambuc   /* If the port is zero, the parallel port is not available at all. */
276433d6423SLionel Sambuc   return (port_base != 0);
277433d6423SLionel Sambuc }
278433d6423SLionel Sambuc 
279433d6423SLionel Sambuc /*===========================================================================*
280433d6423SLionel Sambuc  *				do_initialize				     *
281433d6423SLionel Sambuc  *===========================================================================*/
do_initialize()282433d6423SLionel Sambuc static void do_initialize()
283433d6423SLionel Sambuc {
284433d6423SLionel Sambuc /* Set global variables and initialize the printer. */
285433d6423SLionel Sambuc   if(sys_outb(port_base + 2, INIT_PRINTER) != OK) {
286433d6423SLionel Sambuc 	printf("printer: sys_outb of %x failed\n", port_base+2);
287433d6423SLionel Sambuc 	panic("do_initialize: sys_outb init failed");
288433d6423SLionel Sambuc   }
289433d6423SLionel Sambuc   micro_delay(1000000/20);	/* easily satisfies Centronics minimum */
290433d6423SLionel Sambuc   if(sys_outb(port_base + 2, PR_SELECT) != OK) {
291433d6423SLionel Sambuc 	printf("printer: sys_outb of %x failed\n", port_base+2);
292433d6423SLionel Sambuc 	panic("do_initialize: sys_outb select failed");
293433d6423SLionel Sambuc   }
294433d6423SLionel Sambuc   irq_hook_id = 0;
295433d6423SLionel Sambuc   if(sys_irqsetpolicy(PRINTER_IRQ, 0, &irq_hook_id) != OK ||
296433d6423SLionel Sambuc      sys_irqenable(&irq_hook_id) != OK) {
297433d6423SLionel Sambuc 	panic("do_initialize: irq enabling failed");
298433d6423SLionel Sambuc   }
299433d6423SLionel Sambuc }
300433d6423SLionel Sambuc 
301433d6423SLionel Sambuc /*==========================================================================*
302433d6423SLionel Sambuc  *		    	      printer_open				    *
303433d6423SLionel Sambuc  *==========================================================================*/
printer_open(devminor_t UNUSED (minor),int UNUSED (access),endpoint_t UNUSED (user_endpt))304433d6423SLionel Sambuc static int printer_open(devminor_t UNUSED(minor), int UNUSED(access),
305433d6423SLionel Sambuc 	endpoint_t UNUSED(user_endpt))
306433d6423SLionel Sambuc {
307433d6423SLionel Sambuc /* Initialize on first open. */
308433d6423SLionel Sambuc   static int initialized = FALSE;
309433d6423SLionel Sambuc 
310433d6423SLionel Sambuc   if (!initialized) {
311433d6423SLionel Sambuc 	do_initialize();
312433d6423SLionel Sambuc 
313433d6423SLionel Sambuc 	initialized = TRUE;
314433d6423SLionel Sambuc   }
315433d6423SLionel Sambuc 
316433d6423SLionel Sambuc   return OK;
317433d6423SLionel Sambuc }
318433d6423SLionel Sambuc 
319433d6423SLionel Sambuc /*==========================================================================*
320433d6423SLionel Sambuc  *		    	      prepare_output				    *
321433d6423SLionel Sambuc  *==========================================================================*/
prepare_output()322433d6423SLionel Sambuc static void prepare_output()
323433d6423SLionel Sambuc {
324433d6423SLionel Sambuc /* Start next chunk of printer output. Fetch the data from user space. */
325433d6423SLionel Sambuc   int s;
326433d6423SLionel Sambuc   register int chunk;
327433d6423SLionel Sambuc 
328433d6423SLionel Sambuc   if ( (chunk = user_left) > sizeof obuf) chunk = sizeof obuf;
329433d6423SLionel Sambuc 
330433d6423SLionel Sambuc   s=sys_safecopyfrom(caller, grant_nr, user_vir_d, (vir_bytes) obuf,
331433d6423SLionel Sambuc 	chunk);
332433d6423SLionel Sambuc 
333433d6423SLionel Sambuc   if(s != OK) {
334433d6423SLionel Sambuc   	done_status = EFAULT;
335433d6423SLionel Sambuc   	output_done();
336433d6423SLionel Sambuc   	return;
337433d6423SLionel Sambuc   }
338433d6423SLionel Sambuc   optr = obuf;
339433d6423SLionel Sambuc   oleft = chunk;
340433d6423SLionel Sambuc }
341433d6423SLionel Sambuc 
342433d6423SLionel Sambuc /*===========================================================================*
343433d6423SLionel Sambuc  *				printer_intr				     *
344433d6423SLionel Sambuc  *===========================================================================*/
printer_intr(unsigned int UNUSED (mask))345433d6423SLionel Sambuc static void printer_intr(unsigned int UNUSED(mask))
346433d6423SLionel Sambuc {
347433d6423SLionel Sambuc /* This function does the actual output to the printer. This is called on an
348433d6423SLionel Sambuc  * interrupt message sent from the generic interrupt handler that 'forwards'
349433d6423SLionel Sambuc  * interrupts to this driver. The generic handler did not reenable the printer
350433d6423SLionel Sambuc  * IRQ yet!
351433d6423SLionel Sambuc  */
352433d6423SLionel Sambuc 
353433d6423SLionel Sambuc   u32_t status;
354433d6423SLionel Sambuc   pvb_pair_t char_out[3];
355433d6423SLionel Sambuc 
356433d6423SLionel Sambuc   if (oleft == 0) {
357433d6423SLionel Sambuc 	/* Nothing more to print.  Turn off printer interrupts in case they
358433d6423SLionel Sambuc 	 * are level-sensitive as on the PS/2.  This should be safe even
359433d6423SLionel Sambuc 	 * when the printer is busy with a previous character, because the
360433d6423SLionel Sambuc 	 * interrupt status does not affect the printer.
361433d6423SLionel Sambuc 	 */
362433d6423SLionel Sambuc 	if(sys_outb(port_base + 2, PR_SELECT) != OK) {
363433d6423SLionel Sambuc 		printf("printer: sys_outb of %x failed\n", port_base+2);
364433d6423SLionel Sambuc 		panic("sys_outb failed");
365433d6423SLionel Sambuc 	}
366433d6423SLionel Sambuc 	if(sys_irqenable(&irq_hook_id) != OK) {
367433d6423SLionel Sambuc 		panic("sys_irqenable failed");
368433d6423SLionel Sambuc 	}
369433d6423SLionel Sambuc 	return;
370433d6423SLionel Sambuc   }
371433d6423SLionel Sambuc 
372433d6423SLionel Sambuc   do {
373433d6423SLionel Sambuc 	/* Loop to handle fast (buffered) printers.  It is important that
374433d6423SLionel Sambuc 	 * processor interrupts are not disabled here, just printer interrupts.
375433d6423SLionel Sambuc 	 */
376433d6423SLionel Sambuc 	if(sys_inb(port_base + 1, &status) != OK) {
377433d6423SLionel Sambuc 		printf("printer: sys_inb of %x failed\n", port_base+1);
378433d6423SLionel Sambuc 		panic("sys_inb failed");
379433d6423SLionel Sambuc 	}
380433d6423SLionel Sambuc 	if ((status & STATUS_MASK) == BUSY_STATUS) {
381433d6423SLionel Sambuc 		/* Still busy with last output.  This normally happens
382433d6423SLionel Sambuc 		 * immediately after doing output to an unbuffered or slow
383433d6423SLionel Sambuc 		 * printer.  It may happen after a call from prepare_output or
384433d6423SLionel Sambuc 		 * pr_restart, since they are not synchronized with printer
385433d6423SLionel Sambuc 		 * interrupts.  It may happen after a spurious interrupt.
386433d6423SLionel Sambuc 		 */
387433d6423SLionel Sambuc 		if(sys_irqenable(&irq_hook_id) != OK) {
388433d6423SLionel Sambuc 			panic("sys_irqenable failed");
389433d6423SLionel Sambuc 		}
390433d6423SLionel Sambuc 		return;
391433d6423SLionel Sambuc 	}
392433d6423SLionel Sambuc 	if ((status & STATUS_MASK) == NORMAL_STATUS) {
393433d6423SLionel Sambuc 		/* Everything is all right.  Output another character. */
394433d6423SLionel Sambuc 		pv_set(char_out[0], port_base, *optr);
395433d6423SLionel Sambuc 		optr++;
396433d6423SLionel Sambuc 		pv_set(char_out[1], port_base+2, ASSERT_STROBE);
397433d6423SLionel Sambuc 		pv_set(char_out[2], port_base+2, NEGATE_STROBE);
398433d6423SLionel Sambuc 		if(sys_voutb(char_out, 3) != OK) {
399433d6423SLionel Sambuc 			/* request series of port outb */
400433d6423SLionel Sambuc 			panic("sys_voutb failed");
401433d6423SLionel Sambuc 		}
402433d6423SLionel Sambuc 
403433d6423SLionel Sambuc 		user_vir_d++;
404433d6423SLionel Sambuc 		user_left--;
405433d6423SLionel Sambuc 	} else {
406433d6423SLionel Sambuc 		/* Error.  This would be better ignored (treat as busy). */
407433d6423SLionel Sambuc 		done_status = status;
408433d6423SLionel Sambuc 		output_done();
409433d6423SLionel Sambuc 		if(sys_irqenable(&irq_hook_id) != OK) {
410433d6423SLionel Sambuc 			panic("sys_irqenable failed");
411433d6423SLionel Sambuc 		}
412433d6423SLionel Sambuc 		return;
413433d6423SLionel Sambuc 	}
414433d6423SLionel Sambuc   }
415433d6423SLionel Sambuc   while (--oleft != 0);
416433d6423SLionel Sambuc 
417433d6423SLionel Sambuc   /* Finished printing chunk OK. */
418433d6423SLionel Sambuc   done_status = OK;
419433d6423SLionel Sambuc   output_done();
420433d6423SLionel Sambuc   if(sys_irqenable(&irq_hook_id) != OK) {
421433d6423SLionel Sambuc 	panic("sys_irqenable failed");
422433d6423SLionel Sambuc   }
423433d6423SLionel Sambuc }
424433d6423SLionel Sambuc 
425