hal_parport.c
1 /******************************************************************** 2 * Description: hal_parport.c 3 * This file, 'hal_parport.c', is a HAL component that 4 * provides a driver for the standard PC parallel port. 5 * 6 * Author: John Kasunich 7 * License: GPL Version 2 8 * 9 * Copyright (c) 2003 All rights reserved. 10 * 11 * Last change: 12 ********************************************************************/ 13 14 /** This file, 'hal_parport.c', is a HAL component that provides a 15 driver for the standard PC parallel port. 16 17 It supports up to eight parallel ports, and if the port hardware 18 is bidirectional, the eight data bits can be configured as inputs 19 or outputs. 20 21 The configuration is determined by command line arguments for the 22 user space version of the driver, and by a config string passed 23 to insmod for the realtime version. The format is similar for 24 both, and consists of a port address, followed by an optional 25 direction, repeated for each port. The direction is either "in" 26 or "out" and determines the direction of the 8 bit data port. 27 The default is out. The 5 bits of the status port are always 28 inputs, and the 4 bits of the control port are always outputs. 29 Example command lines are as follows: 30 31 user: hal_parport 378 in 278 32 realtime: insmod hal_parport.o cfg="378 in 278" 33 34 Both of these commands install the driver and configure parports 35 at base addresses 0x0378 (using data port as input) and 0x0278 36 (using data port as output). 37 38 The driver creates HAL pins and parameters for each port pin 39 as follows: 40 Each physical output has a correspinding HAL pin, named 41 'parport.<portnum>.pin-<pinnum>-out', and a HAL parameter 42 'parport.<portnum>.pin-<pinnum>-out-invert'. 43 Each physical input has two corresponding HAL pins, named 44 'parport.<portnum>.pin-<pinnum>-in' and 45 'parport.<portnum>.pin-<pinnum>-in-not'. 46 47 <portnum> is the port number, starting from zero. <pinnum> is 48 the physical pin number on the DB-25 connector. 49 50 The realtime version of the driver exports two HAL functions for 51 each port, 'parport.<portnum>.read' and 'parport.<portnum>.write'. 52 It also exports two additional functions, 'parport.read-all' and 53 'parport.write-all'. Any or all of these functions can be added 54 to realtime HAL threads to update the port data periodically. 55 56 The user space version of the driver cannot export functions, 57 instead it exports parameters with the same names. The main() 58 function sits in a loop checking the parameters. If they are 59 zero, it does nothing. If any parameter is greater than zero, 60 the corresponding function runs once, then the parameter is 61 reset to zero. If any parameter is less than zero, the 62 corresponding function runs on every pass through the loop. 63 The driver will loop forever, until it receives either 64 SIGINT (ctrl-C) or SIGTERM, at which point it cleans up and 65 exits. 66 67 */ 68 69 /** Copyright (C) 2003 John Kasunich 70 <jmkasunich AT users DOT sourceforge DOT net> 71 */ 72 73 /** This program is free software; you can redistribute it and/or 74 modify it under the terms of version 2 of the GNU General 75 Public License as published by the Free Software Foundation. 76 This library is distributed in the hope that it will be useful, 77 but WITHOUT ANY WARRANTY; without even the implied warranty of 78 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 79 GNU General Public License for more details. 80 81 You should have received a copy of the GNU General Public 82 License along with this library; if not, write to the Free Software 83 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 84 85 THE AUTHORS OF THIS LIBRARY ACCEPT ABSOLUTELY NO LIABILITY FOR 86 ANY HARM OR LOSS RESULTING FROM ITS USE. IT IS _EXTREMELY_ UNWISE 87 TO RELY ON SOFTWARE ALONE FOR SAFETY. Any machinery capable of 88 harming persons must have provisions for completely removing power 89 from all motors, etc, before persons enter any danger area. All 90 machinery must be designed to comply with local and national safety 91 codes, and the authors of this software can not, and do not, take 92 any responsibility for such compliance. 93 94 This code was written as part of the EMC HAL project. For more 95 information, go to www.linuxcnc.org. 96 */ 97 98 #include "rtapi.h" /* RTAPI realtime OS API */ 99 #include "rtapi_ctype.h" /* isspace() */ 100 #include "rtapi_app.h" /* RTAPI realtime module decls */ 101 102 #include "hal.h" /* HAL public API decls */ 103 104 /* If FASTIO is defined, uses outb() and inb() from <asm.io>, 105 instead of rtapi_outb() and rtapi_inb() - the <asm.io> ones 106 are inlined, and save a microsecond or two (on my 233MHz box) 107 */ 108 #include <rtapi_io.h> 109 110 #include "hal_parport.h" 111 112 /* module information */ 113 MODULE_AUTHOR("John Kasunich"); 114 MODULE_DESCRIPTION("Parallel Port Driver for EMC HAL"); 115 MODULE_LICENSE("GPL"); 116 static char *cfg = "0x0278"; /* config string, default 1 output port at 278 */ 117 RTAPI_MP_STRING(cfg, "config string"); 118 119 /*********************************************************************** 120 * STRUCTURES AND GLOBAL VARIABLES * 121 ************************************************************************/ 122 123 /* this structure contains the runtime data needed by the 124 parallel port driver for a single port 125 */ 126 127 typedef struct { 128 unsigned short base_addr; /* base I/O address (0x378, etc.) */ 129 unsigned char data_dir; /* non-zero if pins 2-9 are input */ 130 unsigned char use_control_in; /* non-zero if pins 1, 4, 16, 17 are input */ 131 hal_bit_t *status_in[10]; /* ptrs for in pins 15, 13, 12, 10, 11 */ 132 hal_bit_t *data_in[16]; /* ptrs for input pins 2 - 9 */ 133 hal_bit_t *data_out[8]; /* ptrs for output pins 2 - 9 */ 134 hal_bit_t data_inv[8]; /* polarity params for output pins 2 - 9 */ 135 hal_bit_t data_reset[8]; /* reset flag for output pins 2 - 9 */ 136 hal_bit_t *control_in[8]; /* ptrs for in pins 1, 14, 16, 17 */ 137 hal_bit_t *control_out[4]; /* ptrs for out pins 1, 14, 16, 17 */ 138 hal_bit_t control_inv[4]; /* pol. params for output pins 1, 14, 16, 17 */ 139 hal_bit_t control_reset[4]; /* reset flag for output pins 1, 14, 16, 17 */ 140 hal_u32_t reset_time; /* min ns between write and reset */ 141 hal_u32_t debug1, debug2; 142 long long write_time; 143 unsigned char outdata; 144 unsigned char reset_mask; /* reset flag for pin 2..9 */ 145 unsigned char reset_val; /* reset values for pin 2..9 */ 146 long long write_time_ctrl; 147 unsigned char outdata_ctrl; 148 unsigned char reset_mask_ctrl; /* reset flag for pin 1, 14, 16, 17 */ 149 unsigned char reset_val_ctrl; /* reset values for pin 1, 14, 16, 17 */ 150 struct hal_parport_t portdata; 151 } parport_t; 152 153 /* pointer to array of parport_t structs in shared memory, 1 per port */ 154 static parport_t *port_data_array; 155 156 /* other globals */ 157 static int comp_id; /* component ID */ 158 static int num_ports; /* number of ports configured */ 159 160 static unsigned long ns2tsc_factor; 161 #define ns2tsc(x) (((x) * (unsigned long long)ns2tsc_factor) >> 12) 162 163 /*********************************************************************** 164 * LOCAL FUNCTION DECLARATIONS * 165 ************************************************************************/ 166 167 /* These are the functions that actually do the I/O 168 everything else is just init code 169 */ 170 171 static void read_port(void *arg, long period); 172 static void reset_port(void *arg, long period); 173 static void write_port(void *arg, long period); 174 static void read_all(void *arg, long period); 175 static void write_all(void *arg, long period); 176 177 /* 'pins_and_params()' does most of the work involved in setting up 178 the driver. It parses the command line (argv[]), then if the 179 command line is OK, it calls hal_init(), allocates shared memory 180 for the parport_t data structure(s), and exports pins and parameters 181 It does not set up functions, since that is handled differently in 182 realtime and user space. 183 */ 184 static int pins_and_params(char *argv[]); 185 186 static unsigned short parse_port_addr(char *cp); 187 static int export_port(int portnum, parport_t * addr); 188 static int export_input_pin(int portnum, int pin, hal_bit_t ** base, int n); 189 static int export_output_pin(int portnum, int pin, hal_bit_t ** dbase, 190 hal_bit_t * pbase, hal_bit_t * rbase, int n); 191 192 /*********************************************************************** 193 * INIT AND EXIT CODE * 194 ************************************************************************/ 195 196 #define MAX_PORTS 8 197 198 #define MAX_TOK ((MAX_PORTS*2)+3) 199 200 int rtapi_app_main(void) 201 { 202 char *cp; 203 char *argv[MAX_TOK]; 204 char name[HAL_NAME_LEN + 1]; 205 int n, retval; 206 207 208 #ifdef __KERNEL__ 209 // this calculation fits in a 32-bit unsigned 210 // as long as CPUs are under about 6GHz 211 ns2tsc_factor = (cpu_khz << 6) / 15625ul; 212 #else 213 ns2tsc_factor = 1ll<<12; 214 #endif 215 216 /* test for config string */ 217 if (cfg == 0) { 218 rtapi_print_msg(RTAPI_MSG_ERR, "PARPORT: ERROR: no config string\n"); 219 return -1; 220 } 221 rtapi_print ( "config string '%s'\n", cfg ); 222 /* as a RT module, we don't get a nice argc/argv command line, we only 223 get a single string... so we need to tokenize it ourselves */ 224 /* in addition, it seems that insmod under kernel 2.6 will truncate 225 a string parameter at the first whitespace. So we allow '_' as 226 an alternate token separator. */ 227 cp = cfg; 228 for (n = 0; n < MAX_TOK; n++) { 229 /* strip leading whitespace */ 230 while ((*cp != '\0') && ( isspace(*cp) || ( *cp == '_') )) 231 cp++; 232 /* mark beginning of token */ 233 argv[n] = cp; 234 /* find end of token */ 235 while ((*cp != '\0') && !( isspace(*cp) || ( *cp == '_') )) 236 cp++; 237 /* mark end of this token, prepare to search for next one */ 238 if (*cp != '\0') { 239 *cp = '\0'; 240 cp++; 241 } 242 } 243 for (n = 0; n < MAX_TOK; n++) { 244 /* is token empty? */ 245 if (argv[n][0] == '\0') { 246 /* yes - make pointer NULL */ 247 argv[n] = NULL; 248 } 249 } 250 /* parse "command line", set up pins and parameters */ 251 retval = pins_and_params(argv); 252 if (retval != 0) { 253 return retval; 254 } 255 /* export functions for each port */ 256 for (n = 0; n < num_ports; n++) { 257 /* make read function name */ 258 rtapi_snprintf(name, sizeof(name), "parport.%d.read", n); 259 /* export read function */ 260 retval = hal_export_funct(name, read_port, &(port_data_array[n]), 261 0, 0, comp_id); 262 if (retval != 0) { 263 rtapi_print_msg(RTAPI_MSG_ERR, 264 "PARPORT: ERROR: port %d read funct export failed\n", n); 265 hal_exit(comp_id); 266 return -1; 267 } 268 /* make write function name */ 269 rtapi_snprintf(name, sizeof(name), "parport.%d.write", n); 270 /* export write function */ 271 retval = hal_export_funct(name, write_port, &(port_data_array[n]), 272 0, 0, comp_id); 273 if (retval != 0) { 274 rtapi_print_msg(RTAPI_MSG_ERR, 275 "PARPORT: ERROR: port %d write funct export failed\n", n); 276 hal_exit(comp_id); 277 return -1; 278 } 279 /* make reset function name */ 280 rtapi_snprintf(name, sizeof(name), "parport.%d.reset", n); 281 /* export write function */ 282 retval = hal_export_funct(name, reset_port, &(port_data_array[n]), 283 0, 0, comp_id); 284 if (retval != 0) { 285 rtapi_print_msg(RTAPI_MSG_ERR, 286 "PARPORT: ERROR: port %d reset funct export failed\n", n); 287 hal_exit(comp_id); 288 return -1; 289 } 290 } 291 /* export functions that read and write all ports */ 292 retval = hal_export_funct("parport.read-all", read_all, 293 port_data_array, 0, 0, comp_id); 294 if (retval != 0) { 295 rtapi_print_msg(RTAPI_MSG_ERR, 296 "PARPORT: ERROR: read all funct export failed\n"); 297 hal_exit(comp_id); 298 return -1; 299 } 300 retval = hal_export_funct("parport.write-all", write_all, 301 port_data_array, 0, 0, comp_id); 302 if (retval != 0) { 303 rtapi_print_msg(RTAPI_MSG_ERR, 304 "PARPORT: ERROR: write all funct export failed\n"); 305 hal_exit(comp_id); 306 return -1; 307 } 308 rtapi_print_msg(RTAPI_MSG_INFO, 309 "PARPORT: installed driver for %d ports\n", num_ports); 310 hal_ready(comp_id); 311 return 0; 312 } 313 314 void rtapi_app_exit(void) 315 { 316 int n; 317 for (n = 0; n < num_ports; n++) { 318 hal_parport_release(&port_data_array[n].portdata); 319 } 320 hal_exit(comp_id); 321 } 322 323 /*********************************************************************** 324 * REALTIME PORT READ AND WRITE FUNCTIONS * 325 ************************************************************************/ 326 327 static void read_port(void *arg, long period) 328 { 329 parport_t *port; 330 int b; 331 unsigned char indata, mask; 332 333 port = arg; 334 /* read the status port */ 335 indata = rtapi_inb(port->base_addr + 1); 336 /* invert bit 7 (pin 11) to compensate for hardware inverter */ 337 indata ^= 0x80; 338 /* split the bits into 10 variables (5 regular, 5 inverted) */ 339 mask = 0x08; 340 for (b = 0; b < 10; b += 2) { 341 *(port->status_in[b]) = indata & mask; 342 *(port->status_in[b + 1]) = !(indata & mask); 343 mask <<= 1; 344 } 345 /* are we using the data port for input? */ 346 if (port->data_dir != 0) { 347 /* yes, read the data port */ 348 indata = rtapi_inb(port->base_addr); 349 /* split the bits into 16 variables (8 regular, 8 inverted) */ 350 mask = 0x01; 351 for (b = 0; b < 16; b += 2) { 352 *(port->data_in[b]) = indata & mask; 353 *(port->data_in[b + 1]) = !(indata & mask); 354 mask <<= 1; 355 } 356 } 357 /* are we using the control port for input? */ 358 if(port->use_control_in) { 359 mask = 0x01; 360 /* correct for hardware inverters on pins 1, 14, & 17 */ 361 indata = rtapi_inb(port->base_addr + 2) ^ 0x0B; 362 for (b = 0; b < 8; b += 2) { 363 *(port->control_in[b]) = indata & mask; 364 *(port->control_in[b + 1]) = !(indata & mask); 365 mask <<= 1; 366 } 367 } 368 } 369 370 static void reset_port(void *arg, long period) { 371 parport_t *port = arg; 372 long long deadline, reset_time_tsc; 373 unsigned char outdata = (port->outdata&~port->reset_mask) ^ port->reset_val; 374 375 if(port->reset_time > period/4) port->reset_time = period/4; 376 reset_time_tsc = ns2tsc(port->reset_time); 377 378 if(outdata != port->outdata) { 379 deadline = port->write_time + reset_time_tsc; 380 while(rtapi_get_clocks() < deadline) {} 381 rtapi_outb(outdata, port->base_addr); 382 } 383 384 outdata = (port->outdata_ctrl&~port->reset_mask_ctrl)^port->reset_val_ctrl; 385 386 if(outdata != port->outdata_ctrl) { 387 /* correct for hardware inverters on pins 1, 14, & 17 */ 388 outdata ^= 0x0B; 389 deadline = port->write_time_ctrl + reset_time_tsc; 390 while(rtapi_get_clocks() < deadline) {} 391 rtapi_outb(outdata, port->base_addr + 2); 392 } 393 } 394 395 static void write_port(void *arg, long period) 396 { 397 parport_t *port; 398 int b; 399 unsigned char outdata, mask; 400 401 port = arg; 402 /* are we using the data port for output? */ 403 if (port->data_dir == 0) { 404 int reset_mask=0, reset_val=0; 405 /* yes */ 406 outdata = 0x00; 407 mask = 0x01; 408 /* assemble output byte for data port from 8 source variables */ 409 for (b = 0; b < 8; b++) { 410 /* get the data, add to output byte */ 411 if ((*(port->data_out[b])) && (!port->data_inv[b])) { 412 outdata |= mask; 413 } 414 if ((!*(port->data_out[b])) && (port->data_inv[b])) { 415 outdata |= mask; 416 } 417 if (port->data_reset[b]) { 418 reset_mask |= mask; 419 if(port->data_inv[b]) reset_val |= mask; 420 } 421 mask <<= 1; 422 } 423 /* write it to the hardware */ 424 rtapi_outb(outdata, port->base_addr); 425 port->write_time = rtapi_get_clocks(); 426 port->reset_val = reset_val; 427 port->reset_mask = reset_mask; 428 port->outdata = outdata; 429 /* prepare to build control port byte, with direction bit clear */ 430 outdata = 0x00; 431 } else { 432 /* prepare to build control port byte, with direction bit set */ 433 outdata = 0x20; 434 } 435 /* are we using the control port for input? */ 436 if (port->use_control_in) { 437 /* yes, force those pins high */ 438 outdata |= 0x0F; 439 } else { 440 int reset_mask=0, reset_val=0; 441 /* no, assemble output byte from 4 source variables */ 442 mask = 0x01; 443 for (b = 0; b < 4; b++) { 444 /* get the data, add to output byte */ 445 if ((*(port->control_out[b])) && (!port->control_inv[b])) { 446 outdata |= mask; 447 } 448 if ((!*(port->control_out[b])) && (port->control_inv[b])) { 449 outdata |= mask; 450 } 451 if (port->control_reset[b]) { 452 reset_mask |= mask; 453 if(port->control_inv[b]) reset_val |= mask; 454 } 455 mask <<= 1; 456 } 457 port->reset_mask_ctrl = reset_mask; 458 port->reset_val_ctrl = reset_val; 459 port->outdata_ctrl = outdata; 460 } 461 /* correct for hardware inverters on pins 1, 14, & 17 */ 462 outdata ^= 0x0B; 463 /* write it to the hardware */ 464 rtapi_outb(outdata, port->base_addr + 2); 465 port->write_time_ctrl = rtapi_get_clocks(); 466 } 467 468 void read_all(void *arg, long period) 469 { 470 parport_t *port; 471 int n; 472 port = arg; 473 for (n = 0; n < num_ports; n++) { 474 read_port(&(port[n]), period); 475 } 476 } 477 478 void write_all(void *arg, long period) 479 { 480 parport_t *port; 481 int n; 482 port = arg; 483 for (n = 0; n < num_ports; n++) { 484 write_port(&(port[n]), period); 485 } 486 } 487 488 /*********************************************************************** 489 * LOCAL FUNCTION DEFINITIONS * 490 ************************************************************************/ 491 492 static int pins_and_params(char *argv[]) 493 { 494 long port_addr[MAX_PORTS]; 495 int data_dir[MAX_PORTS]; 496 int use_control_in[MAX_PORTS]; 497 int force_epp[MAX_PORTS]; 498 int n, retval; 499 500 /* clear port_addr and data_dir arrays */ 501 for (n = 0; n < MAX_PORTS; n++) { 502 port_addr[n] = 0; 503 data_dir[n] = 0; 504 use_control_in[n] = 0; 505 force_epp[n] = 0; 506 } 507 /* parse config string, results in port_addr[] and data_dir[] arrays */ 508 num_ports = 0; 509 n = 0; 510 while ((num_ports < MAX_PORTS) && (argv[n] != 0)) { 511 port_addr[num_ports] = parse_port_addr(argv[n]); 512 if (port_addr[num_ports] < 0) { 513 rtapi_print_msg(RTAPI_MSG_ERR, 514 "PARPORT: ERROR: bad port address '%s'\n", argv[n]); 515 return -1; 516 } 517 n++; 518 if (argv[n] != 0) { 519 /* is the next token 'in' or 'out' ? */ 520 if ((argv[n][0] == 'i') || (argv[n][0] == 'I')) { 521 /* we aren't picky, anything starting with 'i' means 'in' ;-) 522 */ 523 data_dir[num_ports] = 1; 524 use_control_in[num_ports] = 0; 525 n++; 526 } else if ((argv[n][0] == 'o') || (argv[n][0] == 'O')) { 527 /* anything starting with 'o' means 'out' */ 528 data_dir[num_ports] = 0; 529 use_control_in[num_ports] = 0; 530 n++; 531 } else if ((argv[n][0] == 'e') || (argv[n][0] == 'E')) { 532 /* anything starting with 'e' means 'epp', which is just 533 like 'out' but with EPP mode requested, primarily for 534 the G540 with its charge pump missing-pullup drive 535 issue */ 536 data_dir[num_ports] = 0; 537 use_control_in[num_ports] = 0; 538 force_epp[num_ports] = 1; 539 n++; 540 } else if ((argv[n][0] == 'x') || (argv[n][0] == 'X')) { 541 /* experimental: some parports support a bidirectional 542 * control port. Enable this with pins 2-9 in output mode, 543 * which gives a very nice 8 outs and 9 ins. */ 544 data_dir[num_ports] = 0; 545 use_control_in[num_ports] = 1; 546 n++; 547 } 548 } 549 num_ports++; 550 } 551 /* OK, now we've parsed everything */ 552 if (num_ports == 0) { 553 rtapi_print_msg(RTAPI_MSG_ERR, 554 "PARPORT: ERROR: no ports configured\n"); 555 return -1; 556 } 557 /* have good config info, connect to the HAL */ 558 comp_id = hal_init("hal_parport"); 559 if (comp_id < 0) { 560 rtapi_print_msg(RTAPI_MSG_ERR, "PARPORT: ERROR: hal_init() failed\n"); 561 return -1; 562 } 563 /* allocate shared memory for parport data */ 564 port_data_array = hal_malloc(num_ports * sizeof(parport_t)); 565 if (port_data_array == 0) { 566 rtapi_print_msg(RTAPI_MSG_ERR, 567 "PARPORT: ERROR: hal_malloc() failed\n"); 568 hal_exit(comp_id); 569 return -1; 570 } 571 /* export all the pins and params for each port */ 572 for (n = 0; n < num_ports; n++) { 573 int modes = 0; 574 575 if(use_control_in[n]) { 576 modes = PARPORT_MODE_TRISTATE; 577 } else if(force_epp[n]) { 578 modes = PARPORT_MODE_EPP; 579 } 580 581 retval = hal_parport_get(comp_id, &port_data_array[n].portdata, 582 port_addr[n], -1, modes); 583 584 if(retval < 0) { 585 // failure message already printed by hal_parport_get 586 hal_exit(comp_id); 587 return retval; 588 } 589 590 /* config addr and direction */ 591 port_data_array[n].base_addr = port_data_array[n].portdata.base; 592 port_data_array[n].data_dir = data_dir[n]; 593 port_data_array[n].use_control_in = use_control_in[n]; 594 595 if(force_epp[n] && port_data_array[n].portdata.base_hi) { 596 /* select EPP mode in ECR */ 597 outb(0x94, port_data_array[n].portdata.base_hi + 2); 598 } 599 600 /* set data port (pins 2-9) direction to "in" if needed */ 601 if (data_dir[n]) { 602 rtapi_outb(rtapi_inb(port_data_array[n].base_addr+2) | 0x20, port_data_array[n].base_addr+2); 603 } 604 605 /* export all vars */ 606 retval = export_port(n, &(port_data_array[n])); 607 if (retval != 0) { 608 rtapi_print_msg(RTAPI_MSG_ERR, 609 "PARPORT: ERROR: port %d var export failed\n", n); 610 hal_exit(comp_id); 611 return retval; 612 } 613 } 614 return 0; 615 } 616 617 static unsigned short parse_port_addr(char *cp) 618 { 619 unsigned short result; 620 621 /* initial value */ 622 result = 0; 623 /* test for leading '0x' */ 624 if (cp[0] == '0') { 625 if ((cp[1] == 'X') || (cp[1] == 'x')) { 626 /* leading '0x', skip it */ 627 cp += 2; 628 } 629 } 630 /* ok, now parse digits */ 631 while (*cp != '\0') { 632 /* if char is a hex digit, add it to result */ 633 if ((*cp >= '0') && (*cp <= '9')) { 634 result <<= 4; 635 result += *cp - '0'; 636 } else if ((*cp >= 'A') && (*cp <= 'F')) { 637 result <<= 4; 638 result += (*cp - 'A') + 10; 639 } else if ((*cp >= 'a') && (*cp <= 'f')) { 640 result <<= 4; 641 result += (*cp - 'a') + 10; 642 } else { 643 /* not a valid hex digit */ 644 return -1; 645 } 646 /* next char */ 647 cp++; 648 } 649 650 return result; 651 } 652 653 static int export_port(int portnum, parport_t * port) 654 { 655 int retval, msg; 656 657 /* This function exports a lot of stuff, which results in a lot of 658 logging if msg_level is at INFO or ALL. So we save the current value 659 of msg_level and restore it later. If you actually need to log this 660 function's actions, change the second line below */ 661 msg = rtapi_get_msg_level(); 662 rtapi_set_msg_level(RTAPI_MSG_WARN); 663 664 retval = 0; 665 /* declare input pins (status port) */ 666 retval += export_input_pin(portnum, 15, port->status_in, 0); 667 retval += export_input_pin(portnum, 13, port->status_in, 1); 668 retval += export_input_pin(portnum, 12, port->status_in, 2); 669 retval += export_input_pin(portnum, 10, port->status_in, 3); 670 retval += export_input_pin(portnum, 11, port->status_in, 4); 671 if (port->data_dir != 0) { 672 /* declare input pins (data port) */ 673 retval += export_input_pin(portnum, 2, port->data_in, 0); 674 retval += export_input_pin(portnum, 3, port->data_in, 1); 675 retval += export_input_pin(portnum, 4, port->data_in, 2); 676 retval += export_input_pin(portnum, 5, port->data_in, 3); 677 retval += export_input_pin(portnum, 6, port->data_in, 4); 678 retval += export_input_pin(portnum, 7, port->data_in, 5); 679 retval += export_input_pin(portnum, 8, port->data_in, 6); 680 retval += export_input_pin(portnum, 9, port->data_in, 7); 681 } else { 682 /* declare output pins (data port) */ 683 retval += export_output_pin(portnum, 2, 684 port->data_out, port->data_inv, port->data_reset, 0); 685 retval += export_output_pin(portnum, 3, 686 port->data_out, port->data_inv, port->data_reset, 1); 687 retval += export_output_pin(portnum, 4, 688 port->data_out, port->data_inv, port->data_reset, 2); 689 retval += export_output_pin(portnum, 5, 690 port->data_out, port->data_inv, port->data_reset, 3); 691 retval += export_output_pin(portnum, 6, 692 port->data_out, port->data_inv, port->data_reset, 4); 693 retval += export_output_pin(portnum, 7, 694 port->data_out, port->data_inv, port->data_reset, 5); 695 retval += export_output_pin(portnum, 8, 696 port->data_out, port->data_inv, port->data_reset, 6); 697 retval += export_output_pin(portnum, 9, 698 port->data_out, port->data_inv, port->data_reset, 7); 699 retval += hal_param_u32_newf(HAL_RW, &port->reset_time, comp_id, 700 "parport.%d.reset-time", portnum); 701 retval += hal_param_u32_newf(HAL_RW, &port->debug1, comp_id, 702 "parport.%d.debug1", portnum); 703 retval += hal_param_u32_newf(HAL_RW, &port->debug2, comp_id, 704 "parport.%d.debug2", portnum); 705 port->write_time = 0; 706 } 707 if(port->use_control_in == 0) { 708 /* declare output variables (control port) */ 709 retval += export_output_pin(portnum, 1, 710 port->control_out, port->control_inv, port->control_reset, 0); 711 retval += export_output_pin(portnum, 14, 712 port->control_out, port->control_inv, port->control_reset, 1); 713 retval += export_output_pin(portnum, 16, 714 port->control_out, port->control_inv, port->control_reset, 2); 715 retval += export_output_pin(portnum, 17, 716 port->control_out, port->control_inv, port->control_reset, 3); 717 } else { 718 /* declare input variables (control port) */ 719 retval += export_input_pin(portnum, 1, port->control_in, 0); 720 retval += export_input_pin(portnum, 14, port->control_in, 1); 721 retval += export_input_pin(portnum, 16, port->control_in, 2); 722 retval += export_input_pin(portnum, 17, port->control_in, 3); 723 } 724 725 /* restore saved message level */ 726 rtapi_set_msg_level(msg); 727 return retval; 728 } 729 730 static int export_input_pin(int portnum, int pin, hal_bit_t ** base, int n) 731 { 732 int retval; 733 734 /* export write only HAL pin for the input bit */ 735 retval = hal_pin_bit_newf(HAL_OUT, base + (2 * n), comp_id, 736 "parport.%d.pin-%02d-in", portnum, pin); 737 if (retval != 0) { 738 return retval; 739 } 740 /* export another write only HAL pin for the same bit inverted */ 741 retval = hal_pin_bit_newf(HAL_OUT, base + (2 * n) + 1, comp_id, 742 "parport.%d.pin-%02d-in-not", portnum, pin); 743 return retval; 744 } 745 746 static int export_output_pin(int portnum, int pin, hal_bit_t ** dbase, 747 hal_bit_t * pbase, hal_bit_t * rbase, int n) 748 { 749 int retval; 750 751 /* export read only HAL pin for output data */ 752 retval = hal_pin_bit_newf(HAL_IN, dbase + n, comp_id, 753 "parport.%d.pin-%02d-out", portnum, pin); 754 if (retval != 0) { 755 return retval; 756 } 757 /* export parameter for polarity */ 758 retval = hal_param_bit_newf(HAL_RW, pbase + n, comp_id, 759 "parport.%d.pin-%02d-out-invert", portnum, pin); 760 if (retval != 0) { 761 return retval; 762 } 763 /* export parameter for reset */ 764 if (rbase) 765 retval = hal_param_bit_newf(HAL_RW, rbase + n, comp_id, 766 "parport.%d.pin-%02d-out-reset", portnum, pin); 767 return retval; 768 }