📄 hal_parport.c
字号:
/********************************************************************* Description: hal_parport.c* This file, 'hal_parport.c', is a HAL component that * provides a driver for the standard PC parallel port.** Author: John Kasunich* License: GPL Version 2* * Copyright (c) 2003 All rights reserved.*********************************************************************//** This file, 'hal_parport.c', is a HAL component that provides a driver for the standard PC parallel port. It supports up to eight parallel ports, and if the port hardware is bidirectional, the eight data bits can be configured as inputs or outputs. The configuration is determined by command line arguments for the user space version of the driver, and by a config string passed to insmod for the realtime version. The format is similar for both, and consists of a port address, followed by an optional direction, repeated for each port. The direction is either "in" or "out" and determines the direction of the 8 bit data port. The default is out. The 5 bits of the status port are always inputs, and the 4 bits of the control port are always outputs. Example command lines are as follows: user: hal_parport 378 in 278 realtime: insmod hal_parport.o cfg="378 in 278" Both of these commands install the driver and configure parports at base addresses 0x0378 (using data port as input) and 0x0278 (using data port as output). The driver creates HAL pins and parameters for each port pin as follows: Each physical output has a correspinding HAL pin, named 'parport.<portnum>.pin-<pinnum>-out', and a HAL parameter 'parport.<portnum>.pin-<pinnum>-out-invert'. Each physical input has two corresponding HAL pins, named 'parport.<portnum>.pin-<pinnum>-in' and 'parport.<portnum>.pin-<pinnum>-in-not'. <portnum> is the port number, starting from zero. <pinnum> is the physical pin number on the DB-25 connector. The realtime version of the driver exports two HAL functions for each port, 'parport.<portnum>.read' and 'parport.<portnum>.write'. It also exports two additional functions, 'parport.read-all' and 'parport.write-all'. Any or all of these functions can be added to realtime HAL threads to update the port data periodically. The user space version of the driver cannot export functions, instead it exports parameters with the same names. The main() function sits in a loop checking the parameters. If they are zero, it does nothing. If any parameter is greater than zero, the corresponding function runs once, then the parameter is reset to zero. If any parameter is less than zero, the corresponding function runs on every pass through the loop. The driver will loop forever, until it receives either SIGINT (ctrl-C) or SIGTERM, at which point it cleans up and exits.*//** Copyright (C) 2003 John Kasunich <jmkasunich AT users DOT sourceforge DOT net>*//** This program is free software; you can redistribute it and/or modify it under the terms of version 2.1 of the GNU General Public License as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA THE AUTHORS OF THIS LIBRARY ACCEPT ABSOLUTELY NO LIABILITY FOR ANY HARM OR LOSS RESULTING FROM ITS USE. IT IS _EXTREMELY_ UNWISE TO RELY ON SOFTWARE ALONE FOR SAFETY. Any machinery capable of harming persons must have provisions for completely removing power from all motors, etc, before persons enter any danger area. All machinery must be designed to comply with local and national safety codes, and the authors of this software can not, and do not, take any responsibility for such compliance. This code was written as part of the EMC HAL project. For more information, go to www.linuxcnc.org.*/#if ( !defined RTAPI ) && ( !defined ULAPI )#error parport needs RTAPI/ULAPI, check makefile and flags#endif#ifdef RTAPI /* realtime */#include <linux/ctype.h> /* isspace() */#include "rtapi.h" /* RTAPI realtime OS API */#include "rtapi_app.h" /* RTAPI realtime module decls */#else /* user space */#include <ctype.h> /* isspace() */#include <signal.h> /* signal() */#include <sys/time.h> /* stuct timeval */#include <sys/types.h> /* for select() */#include <unistd.h> /* for select() */#include <sys/io.h> /* iopl() */#include "rtapi.h" /* RTAPI realtime OS API */#endif#include "hal.h" /* HAL public API decls *//* If FASTIO is defined, uses outb() and inb() from <asm.io>, instead of rtapi_outb() and rtapi_inb() - the <asm.io> ones are inlined, and save a microsecond or two (on my 233MHz box)*/#define FASTIO#ifdef FASTIO#define rtapi_inb inb#define rtapi_outb outb#ifdef RTAPI /* for ULAPI, sys/io.h defines these functs */#include <asm/io.h>#endif#endif#ifdef RTAPI /* realtime */#ifdef MODULE/* module information */MODULE_AUTHOR("John Kasunich");MODULE_DESCRIPTION("Parallel Port Driver for EMC HAL");#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endif /* MODULE_LICENSE */static char *cfg = "0x0278"; /* config string, default 1 output port at 278 */RTAPI_MP_STRING(cfg, "config string");#endif /* MODULE */#endif /* RTAPI *//************************************************************************ STRUCTURES AND GLOBAL VARIABLES *************************************************************************//* this structure contains the runtime data needed by the parallel port driver for a single port*/typedef struct { unsigned short base_addr; /* base I/O address (0x378, etc.) */ unsigned short data_dir; /* non-zero if pins 2-9 are input */ hal_bit_t *status_in[10]; /* ptrs for in pins 15, 13, 12, 10, 11 */ hal_bit_t *data_in[16]; /* ptrs for input pins 2 - 9 */ hal_bit_t *data_out[8]; /* ptrs for output pins 2 - 9 */ hal_bit_t data_inv[8]; /* polarity params for output pins 2 - 9 */ hal_bit_t *control_out[4]; /* ptrs for out pins 1, 14, 16, 17 */ hal_bit_t control_inv[4]; /* pol. params for pins 1, 14, 16, 17 */} parport_t;/* pointer to array of parport_t structs in shared memory, 1 per port */static parport_t *port_data_array;/* other globals */static int comp_id; /* component ID */static int num_ports; /* number of ports configured *//************************************************************************ LOCAL FUNCTION DECLARATIONS *************************************************************************//* These are the functions that actually do the I/O everything else is just init code*/static void read_port(void *arg, long period);static void write_port(void *arg, long period);static void read_all(void *arg, long period);static void write_all(void *arg, long period);/* 'pins_and_params()' does most of the work involved in setting up the driver. It parses the command line (argv[]), then if the command line is OK, it calls hal_init(), allocates shared memory for the parport_t data structure(s), and exports pins and parameters It does not set up functions, since that is handled differently in realtime and user space.*/static int pins_and_params(char *argv[]);static unsigned short parse_port_addr(char *cp);static int export_port(int portnum, parport_t * addr);static int export_input_pin(int portnum, int pin, hal_bit_t ** base, int n);static int export_output_pin(int portnum, int pin, hal_bit_t ** dbase, hal_bit_t * pbase, int n);/************************************************************************ INIT AND EXIT CODE *************************************************************************/#define MAX_PORTS 8#ifdef RTAPI /* realtime */#define MAX_TOK ((MAX_PORTS*2)+3)int rtapi_app_main(void){ char *cp; char *argv[MAX_TOK]; char name[HAL_NAME_LEN + 2]; int n, retval; /* test for config string */ if (cfg == 0) { rtapi_print_msg(RTAPI_MSG_ERR, "PARPORT: ERROR: no config string\n"); return -1; }rtapi_print ( "config string '%s'\n", cfg ); /* as a RT module, we don't get a nice argc/argv command line, we only get a single string... so we need to tokenize it ourselves */ /* in addition, it seems that insmod under kernel 2.6 will truncate a string parameter at the first whitespace. So we allow '_' as an alternate token separator. */ cp = cfg; for (n = 0; n < MAX_TOK; n++) { /* strip leading whitespace */ while ((*cp != '\0') && ( isspace(*cp) || ( *cp == '_') )) cp++; /* mark beginning of token */ argv[n] = cp; /* find end of token */ while ((*cp != '\0') && !( isspace(*cp) || ( *cp == '_') )) cp++; /* mark end of this token, prepare to search for next one */ if (*cp != '\0') { *cp = '\0'; cp++; } } for (n = 0; n < MAX_TOK; n++) { /* is token empty? */ if (argv[n][0] == '\0') { /* yes - make pointer NULL */ argv[n] = NULL; } } /* parse "command line", set up pins and parameters */ retval = pins_and_params(argv); if (retval != 0) { return retval; } /* export functions for each port */ for (n = 0; n < num_ports; n++) { /* make read function name */ rtapi_snprintf(name, HAL_NAME_LEN, "parport.%d.read", n); /* export read function */ retval = hal_export_funct(name, read_port, &(port_data_array[n]), 0, 0, comp_id); if (retval != 0) { rtapi_print_msg(RTAPI_MSG_ERR, "PARPORT: ERROR: port %d read funct export failed\n", n); hal_exit(comp_id); return -1; } /* make write function name */ rtapi_snprintf(name, HAL_NAME_LEN, "parport.%d.write", n); /* export write function */ retval = hal_export_funct(name, write_port, &(port_data_array[n]), 0, 0, comp_id); if (retval != 0) { rtapi_print_msg(RTAPI_MSG_ERR, "PARPORT: ERROR: port %d write funct export failed\n", n); hal_exit(comp_id); return -1; } } /* export functions that read and write all ports */ retval = hal_export_funct("parport.read-all", read_all, port_data_array, 0, 0, comp_id); if (retval != 0) { rtapi_print_msg(RTAPI_MSG_ERR, "PARPORT: ERROR: read all funct export failed\n"); hal_exit(comp_id); return -1; } retval = hal_export_funct("parport.write-all", write_all, port_data_array, 0, 0, comp_id); if (retval != 0) { rtapi_print_msg(RTAPI_MSG_ERR, "PARPORT: ERROR: write all funct export failed\n"); hal_exit(comp_id); return -1; } for (n = 0; n < num_ports; n++) { void *region = rtapi_request_region(port_data_array[n].base_addr, 4, "hal_parport"); if(!region) { int m; for(m = 0; m < n; m++) { rtapi_release_region(port_data_array[m].base_addr, 4); } rtapi_print_msg(RTAPI_MSG_ERR, "PARPORT: ERROR: request_region(%x) failed\n" , port_data_array[n].base_addr); rtapi_print_msg(RTAPI_MSG_ERR, "(make sure the kernel module 'parport' is unloaded)\n"); hal_exit(comp_id); return -EBUSY; } } rtapi_print_msg(RTAPI_MSG_INFO, "PARPORT: installed driver for %d ports\n", num_ports); return 0;}void rtapi_app_exit(void){ int n; for (n = 0; n < num_ports; n++) { rtapi_release_region(port_data_array[n].base_addr, 4); } hal_exit(comp_id);}#else /* user space */static int done = 0;static void quit(int sig){ done = 1;}int main(int argc, char *argv[]){ char name[HAL_NAME_LEN + 2]; int n, retval; hal_s8_t *read_funct_flags; hal_s8_t *write_funct_flags; struct timeval tv; /* ask linux for permission to use the I/O ports */ retval = iopl(3); if (retval != 0) { rtapi_print_msg(RTAPI_MSG_ERR, "PARPORT: ERROR: could not get I/O permission\n"); return -1; } /* parse command line, set up pins and parameters */ retval = pins_and_params(&(argv[1])); if (retval != 0) { return retval; } /* allocate space for function run/stop parameters */ read_funct_flags = hal_malloc((num_ports + 1) * sizeof(hal_s8_t) * 2); if (read_funct_flags == 0) { rtapi_print_msg(RTAPI_MSG_ERR, "PARPORT: ERROR: hal_malloc() failed\n"); hal_exit(comp_id); return -1; } write_funct_flags = read_funct_flags + (num_ports + 1); /* export function run/stop parameters for each port */ for (n = 0; n < num_ports; n++) { /* make read function name */ rtapi_snprintf(name, HAL_NAME_LEN, "parport.%d.read", n); /* export read function parameter */ retval = hal_param_s8_new(name, HAL_RD_WR, &read_funct_flags[n + 1], comp_id); if (retval != 0) { rtapi_print_msg(RTAPI_MSG_ERR, "PARPORT: ERROR: port %d read funct param failed\n", n); hal_exit(comp_id); return -1; } /* make write function name */ rtapi_snprintf(name, HAL_NAME_LEN, "parport.%d.write", n); /* export read function parameter */ retval = hal_param_s8_new(name, HAL_RD_WR, &write_funct_flags[n + 1], comp_id); if (retval != 0) { rtapi_print_msg(RTAPI_MSG_ERR, "PARPORT: ERROR: port %d write funct param failed\n", n); hal_exit(comp_id); return -1; } } /* export parameters for read/write all port functuons */ retval = hal_param_s8_new("parport.read_all", HAL_RD_WR, &read_funct_flags[0], comp_id); if (retval != 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -