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