00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <minix/endpoint.h>
00036 #include "../drivers.h"
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 #define ASSERT_STROBE 0x1D
00056 #define NEGATE_STROBE 0x1C
00057 #define PR_SELECT 0x0C
00058 #define INIT_PRINTER 0x08
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 #define BUSY_STATUS 0x10
00069 #define NO_PAPER 0x20
00070 #define NORMAL_STATUS 0x90
00071 #define ON_LINE 0x10
00072 #define STATUS_MASK 0xB0
00073
00074 #define MAX_ONLINE_RETRIES 120
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088 PRIVATE int caller;
00089 PRIVATE int revive_pending;
00090 PRIVATE int revive_status;
00091 PRIVATE int done_status;
00092 PRIVATE int oleft;
00093 PRIVATE unsigned char obuf[128];
00094 PRIVATE unsigned char *optr;
00095 PRIVATE int orig_count;
00096 PRIVATE int port_base;
00097 PRIVATE int proc_nr;
00098 PRIVATE cp_grant_id_t grant_nr;
00099 PRIVATE int user_left;
00100 PRIVATE vir_bytes user_vir_g;
00101 PRIVATE vir_bytes user_vir_d;
00102 PRIVATE int user_safe;
00103 PUBLIC int writing;
00104 PRIVATE int irq_hook_id;
00105
00106 extern int errno;
00107
00108 FORWARD _PROTOTYPE( void do_cancel, (message *m_ptr) );
00109 FORWARD _PROTOTYPE( void output_done, (void) );
00110 FORWARD _PROTOTYPE( void do_write, (message *m_ptr, int safe) );
00111 FORWARD _PROTOTYPE( void do_status, (message *m_ptr) );
00112 FORWARD _PROTOTYPE( void prepare_output, (void) );
00113 FORWARD _PROTOTYPE( void do_initialize, (void) );
00114 FORWARD _PROTOTYPE( void reply, (int code,int replyee,int proc,int status));
00115 FORWARD _PROTOTYPE( void do_printer_output, (void) );
00116 FORWARD _PROTOTYPE( void do_signal, (void) );
00117
00118
00119 FORWARD _PROTOTYPE( void sef_local_startup, (void) );
00120 FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
00121 EXTERN _PROTOTYPE( void sef_cb_lu_prepare, (int state) );
00122 EXTERN _PROTOTYPE( int sef_cb_lu_state_isvalid, (int state) );
00123 EXTERN _PROTOTYPE( void sef_cb_lu_state_dump, (int state) );
00124 PUBLIC int is_status_msg_expected = FALSE;
00125
00126
00127
00128
00129 PUBLIC void main(void)
00130 {
00131
00132 message pr_mess;
00133
00134
00135 sef_local_startup();
00136
00137 while (TRUE) {
00138 sef_receive(ANY, &pr_mess);
00139
00140 if (is_notify(pr_mess.m_type)) {
00141 switch (_ENDPOINT_P(pr_mess.m_source)) {
00142 case HARDWARE:
00143 do_printer_output();
00144 break;
00145 case PM_PROC_NR:
00146 do_signal();
00147 break;
00148 default:
00149 reply(TASK_REPLY, pr_mess.m_source,
00150 pr_mess.IO_ENDPT, EINVAL);
00151 }
00152 continue;
00153 }
00154
00155 switch(pr_mess.m_type) {
00156 case DEV_OPEN:
00157 do_initialize();
00158
00159 case DEV_CLOSE:
00160 reply(TASK_REPLY, pr_mess.m_source, pr_mess.IO_ENDPT, OK);
00161 break;
00162 case DEV_WRITE_S: do_write(&pr_mess, 1); break;
00163 case DEV_STATUS: do_status(&pr_mess); break;
00164 case CANCEL: do_cancel(&pr_mess); break;
00165 default:
00166 reply(TASK_REPLY, pr_mess.m_source, pr_mess.IO_ENDPT, EINVAL);
00167 }
00168 }
00169 }
00170
00171
00172
00173
00174 PRIVATE void sef_local_startup()
00175 {
00176
00177 sef_setcb_init_fresh(sef_cb_init_fresh);
00178 sef_setcb_init_lu(sef_cb_init_fresh);
00179 sef_setcb_init_restart(sef_cb_init_fresh);
00180
00181
00182 sef_setcb_lu_prepare(sef_cb_lu_prepare);
00183 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid);
00184 sef_setcb_lu_state_dump(sef_cb_lu_state_dump);
00185
00186
00187 sef_startup();
00188 }
00189
00190
00191
00192
00193 PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
00194 {
00195
00196 struct sigaction sa;
00197
00198
00199 sa.sa_handler = SIG_MESS;
00200 sigemptyset(&sa.sa_mask);
00201 sa.sa_flags = 0;
00202 if (sigaction(SIGTERM,&sa,NULL)<0) panic("PRN","sigaction failed", errno);
00203
00204 return(OK);
00205 }
00206
00207
00208
00209
00210 PRIVATE void do_signal()
00211 {
00212 sigset_t sigset;
00213
00214 if (getsigset(&sigset) != 0) return;
00215
00216
00217 if (sigismember(&sigset, SIGTERM)) {
00218 exit(0);
00219 }
00220
00221 }
00222
00223
00224
00225
00226 PRIVATE void do_write(m_ptr, safe)
00227 register message *m_ptr;
00228 int safe;
00229 {
00230
00231
00232 register int r = SUSPEND;
00233 int retries;
00234 unsigned long status;
00235
00236
00237
00238
00239 if (writing) r = EIO;
00240 else if (m_ptr->COUNT <= 0) r = EINVAL;
00241
00242
00243 reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, r);
00244
00245
00246
00247
00248 if (SUSPEND == r) {
00249 caller = m_ptr->m_source;
00250 proc_nr = m_ptr->IO_ENDPT;
00251 user_left = m_ptr->COUNT;
00252 orig_count = m_ptr->COUNT;
00253 user_vir_g = (vir_bytes) m_ptr->ADDRESS;
00254 user_vir_d = 0;
00255 user_safe = safe;
00256 writing = TRUE;
00257 grant_nr = safe ? (cp_grant_id_t) m_ptr->ADDRESS : GRANT_INVALID;
00258
00259 retries = MAX_ONLINE_RETRIES + 1;
00260 while (--retries > 0) {
00261 if(sys_inb(port_base + 1, &status) != OK) {
00262 printf("printer: sys_inb of %x failed\n", port_base+1);
00263 panic(__FILE__,"sys_inb failed", NO_NUM);
00264 }
00265 if ((status & ON_LINE)) {
00266 prepare_output();
00267 do_printer_output();
00268 return;
00269 }
00270 micro_delay(500000);
00271 }
00272
00273 done_status = status;
00274 output_done();
00275 }
00276 }
00277
00278
00279
00280
00281 PRIVATE void output_done()
00282 {
00283
00284
00285
00286 register int status;
00287
00288 if (!writing) return;
00289 if (done_status != OK) {
00290 status = EIO;
00291 if ((done_status & ON_LINE) == 0) {
00292 printf("Printer is not on line\n");
00293 } else if ((done_status & NO_PAPER)) {
00294 printf("Printer is out of paper\n");
00295 status = EAGAIN;
00296 } else {
00297 printf("Printer error, status is 0x%02X\n", done_status);
00298 }
00299
00300 if (status == EAGAIN && user_left < orig_count) {
00301 status = orig_count - user_left;
00302 }
00303 oleft = 0;
00304 }
00305 else if (user_left != 0) {
00306 prepare_output();
00307 return;
00308 }
00309 else {
00310 status = orig_count;
00311 }
00312 is_status_msg_expected = TRUE;
00313 revive_pending = TRUE;
00314 revive_status = status;
00315 notify(caller);
00316 }
00317
00318
00319
00320
00321 PRIVATE void do_status(m_ptr)
00322 register message *m_ptr;
00323 {
00324 if (revive_pending) {
00325 m_ptr->m_type = DEV_REVIVE;
00326 m_ptr->REP_ENDPT = proc_nr;
00327 m_ptr->REP_STATUS = revive_status;
00328 m_ptr->REP_IO_GRANT = grant_nr;
00329
00330 writing = FALSE;
00331 revive_pending = FALSE;
00332 } else {
00333 m_ptr->m_type = DEV_NO_STATUS;
00334
00335 is_status_msg_expected = FALSE;
00336 }
00337 send(m_ptr->m_source, m_ptr);
00338 }
00339
00340
00341
00342
00343 PRIVATE void do_cancel(m_ptr)
00344 register message *m_ptr;
00345 {
00346
00347
00348
00349
00350
00351
00352 if (writing && m_ptr->IO_ENDPT == proc_nr) {
00353 oleft = 0;
00354 writing = FALSE;
00355 revive_pending = FALSE;
00356 }
00357 reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EINTR);
00358 }
00359
00360
00361
00362
00363 PRIVATE void reply(code, replyee, process, status)
00364 int code;
00365 int replyee;
00366 int process;
00367 int status;
00368 {
00369
00370
00371 message pr_mess;
00372
00373 pr_mess.m_type = code;
00374 pr_mess.REP_STATUS = status;
00375 pr_mess.REP_ENDPT = process;
00376 send(replyee, &pr_mess);
00377 }
00378
00379
00380
00381
00382 PRIVATE void do_initialize()
00383 {
00384
00385 static int initialized = FALSE;
00386 if (initialized) return;
00387 initialized = TRUE;
00388
00389
00390 if(sys_vircopy(SELF, BIOS_SEG, LPT1_IO_PORT_ADDR,
00391 SELF, D, (vir_bytes) &port_base, LPT1_IO_PORT_SIZE) != OK) {
00392 panic(__FILE__, "do_initialize: sys_vircopy failed", NO_NUM);
00393 }
00394 if(sys_outb(port_base + 2, INIT_PRINTER) != OK) {
00395 printf("printer: sys_outb of %x failed\n", port_base+2);
00396 panic(__FILE__, "do_initialize: sys_outb init failed", NO_NUM);
00397 }
00398 micro_delay(1000000/20);
00399 if(sys_outb(port_base + 2, PR_SELECT) != OK) {
00400 printf("printer: sys_outb of %x failed\n", port_base+2);
00401 panic(__FILE__, "do_initialize: sys_outb select failed", NO_NUM);
00402 }
00403 irq_hook_id = 0;
00404 if(sys_irqsetpolicy(PRINTER_IRQ, 0, &irq_hook_id) != OK ||
00405 sys_irqenable(&irq_hook_id) != OK) {
00406 panic(__FILE__, "do_initialize: irq enabling failed", NO_NUM);
00407 }
00408 }
00409
00410
00411
00412
00413 PRIVATE void prepare_output()
00414 {
00415
00416 int s;
00417 register int chunk;
00418
00419 if ( (chunk = user_left) > sizeof obuf) chunk = sizeof obuf;
00420 if(user_safe) {
00421 s=sys_safecopyfrom(proc_nr, user_vir_g, user_vir_d,
00422 (vir_bytes) obuf, chunk, D);
00423 } else {
00424 s=sys_datacopy(proc_nr, user_vir_g, SELF, (vir_bytes) obuf, chunk);
00425 }
00426
00427 if(s != OK) {
00428 done_status = EFAULT;
00429 output_done();
00430 return;
00431 }
00432 optr = obuf;
00433 oleft = chunk;
00434 }
00435
00436
00437
00438
00439 PRIVATE void do_printer_output()
00440 {
00441
00442
00443
00444
00445
00446
00447 unsigned long status;
00448 pvb_pair_t char_out[3];
00449
00450 if (oleft == 0) {
00451
00452
00453
00454
00455
00456 if(sys_outb(port_base + 2, PR_SELECT) != OK) {
00457 printf("printer: sys_outb of %x failed\n", port_base+2);
00458 panic(__FILE__,"sys_outb failed", NO_NUM);
00459 }
00460 if(sys_irqenable(&irq_hook_id) != OK) {
00461 panic(__FILE__,"sys_irqenable failed", NO_NUM);
00462 }
00463 return;
00464 }
00465
00466 do {
00467
00468
00469
00470 if(sys_inb(port_base + 1, &status) != OK) {
00471 printf("printer: sys_inb of %x failed\n", port_base+1);
00472 panic(__FILE__,"sys_inb failed", NO_NUM);
00473 }
00474 if ((status & STATUS_MASK) == BUSY_STATUS) {
00475
00476
00477
00478
00479
00480
00481 if(sys_irqenable(&irq_hook_id) != OK) {
00482 panic(__FILE__, "sys_irqenable failed\n", NO_NUM);
00483 }
00484 return;
00485 }
00486 if ((status & STATUS_MASK) == NORMAL_STATUS) {
00487
00488 pv_set(char_out[0], port_base, *optr);
00489 optr++;
00490 pv_set(char_out[1], port_base+2, ASSERT_STROBE);
00491 pv_set(char_out[2], port_base+2, NEGATE_STROBE);
00492 if(sys_voutb(char_out, 3) != OK) {
00493
00494 panic(__FILE__, "sys_voutb failed\n", NO_NUM);
00495 }
00496
00497 user_vir_d++;
00498 user_left--;
00499 } else {
00500
00501 done_status = status;
00502 output_done();
00503 if(sys_irqenable(&irq_hook_id) != OK) {
00504 panic(__FILE__, "sys_irqenable failed\n", NO_NUM);
00505 }
00506 return;
00507 }
00508 }
00509 while (--oleft != 0);
00510
00511
00512 done_status = OK;
00513 output_done();
00514 if(sys_irqenable(&irq_hook_id) != OK) {
00515 panic(__FILE__, "sys_irqenable failed\n", NO_NUM);
00516 }
00517 }
00518