From 9e8b2c0e969bd526afa1c1238000f10ba74f8088 Mon Sep 17 00:00:00 2001 From: Charles Steinkuehler Date: Tue, 9 Oct 2012 08:48:11 -0500 Subject: [PATCH] Applied preempt-rt patch set Used 2012-05-04 patch set from John Morris, which includes work from (at least) Michael Abel, Michael Busch, and Jeff Epler. --- .gitignore | 1 + scripts/realtime.in | 8 +- src/Makefile | 54 +- src/Makefile.modinc.in | 2 +- src/configure.in | 55 +- src/hal/drivers/Submakefile | 2 +- src/hal/drivers/hal_ax5214h.c | 2 +- src/hal/drivers/hal_motenc.c | 16 +- src/hal/drivers/hal_parport.c | 33 +- src/hal/drivers/hal_skeleton.c | 2 +- src/hal/drivers/hal_speaker.c | 2 +- src/hal/drivers/hal_stg.c | 161 +++-- src/hal/drivers/hal_tiro.c | 3 +- src/hal/drivers/hal_vti.c | 36 +- src/hal/drivers/hal_vti.h | 2 + src/hal/drivers/pci_8255.c | 5 +- src/hal/drivers/probe_parport.c | 25 +- src/hal/hal_parport.h | 224 +++++++ src/hal/hal_priv.h | 6 +- src/hal/utils/Submakefile | 2 +- src/hal/utils/halcmd_commands.c | 8 +- src/hal/utils/halrmt.c | 2 +- src/module_helper/Submakefile | 2 +- src/rtapi/Submakefile | 17 + src/rtapi/linux_common.h | 259 ++++++++ src/rtapi/linux_rtapi.c | 1024 +++++++++++++++++++++++++++++++ src/rtapi/linux_rtapi_app.cc | 751 +++++++++++++++++++++++ src/rtapi/linux_ulapi.c | 63 ++ src/rtapi/rtapi.h | 143 ++++- src/rtapi/rtapi_bitops.h | 17 +- tests/hm2-idrom/skip | 2 +- 31 files changed, 2743 insertions(+), 186 deletions(-) create mode 100644 src/rtapi/linux_common.h create mode 100644 src/rtapi/linux_rtapi.c create mode 100644 src/rtapi/linux_rtapi_app.cc create mode 100644 src/rtapi/linux_ulapi.c diff --git a/.gitignore b/.gitignore index c1e042e35..d16bed50c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ build-stamp *.mod.c *.cmd .tmp* +*~ # Ignore generated html files, *.html # Except Gcode quick-ref cards (en,de,sp,fr) which are maintained by hand diff --git a/scripts/realtime.in b/scripts/realtime.in index 28f70ffab..d4368d97b 100644 --- a/scripts/realtime.in +++ b/scripts/realtime.in @@ -75,7 +75,7 @@ CheckConfig(){ MODULES_LOAD= MODULES_UNLOAD= case $RTPREFIX in - sim) SHM_DEV=/dev/zero;; + sim|linux) SHM_DEV=/dev/zero;; *) for MOD in $MODULES ; do eval MOD=\${MODPATH_$MOD} @@ -103,7 +103,7 @@ CheckConfig(){ CheckStatus(){ case $RTPREFIX in - sim) + sim|linux) if [ -z "$($PIDOF rtapi_app)" ]; then exit 1 else @@ -152,7 +152,7 @@ CheckMem(){ Load(){ CheckKernel case $RTPREFIX in - sim) + sim|linux) ;; *) for MOD in $MODULES_LOAD ; do @@ -181,7 +181,7 @@ CheckLoaded(){ Unload(){ CheckKernel case $RTPREFIX in - sim) + sim|linux) rtapi_app exit ipcrm -M 0x48414c32 2>/dev/null ;# HAL_KEY ipcrm -M 0x90280A48 2>/dev/null ;# RTAPI_KEY diff --git a/src/Makefile b/src/Makefile index 3d8369cc2..b3afe7f88 100644 --- a/src/Makefile +++ b/src/Makefile @@ -78,6 +78,7 @@ default: configs userspace modules ifeq ($(RUN_IN_PLACE),yes) ifneq ($(BUILD_SYS),sim) @if [ -f ../bin/linuxcnc_module_helper ]; then if ! [ `stat -c %u ../bin/linuxcnc_module_helper` -eq 0 -a -u ../bin/linuxcnc_module_helper ]; then $(VECHO) "You now need to run 'sudo make setuid' in order to run in place."; fi; fi + @if [ -f ../bin/rtapi_app ]; then if ! [ `stat -c %u ../bin/rtapi_app` -eq 0 -a -u ../bin/rtapi_app ]; then $(VECHO) "You now need to run 'sudo make setuid' in order to run in place."; fi; fi endif endif @@ -405,12 +406,22 @@ setuid: @echo "'make setuid' is not needed for the simulator" else setuid: - chown root ../bin/linuxcnc_module_helper - chmod 4750 ../bin/linuxcnc_module_helper - chown root ../bin/pci_write - chmod 4750 ../bin/pci_write - chown root ../bin/pci_read - chmod 4750 ../bin/pci_read + if test -f ../bin/rtapi_app; then\ + chown root ../bin/rtapi_app;\ + chmod 4750 ../bin/rtapi_app;\ + fi + if test -f ../bin/linuxcnc_module_helper; then\ + chown root ../bin/linuxcnc_module_helper;\ + chmod 4750 ../bin/linuxcnc_module_helper;\ + fi + if test -f ../bin/pci_write; then\ + chown root ../bin/pci_write;\ + chmod 4750 ../bin/pci_write;\ + fi + if test -f ../bin/pci_read; then\ + chown root ../bin/pci_read;\ + chmod 4750 ../bin/pci_read;\ + fi endif # These rules allows a header file from this directory to be installed into @@ -571,7 +582,7 @@ install-kernel-dep: $(DESTDIR)$(bindir) \ $(DESTDIR)$(sysconfdir)/linuxcnc $(FILE) ../rtlib/*$(MODULE_EXT) $(DESTDIR)$(EMC2_RTLIB_DIR) -ifneq "$(BUILD_SYS)" "sim" +ifeq "$(filter sim linux,$(BUILD_SYS))" "" $(FILE) Module.symvers $(DESTDIR)$(EMC2_RTLIB_DIR) $(SETUID) ../bin/linuxcnc_module_helper $(DESTDIR)$(bindir) $(SETUID) ../bin/pci_write $(DESTDIR)$(bindir) @@ -645,7 +656,7 @@ endif # find a way around it. # Subdirectory: rtapi -ifneq ($(BUILD_SYS),sim) +ifeq "$(filter sim linux,$(BUILD_SYS))" "" obj-$(CONFIG_RTAPI) += rtapi.o rtapi-objs := rtapi/$(RTPREFIX)_rtapi.o endif @@ -704,18 +715,23 @@ obj-$(CONFIG_HAL_STG) += hal_stg.o hal_stg-objs := hal/drivers/hal_stg.o $(MATHSTUB) obj-$(CONFIG_HAL_VTI) += hal_vti.o hal_vti-objs := hal/drivers/hal_vti.o $(MATHSTUB) -obj-$(CONFIG_HAL_EVOREG) += hal_evoreg.o -hal_evoreg-objs := hal/drivers/hal_evoreg.o $(MATHSTUB) +#obj-$(CONFIG_HAL_EVOREG) += hal_evoreg.o +#hal_evoreg-objs := hal/drivers/hal_evoreg.o $(MATHSTUB) obj-$(CONFIG_HAL_MOTENC) += hal_motenc.o hal_motenc-objs := hal/drivers/hal_motenc.o $(MATHSTUB) obj-$(CONFIG_HAL_AX521H) += hal_ax5214h.o hal_ax5214h-objs := hal/drivers/hal_ax5214h.o $(MATHSTUB) -obj-$(CONFIG_HAL_PPMC) += hal_ppmc.o -hal_ppmc-objs := hal/drivers/hal_ppmc.o $(MATHSTUB) obj-$(CONFIG_HAL_SPEAKER) += hal_speaker.o hal_speaker-objs := hal/drivers/hal_speaker.o $(MATHSTUB) obj-$(CONFIG_HAL_SKELETON) += hal_skeleton.o hal_skeleton-objs := hal/drivers/hal_skeleton.o $(MATHSTUB) + +# these won't compile as-is with realtime=linux +ifneq ($(BUILD_SYS),linux) +obj-$(CONFIG_HAL_M5I20) += hal_m5i20.o +hal_m5i20-objs := hal/drivers/hal_m5i20.o $(MATHSTUB) +obj-$(CONFIG_HAL_PPMC) += hal_ppmc.o +hal_ppmc-objs := hal/drivers/hal_ppmc.o $(MATHSTUB) obj-$(CONFIG_OPTO_AC5) += opto_ac5.o opto_ac5-objs := hal/drivers/opto_ac5.o $(MATHSTUB) @@ -752,8 +768,9 @@ hm2_test-objs := \ hal/drivers/mesa-hostmot2/hm2_test.o \ hal/drivers/mesa-hostmot2/bitfile.o \ $(MATHSTUB) +endif -ifneq "$(filter 2.6.%, $(kernelvers))" "" +ifneq "$(filter linux,$(BUILD_SYS))$(filter 2.6.%, $(kernelvers))" "" obj-$(CONFIG_PROBE_PARPORT) += probe_parport.o probe_parport-objs := hal/drivers/probe_parport.o $(MATHSTUB) endif @@ -833,7 +850,7 @@ motmod-objs += libnml/posemath/_posemath.o motmod-objs += libnml/posemath/sincos.o $(MATHSTUB) TORTOBJS = $(foreach file,$($(patsubst %.o,%,$(1))-objs), objects/rt$(file)) -ifeq ($(BUILD_SYS),sim) +ifneq "$(filter sim linux,$(BUILD_SYS))" "" EXTRA_CFLAGS += -fPIC -Os RTOBJS := $(sort $(foreach mod,$(obj-m),$(call TORTOBJS,$(mod)))) @@ -881,8 +898,8 @@ $(sort $(RTOBJS)) : objects/rt%.o : %.c $(Q)ld -r -static -S -Os $(LDFLAGS) -o $@ $^ $(EXTRALINK) $(MATHLIB) endif -ifneq "$(filter normal sim,$(BUILD_SYS))" "" -ifneq "$(BUILD_SYS)" "sim" +ifneq "$(filter normal sim linux,$(BUILD_SYS))" "" +ifeq "$(filter sim linux,$(BUILD_SYS))" "" ../rtlib/rtapi$(MODULE_EXT): $(addprefix objects/rt,$(rtapi-objs)) endif ../rtlib/classicladder_rt$(MODULE_EXT): $(addprefix objects/rt,$(classicladder_rt-objs)) @@ -906,11 +923,14 @@ endif ../rtlib/streamer$(MODULE_EXT): $(addprefix objects/rt,$(streamer-objs)) ../rtlib/sampler$(MODULE_EXT): $(addprefix objects/rt,$(sampler-objs)) ../rtlib/hal_parport$(MODULE_EXT): $(addprefix objects/rt,$(hal_parport-objs)) +ifeq ($(BUILD_SYS),linux) +../rtlib/probe_parport$(MODULE_EXT): $(addprefix objects/rt,$(probe_parport-objs)) +endif ../rtlib/pci_8255$(MODULE_EXT): $(addprefix objects/rt,$(pci_8255-objs)) ../rtlib/hal_tiro$(MODULE_EXT): $(addprefix objects/rt,$(hal_tiro-objs)) ../rtlib/hal_stg$(MODULE_EXT): $(addprefix objects/rt,$(hal_stg-objs)) ../rtlib/hal_vti$(MODULE_EXT): $(addprefix objects/rt,$(hal_vti-objs)) -../rtlib/hal_evoreg$(MODULE_EXT): $(addprefix objects/rt,$(hal_evoreg-objs)) +#../rtlib/hal_evoreg$(MODULE_EXT): $(addprefix objects/rt,$(hal_evoreg-objs)) ../rtlib/hal_motenc$(MODULE_EXT): $(addprefix objects/rt,$(hal_motenc-objs)) ../rtlib/hal_ax5214h$(MODULE_EXT): $(addprefix objects/rt,$(hal_ax5214h-objs)) ../rtlib/hal_ppmc$(MODULE_EXT): $(addprefix objects/rt,$(hal_ppmc-objs)) diff --git a/src/Makefile.modinc.in b/src/Makefile.modinc.in index 98480f1f6..749c9152c 100644 --- a/src/Makefile.modinc.in +++ b/src/Makefile.modinc.in @@ -70,7 +70,7 @@ install: cp $(patsubst %.o,%.ko,$(obj-m)) $(DESTDIR)$(RTLIBDIR)/ endif -ifeq ($(BUILDSYS),sim) +ifneq "$(filter sim linux,$(BUILDSYS))" "" EXTRA_CFLAGS += -DSIM -fPIC allmodules = $(patsubst %.o,%.so,$(obj-m)) modules: $(allmodules) diff --git a/src/configure.in b/src/configure.in index 75798d83f..d49f20c42 100644 --- a/src/configure.in +++ b/src/configure.in @@ -83,6 +83,7 @@ RTLINUXPRO="" RTPREFIX="" KERNELDIR="" RTFLAGS="" +LINUX_REALTIME=no RTAI3_MOD="" RTAI_MOD="" @@ -116,17 +117,27 @@ AC_ARG_ENABLE(simulator, AC_SUBST(SIMULATOR) AC_ARG_WITH(realtime, - [ --with-realtime= Path where RTAI or RTlinux is installed], + [ --with-realtime= Path where RTAI or RTlinux is installed or 'linux' for linux-rt], [ case "$withval" in "" | y | ye | yes | n | no) AC_MSG_ERROR([You must supply a path for --with-realtime.]) ;; + linux) + LINUX_REALTIME=yes + BUILD_SYS=linux + RTPREFIX=linux + MODEXT=.so + MODULE_DIR=${prefix}/lib/emc2/modules + AC_MSG_RESULT([configuring for Realtime-Linux]) + ;; *) - case "$SIMULATOR" in - yes) AC_MSG_ERROR([--with-realtime and --enable-simulator are mutually exclusive]) ;; - *) RTDIR="$withval" ;; - esac - ;; + RTDIR="$withval" ;; esac]) +if test x$RTDIR != x; then + case "$SIMULATOR" in + yes) AC_MSG_ERROR([--with-realtime and --enable-simulator are mutually exclusive]) ;; + esac +fi + ############################################################################## # Subsection 2.2 # @@ -143,13 +154,8 @@ AC_ARG_WITH(realtime, ############################################################################## #at this point if RTDIR is empty, we need to find RT ourselves -if test $SIMULATOR = yes; then - RTS=sim - AC_PATH_PROG(PTH_CONFIG,pth-config,"") - if test "$PTH_CONFIG" = ""; then - AC_MSG_ERROR([GNU PTH library is required: get it with apt-get install libpth-dev]) - fi -else +if test $SIMULATOR != yes -a $LINUX_REALTIME != yes; then + # Using realtime hypervisor if test -z "$RTDIR"; then DIRS="/usr/realtime-`uname -r` /usr/realtime /usr/realtime* /usr /usr/src/rtai*" else @@ -175,6 +181,20 @@ to build without a realtime system.]) AC_MSG_RESULT([Using $RTS as the RT signature]) fi +if test $LINUX_REALTIME = yes; then + # Using realtime capable linux + RTS=linux +fi + +if test $SIMULATOR = yes; then + # Using simulator + RTS=sim + AC_PATH_PROG(PTH_CONFIG,pth-config,"") + if test "$PTH_CONFIG" = ""; then + AC_MSG_ERROR([GNU PTH library is required: get it with apt-get install libpth-dev]) + fi +fi + ############################################################################## # Subsection 2.3 # @@ -246,7 +266,7 @@ sim) RTFLAGS=-DSIMULATOR esac -if test $RTS != sim; then +if test $RTS != sim -a $RTS != linux; then AC_MSG_CHECKING([for location of kernel headers]) AC_ARG_WITH(kernel-headers, [ --with-kernel-headers= Location for kernel headers], @@ -274,6 +294,8 @@ elif test $RTPREFIX = rtai; then AC_DEFINE(RTAPI_RTAI, [], [Realtime system is RTAI]) elif test $RTPREFIX = rtl; then AC_DEFINE(RTAPI_RTL, [], [Realtime system is RTL]) +elif test $RTPREFIX = linux; then + AC_DEFINE(RTAPI_LINUX, [], [Realtime capable Linux]) fi @@ -366,7 +388,7 @@ AC_SUBST([HIDRAW_H_USABLE]) # compiled against. # ############################################################################## -if test $RTS '!=' sim; then +if test $RTS '!=' sim -a $RTS != linux; then AC_CHECK_HEADERS([$KERNELDIR/include/linux/version.h],[],[AC_MSG_ERROR([version.h not found - Is the kernel headers package installed ?])]) # Unfortunately, many distributions (redhat, mandrake) have #defines @@ -1508,6 +1530,9 @@ echo "# is possible. Drivers won't be built. #" else echo "# This means that RT is properly installed #" fi +if test $LINUX_REALTIME = yes; then +echo "# Using realtime capable Linux. #" +fi echo "# If things don't work check config.log for errors & warnings #" echo "# #" diff --git a/src/hal/drivers/Submakefile b/src/hal/drivers/Submakefile index 46d341784..881a5966f 100644 --- a/src/hal/drivers/Submakefile +++ b/src/hal/drivers/Submakefile @@ -33,7 +33,7 @@ pluto_clean: # The kernel's build system won't know how to rebuild generated files # so modules must depend on them explicitly -ifneq ($(BUILD_SYS),sim) +ifeq "$(filter sim linux,$(BUILD_SYS))" "" modules: \ hal/drivers/pluto_servo_rbf.h \ hal/drivers/pluto_step_rbf.h diff --git a/src/hal/drivers/hal_ax5214h.c b/src/hal/drivers/hal_ax5214h.c index 0d14d4b0b..fb4ec8e5b 100644 --- a/src/hal/drivers/hal_ax5214h.c +++ b/src/hal/drivers/hal_ax5214h.c @@ -96,7 +96,7 @@ instead of rtapi_outb() and rtapi_inb() - the ones are inlined, and save a microsecond or two (on my 233MHz box) */ -#define FASTIO +#define NOFASTIO #ifdef FASTIO #define rtapi_inb inb diff --git a/src/hal/drivers/hal_motenc.c b/src/hal/drivers/hal_motenc.c index b64ed340b..d0cff54f1 100644 --- a/src/hal/drivers/hal_motenc.c +++ b/src/hal/drivers/hal_motenc.c @@ -207,6 +207,7 @@ typedef struct { typedef struct { // Private data. + struct rtapi_pcidev *pDev; MotencRegMap *pCard; int boardType; char *pTypeName; @@ -273,7 +274,7 @@ int rtapi_app_main(void) { int i, j; - struct pci_dev *pDev = NULL; + struct rtapi_pcidev *pDev = NULL; MotencRegMap *pCard = NULL; Device *pDevice; @@ -291,7 +292,7 @@ rtapi_app_main(void) i = 0; // Find a MOTENC card. - while((i < MAX_DEVICES) && ((pDev = pci_get_device(MOTENC_VENDOR_ID, MOTENC_DEVICE_ID, pDev)) != NULL)){ + while((i < MAX_DEVICES) && ((pDev = rtapi_pci_get_device(MOTENC_VENDOR_ID, MOTENC_DEVICE_ID, pDev)) != NULL)){ // Allocate memory for device object. pDevice = hal_malloc(sizeof(Device)); @@ -301,14 +302,15 @@ rtapi_app_main(void) hal_exit(driver.componentId); return(-ENOMEM); } + pDevice->pDev = pDev; // Save pointer to device object. driver.deviceTable[i++] = pDevice; // Map card into memory. - pCard = (MotencRegMap *)ioremap_nocache(pci_resource_start(pDev, 2), pci_resource_len(pDev, 2)); - rtapi_print_msg(RTAPI_MSG_INFO, "MOTENC: Card detected in slot %2x\n", PCI_SLOT(pDev->devfn)); - rtapi_print_msg(RTAPI_MSG_INFO, "MOTENC: Card address @ %p, Len = %d\n", pCard, (int)pci_resource_len(pDev, 2)); + pCard = (MotencRegMap *)rtapi_pci_ioremap(pDev, 2, sizeof(MotencRegMap)); + rtapi_print_msg(RTAPI_MSG_INFO, "MOTENC: Card detected\n"); + rtapi_print_msg(RTAPI_MSG_INFO, "MOTENC: Card address @ %p, Len = %d\n", pCard, (int)sizeof(MotencRegMap)); // Initialize device. Device_Init(pDevice, pCard); @@ -376,7 +378,9 @@ rtapi_app_exit(void) } // Unmap card. - iounmap((void *)(pDevice->pCard)); + rtapi_pci_iounmap(pDevice->pDev, (void *)(pDevice->pCard)); + // Unregister the device + rtapi_pci_put_device(pDevice->pDev); // TODO: Free device object when HAL supports free. // hal_free(pDevice); diff --git a/src/hal/drivers/hal_parport.c b/src/hal/drivers/hal_parport.c index 2eacc7932..fb53ce9de 100644 --- a/src/hal/drivers/hal_parport.c +++ b/src/hal/drivers/hal_parport.c @@ -95,6 +95,7 @@ information, go to www.linuxcnc.org. */ +#include #include "rtapi.h" /* RTAPI realtime OS API */ #include "rtapi_ctype.h" /* isspace() */ #include "rtapi_app.h" /* RTAPI realtime module decls */ @@ -107,10 +108,14 @@ */ #define FASTIO -#ifdef FASTIO -#define rtapi_inb inb -#define rtapi_outb outb -#include +#ifdef RTAPI_LINUX /* Realtime-Linux */ +# include +#else /* Realtime hypervisor */ +# ifdef FASTIO +# define rtapi_inb inb +# define rtapi_outb outb +# include +# endif #endif #include "hal_parport.h" @@ -211,7 +216,7 @@ int rtapi_app_main(void) int n, retval; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) &&0//FIXME // this calculation fits in a 32-bit unsigned // as long as CPUs are under about 6GHz ns2tsc_factor = (cpu_khz << 6) / 15625ul; @@ -338,7 +343,7 @@ static void read_port(void *arg, long period) port = arg; /* read the status port */ - indata = rtapi_inb(port->base_addr + 1); + indata = hal_parport_read_status(&port->portdata); /* invert bit 7 (pin 11) to compensate for hardware inverter */ indata ^= 0x80; /* split the bits into 10 variables (5 regular, 5 inverted) */ @@ -351,7 +356,7 @@ static void read_port(void *arg, long period) /* are we using the data port for input? */ if (port->data_dir != 0) { /* yes, read the data port */ - indata = rtapi_inb(port->base_addr); + indata = hal_parport_read_data(&port->portdata); /* split the bits into 16 variables (8 regular, 8 inverted) */ mask = 0x01; for (b = 0; b < 16; b += 2) { @@ -364,7 +369,7 @@ static void read_port(void *arg, long period) if(port->use_control_in) { mask = 0x01; /* correct for hardware inverters on pins 1, 14, & 17 */ - indata = rtapi_inb(port->base_addr + 2) ^ 0x0B; + indata = hal_parport_read_control(&port->portdata) ^ 0x0B; for (b = 0; b < 8; b += 2) { *(port->control_in[b]) = indata & mask; *(port->control_in[b + 1]) = !(indata & mask); @@ -384,7 +389,7 @@ static void reset_port(void *arg, long period) { if(outdata != port->outdata) { deadline = port->write_time + reset_time_tsc; while(rtapi_get_clocks() < deadline) {} - rtapi_outb(outdata, port->base_addr); + hal_parport_write_data(&port->portdata, outdata); } outdata = (port->outdata_ctrl&~port->reset_mask_ctrl)^port->reset_val_ctrl; @@ -394,7 +399,7 @@ static void reset_port(void *arg, long period) { outdata ^= 0x0B; deadline = port->write_time_ctrl + reset_time_tsc; while(rtapi_get_clocks() < deadline) {} - rtapi_outb(outdata, port->base_addr + 2); + hal_parport_write_control(&port->portdata, outdata); } } @@ -427,7 +432,7 @@ static void write_port(void *arg, long period) mask <<= 1; } /* write it to the hardware */ - rtapi_outb(outdata, port->base_addr); + hal_parport_write_data(&port->portdata, outdata); port->write_time = rtapi_get_clocks(); port->reset_val = reset_val; port->reset_mask = reset_mask; @@ -467,7 +472,7 @@ static void write_port(void *arg, long period) /* correct for hardware inverters on pins 1, 14, & 17 */ outdata ^= 0x0B; /* write it to the hardware */ - rtapi_outb(outdata, port->base_addr + 2); + hal_parport_write_control(&port->portdata, outdata); port->write_time_ctrl = rtapi_get_clocks(); } @@ -581,9 +586,7 @@ static int pins_and_params(char *argv[]) port_data_array[n].use_control_in = use_control_in[n]; /* set data port (pins 2-9) direction to "in" if needed */ - if (data_dir[n]) { - rtapi_outb(rtapi_inb(port_data_array[n].base_addr+2) | 0x20, port_data_array[n].base_addr+2); - } + hal_parport_set_datadir(&port_data_array[n].portdata, (data_dir[n] != 0)); /* export all vars */ retval = export_port(n, &(port_data_array[n])); diff --git a/src/hal/drivers/hal_skeleton.c b/src/hal/drivers/hal_skeleton.c index 5af19c71d..33d171f9a 100644 --- a/src/hal/drivers/hal_skeleton.c +++ b/src/hal/drivers/hal_skeleton.c @@ -84,7 +84,7 @@ instead of rtapi_outb() and rtapi_inb() - the ones are inlined, and save a microsecond or two (on my 233MHz box) */ -#define FASTIO +#define NOFASTIO #ifdef FASTIO #define rtapi_inb inb diff --git a/src/hal/drivers/hal_speaker.c b/src/hal/drivers/hal_speaker.c index 95d7c3e9c..f6adee457 100644 --- a/src/hal/drivers/hal_speaker.c +++ b/src/hal/drivers/hal_speaker.c @@ -68,7 +68,7 @@ instead of rtapi_outb() and rtapi_inb() - the ones are inlined, and save a microsecond or two (on my 233MHz box) */ -#define FASTIO +#define NOFASTIO #ifdef FASTIO #define rtapi_inb inb diff --git a/src/hal/drivers/hal_stg.c b/src/hal/drivers/hal_stg.c index 01a85cc8c..59396b335 100644 --- a/src/hal/drivers/hal_stg.c +++ b/src/hal/drivers/hal_stg.c @@ -135,7 +135,6 @@ information, go to www.linuxcnc.org. */ -#include #include "rtapi.h" /* RTAPI realtime OS API */ #include "rtapi_app.h" /* RTAPI realtime module decls */ #include "hal.h" /* HAL public API decls */ @@ -645,15 +644,15 @@ static void stg_debug_print( void *arg, long period ) if( stg->model == 1 ) { - intc_reg = inb(base + INTC); + intc_reg = rtapi_inb(base + INTC); rtapi_print_msg(RTAPI_MSG_DBG, "STG: %04d: IXS1 is %s\n", counter, ( intc_reg & IXS1 ) ? "TRUE" : "FALSE" ); rtapi_print_msg(RTAPI_MSG_DBG, "STG: %04d: IXS0 is %s\n", counter, ( intc_reg & IXS0 ) ? "TRUE" : "FALSE" ); rtapi_print_msg(RTAPI_MSG_DBG, "STG: %04d: IXLVL is active %s\n", counter, ( intc_reg & IXLVL ) ? "TRUE" : "FALSE" ); } else if (stg->model == 2 ) { - idlen_reg = inb( base + IDLEN ); - seldi_reg = inb( base + SELDI ); + idlen_reg = rtapi_inb( base + IDLEN ); + seldi_reg = rtapi_inb( base + SELDI ); rtapi_print_msg(RTAPI_MSG_DBG, "STG: %04d: IDLEN is 0x%02x\n", counter, idlen_reg ); rtapi_print_msg(RTAPI_MSG_DBG, "STG: %04d: SELDI is 0x%02x\n", counter, seldi_reg ); @@ -806,30 +805,30 @@ static void stg_di_read(void *arg, long period) //reads digital inputs from the if ( (stg->dir_bits & 0x01) == 0) { // if port A is set as input, read the bits if (stg->model == 1) - val = inb(base + DIO_A); + val = rtapi_inb(base + DIO_A); else - val = inb(base + PORT_A); + val = rtapi_inb(base + PORT_A); split_input(val, &(stg->port[0][0]), 8); } if ( (stg->dir_bits & 0x02) == 0) { // if port B is set as input, read the bits if (stg->model == 1) - val = inb(base + DIO_B); + val = rtapi_inb(base + DIO_B); else - val = inb(base + PORT_B); + val = rtapi_inb(base + PORT_B); split_input(val, &(stg->port[1][0]), 8); } if ( (stg->dir_bits & 0x04) == 0) { // if port C is set as input, read the bits if (stg->model == 1) - val = inb(base + DIO_C); + val = rtapi_inb(base + DIO_C); else - val = inb(base + PORT_C); + val = rtapi_inb(base + PORT_C); split_input(val, &(stg->port[2][0]), 8); } if ( (stg->dir_bits & 0x08) == 0) { // if port D is set as input, read the bits if (stg->model == 1) - val = inb(base + DIO_D); + val = rtapi_inb(base + DIO_D); else - val = inb(base + PORT_D); + val = rtapi_inb(base + PORT_D); split_input(val, &(stg->port[3][0]), 8); } } @@ -843,30 +842,30 @@ static void stg_do_write(void *arg, long period) //writes digital outputs to the if ( (stg->dir_bits & 0x01) != 0) { // if port A is set as output, write the bits val = build_output(&(stg->port[0][0]), 8); if (stg->model == 1) - outb(val, base + DIO_A); + rtapi_outb(val, base + DIO_A); else - outb(val, base + PORT_A); + rtapi_outb(val, base + PORT_A); } if ( (stg->dir_bits & 0x02) != 0) { // if port B is set as output, write the bits val = build_output(&(stg->port[1][0]), 8); if (stg->model == 1) - outb(val, base + DIO_B); + rtapi_outb(val, base + DIO_B); else - outb(val, base + PORT_B); + rtapi_outb(val, base + PORT_B); } if ( (stg->dir_bits & 0x04) != 0) { // if port C is set as output, write the bits val = build_output(&(stg->port[2][0]), 8); if (stg->model == 1) - outb(val, base + DIO_C); + rtapi_outb(val, base + DIO_C); else - outb(val, base + PORT_C); + rtapi_outb(val, base + PORT_C); } if ( (stg->dir_bits & 0x08) != 0) { // if port D is set as output, write the bits val = build_output(&(stg->port[3][0]), 8); if (stg->model == 1) - outb(val, base + DIO_D); + rtapi_outb(val, base + DIO_D); else - outb(val, base + PORT_D); + rtapi_outb(val, base + PORT_D); } } @@ -889,17 +888,17 @@ static int stg_counter_init(int ch) { /* Set Counter Command Register - Master Control, Master Reset (MRST), */ /* and Reset address pointer (RADR). */ - outb(0x23, CTRL(ch)); + rtapi_outb(0x23, CTRL(ch)); /* Set Counter Command Register - Input Control, OL Load (P3), */ /* and Enable Inputs A and B (INA/B). */ - outb(0x68, CTRL(ch)); + rtapi_outb(0x68, CTRL(ch)); /* Set Counter Command Register - Output Control */ - outb(0x80, CTRL(ch)); + rtapi_outb(0x80, CTRL(ch)); /* Set Counter Command Register - Quadrature */ - outb(0xC3, CTRL(ch)); + rtapi_outb(0xC3, CTRL(ch)); return 0; } @@ -929,7 +928,7 @@ static int stg_adc_init(int ch) /* not much to setup for the ADC's */ /* only select the mode of operation we will work with AutoZero */ if (stg_driver->model == 1) - outb(0x0f, base + MIO_2); // the second 82C55 is already configured (by running stg_dio_init) + rtapi_outb(0x0f, base + MIO_2); // the second 82C55 is already configured (by running stg_dio_init) // we only set bit 8 (AZ) to 1 to enable it return 0; } @@ -953,13 +952,13 @@ static int stg_dio_init(void) if (stg_driver->model == 1) { // write the computed control to MIO_1 - outb(control, base+MIO_1); + rtapi_outb(control, base+MIO_1); } else { //model STG2 // write port A,B,C direction to ABC_DIR - outb(control, base+ABC_DIR); + rtapi_outb(control, base+ABC_DIR); } - tempINTC = inb(base + INTC); + tempINTC = rtapi_inb(base + INTC); if (stg_driver->model == 1) { // next compute the directions for port D, located on the second 82C55 @@ -968,22 +967,22 @@ static int stg_dio_init(void) if ( (stg_driver->dir_bits & 0x08) == 0)// if port D is set as input, set bits accordingly control = 0x92; - tempIMR = inb(base + IMR); // get the current interrupt mask + tempIMR = rtapi_inb(base + IMR); // get the current interrupt mask - outb(0xff, base + OCW1); //mask off all interrupts + rtapi_outb(0xff, base + OCW1); //mask off all interrupts // write the computed control to MIO_2 - outb(control, base+MIO_2); + rtapi_outb(control, base+MIO_2); - outb(tempINTC, base + INTC); //restore interrupt control reg. + rtapi_outb(tempINTC, base + INTC); //restore interrupt control reg. - outb(tempIMR, base+ OCW1); //restore int mask + rtapi_outb(tempIMR, base+ OCW1); //restore int mask } else { //model STG2 // save contents of CNTRL0, it will get reinitialized - tempCtrl0 = inb(base+CNTRL0); - tempCtrl1 = inb(base+CNTRL1); + tempCtrl0 = rtapi_inb(base+CNTRL0); + tempCtrl1 = rtapi_inb(base+CNTRL1); // CNTRL0 output, BRDTST input, D output control = 0x82; @@ -991,12 +990,12 @@ static int stg_dio_init(void) if ( (stg_driver->dir_bits & 0x08) == 0)// if port D is set as input, set bits accordingly control = 0x8b; - outb(0xff, base + CNTRL1); // disable interrupts + rtapi_outb(0xff, base + CNTRL1); // disable interrupts - outb(control, base + D_DIR); // set port D direction, also resets CNTRL0 + rtapi_outb(control, base + D_DIR); // set port D direction, also resets CNTRL0 - outb(tempCtrl0, base + CNTRL0); - outb( (tempCtrl1 & 0x0f) | 0xf0, base + CNTRL1); + rtapi_outb(tempCtrl0, base + CNTRL0); + rtapi_outb( (tempCtrl1 & 0x0f) | 0xf0, base + CNTRL1); } return 0; @@ -1010,7 +1009,7 @@ static int stg_dio_init(void) static void stg_counter_latch(int i) { - outb(0x03, CTRL(i)); + rtapi_outb(0x03, CTRL(i)); } @@ -1032,9 +1031,9 @@ static long stg_counter_read(int i) } byte; } pos; - pos.byte.b0 = inb(DATA(i)); - pos.byte.b1 = inb(DATA(i)); - pos.byte.b2 = inb(DATA(i)); + pos.byte.b0 = rtapi_inb(DATA(i)); + pos.byte.b1 = rtapi_inb(DATA(i)); + pos.byte.b2 = rtapi_inb(DATA(i)); if (pos.byte.b2 < 0) { pos.byte.b3 = -1; } else { @@ -1069,13 +1068,13 @@ static void stg1_select_index_axis(void *arg, unsigned int channel) byAxis &= 0x6; // ignore low bit, we check 2 axes at a time byAxis <<= 3; // shift into position for IXS1, IXS0 - byIntc = inb(base + INTC); // get a copy of INTC, we'll change + byIntc = rtapi_inb(base + INTC); // get a copy of INTC, we'll change // some bits in it, not all byIntc &= ~(IXLVL | IXS1 | IXS0); // zero bits for axis and polarity byIntc |= byAxis; // put axes address in INTC if (byPol != 0) // is index pulse active high? byIntc |= IXLVL; - outb(byIntc, base + INTC); + rtapi_outb(byIntc, base + INTC); } } @@ -1085,7 +1084,7 @@ static void stg2_select_index_axes( void *arg, unsigned char mask ) * writing 0 to the corresponding bit disables the index pulse * writing 1 enables it */ - outb( mask, base + IDLEN ); + rtapi_outb( mask, base + IDLEN ); return; } @@ -1097,8 +1096,8 @@ static void stg1_reset_index_latch(void *arg, unsigned int channel) if (stg->model == 1) { // routine for Model 1 - inb(base + ODDRST); //reset index pulse latch for ODD axis - inb(base + BRDTST); //reset index pulse latch for EVEN axis + rtapi_inb(base + ODDRST); //reset index pulse latch for ODD axis + rtapi_inb(base + BRDTST); //reset index pulse latch for EVEN axis } return; } @@ -1113,15 +1112,15 @@ static void stg2_reset_all_index_latches( void *arg ) * writing 0 to IDL resets the index latch, * writing 1 has no effect */ - outb( 0x00, base + IDL); + rtapi_outb( 0x00, base + IDL); } return; } unsigned char stg1_get_current_IRR(void) { - outb(base + OCW3, 0x0a); // IRR on next read - return inb(base + IRR); + rtapi_outb(base + OCW3, 0x0a); // IRR on next read + return rtapi_inb(base + IRR); } static unsigned short stg1_get_index_pulse_latch(void *arg, unsigned int chan) @@ -1150,7 +1149,7 @@ static unsigned char stg2_get_all_index_pulse_latches( void *arg ) unsigned char indexRegister = 0; if( stg-> model == 2 ) - indexRegister = inb( base + IDL ); + indexRegister = rtapi_inb( base + IDL ); return indexRegister; } @@ -1163,7 +1162,7 @@ static unsigned char stg2_get_all_index_pulse_latches( void *arg ) static int stg_dac_write(int ch, short value) { /* write the DAC */ - outw(value, base + DAC_0 + (ch << 1)); + rtapi_outw(value, base + DAC_0 + (ch << 1)); return 0; } @@ -1180,32 +1179,32 @@ int stg_adc_start(void *arg, unsigned short wAxis) if (stg->model == 1) { /* do a dummy read from the ADC, just to set the input multiplexer to the right channel */ - inw(base + ADC_0 + (wAxis << 1)); + rtapi_inw(base + ADC_0 + (wAxis << 1)); /* wait 4 uS for settling time on the multiplexer and ADC. You probably shouldn't really have a delay in a driver */ - outb(0, 0x80); - outb(0, 0x80); - outb(0, 0x80); - outb(0, 0x80); + rtapi_outb(0, 0x80); + rtapi_outb(0, 0x80); + rtapi_outb(0, 0x80); + rtapi_outb(0, 0x80); /* now start conversion */ - outw(0, base + ADC_0 + (wAxis << 1)); + rtapi_outw(0, base + ADC_0 + (wAxis << 1)); } else { //model STG2 - tempCtrl0 = inb(base+CNTRL0) & 0x07; // save IRQ + tempCtrl0 = rtapi_inb(base+CNTRL0) & 0x07; // save IRQ tempCtrl0 |= (wAxis << 4) | 0x88; //autozero & cal cycle - outb(tempCtrl0, base + CNTRL0); // select channel + rtapi_outb(tempCtrl0, base + CNTRL0); // select channel /* wait 4 uS for settling time on the multiplexer and ADC. You probably shouldn't really have a delay in a driver */ - outb(0, 0x80); - outb(0, 0x80); - outb(0, 0x80); - outb(0, 0x80); + rtapi_outb(0, 0x80); + rtapi_outb(0, 0x80); + rtapi_outb(0, 0x80); + rtapi_outb(0, 0x80); /* now start conversion */ - outw(0, base + ADC_0); + rtapi_outw(0, base + ADC_0); } return 0; }; @@ -1232,15 +1231,15 @@ static short stg_adc_read(void *arg, int axis) Register) of Interrupt Controller. Don't wait forever though bail out eventually. */ - for (j = 0; !(inb(base + IRR) & 0x08) && (j < 1000); j++); + for (j = 0; !(rtapi_inb(base + IRR) & 0x08) && (j < 1000); j++); - j = inw(base + ADC_0 + (axis << 1)); + j = rtapi_inw(base + ADC_0 + (axis << 1)); } else { //model 2 - for (j = 0; (inb(base + BRDTST) & 0x08) && (j < 1000); j++); + for (j = 0; (rtapi_inb(base + BRDTST) & 0x08) && (j < 1000); j++); - j = inw(base + ADC_0 + (axis << 1)); + j = rtapi_inw(base + ADC_0 + (axis << 1)); } @@ -1279,9 +1278,9 @@ static int stg_set_interrupt(short interrupt) default: tempINTC |= 4;break; } if (stg_driver->model == 1) - outb(tempINTC, base + INTC); + rtapi_outb(tempINTC, base + INTC); else - outb(tempINTC, base + CNTRL0); + rtapi_outb(tempINTC, base + CNTRL0); return 0; } @@ -1319,32 +1318,32 @@ static int stg_init_card() * STG1 */ // initialize INTC as output - outb(0x92, base + MIO_2); + rtapi_outb(0x92, base + MIO_2); stg_set_interrupt(5); // initialize it to smthg, we won't use it anyways - outb(0x1a, base + ICW1); // initialize the 82C59 as single chip (STG docs say so:) - outb(0x00, base + ICW2); // ICW2 not used, must init it to 0 - outb(0xff, base + OCW1); // mask off all interrupts + rtapi_outb(0x1a, base + ICW1); // initialize the 82C59 as single chip (STG docs say so:) + rtapi_outb(0x00, base + ICW2); // ICW2 not used, must init it to 0 + rtapi_outb(0xff, base + OCW1); // mask off all interrupts rtapi_print_msg(RTAPI_MSG_INFO, "STG: Initialised stg%1d card at address %x\n", stg_driver->model, base); } else if (stg_driver->model == 2 ) { /* * STG2 */ - outb(0x8b, base + D_DIR); // initialize CONTRL0 output, BRDTST input + rtapi_outb(0x8b, base + D_DIR); // initialize CONTRL0 output, BRDTST input /* stg2 manual, p.21 * writing 0 to the corresponding bit disables the index pulse * writing 1 enables it */ - outb( 0x00, base + IDLEN ); + rtapi_outb( 0x00, base + IDLEN ); /* stg2 manual, p.21 * writing 0 to the corresponding bit selects the index pulse to latch the counter * writing 1 to the corresponding bit selects EXLATCH to latch the counter */ - outb( 0x00, base + SELDI ); + rtapi_outb( 0x00, base + SELDI ); stg_set_interrupt(5); // initialize it to something, we won't use it anyways rtapi_print_msg(RTAPI_MSG_INFO, @@ -1378,10 +1377,10 @@ unsigned short stg_autodetect() address = i * 0x20 + 0x200; /* does jumper = i? */ - //if ((inb(address + BRDTST) & 0x0f) == i) { // by Xuecheng, not necessary + //if ((rtapi_inb(address + BRDTST) & 0x0f) == i) { // by Xuecheng, not necessary k = 0; // var for getting the serial for (j = 0; j < 8; j++) { - ofs = (inb(address + BRDTST) >> 4); + ofs = (rtapi_inb(address + BRDTST) >> 4); if (ofs & 8) { /* is SER set? */ ofs = ofs & 7; /* mask for Q2,Q1,Q0 */ diff --git a/src/hal/drivers/hal_tiro.c b/src/hal/drivers/hal_tiro.c index 0273c42a6..9b34be845 100644 --- a/src/hal/drivers/hal_tiro.c +++ b/src/hal/drivers/hal_tiro.c @@ -57,13 +57,14 @@ information, go to www.linuxcnc.org. */ +#include "config.h" #include "rtapi.h" /* RTAPI realtime OS API */ #include "rtapi_app.h" /* RTAPI realtime module decls */ #include "hal.h" /* HAL public API decls */ #define FASTIO -#ifdef FASTIO +#if defined(FASTIO) && !defined(RTAPI_LINUX) #define rtapi_inb inb #define rtapi_outb outb #include diff --git a/src/hal/drivers/hal_vti.c b/src/hal/drivers/hal_vti.c index f7ac0d3fb..758850794 100644 --- a/src/hal/drivers/hal_vti.c +++ b/src/hal/drivers/hal_vti.c @@ -152,7 +152,6 @@ information, go to www.linuxcnc.org. */ -#include #include "rtapi.h" /* RTAPI realtime OS API */ #include "rtapi_app.h" /* RTAPI realtime module decls */ #include @@ -208,8 +207,7 @@ typedef struct { } vti_struct; static vti_struct *vti_driver; -struct pci_dev *dev = NULL; -struct pci_access *device; +static struct rtapi_pcidev *dev = NULL; volatile struct encoder *encoder = NULL; volatile struct timer *timer = NULL; volatile struct dac *dac = NULL; @@ -314,6 +312,7 @@ int rtapi_app_main(void) diocount = vti_parse_dio(); if (diocount == -1) { + rtapi_pci_put_device(dev); rtapi_print_msg(RTAPI_MSG_ERR, "VTI: ERROR: bad config info for port.\n"); return -1; @@ -324,6 +323,7 @@ int rtapi_app_main(void) /* init counter chip */ if (vti_counter_init(num_chan) == -1) { + rtapi_pci_put_device(dev); rtapi_print_msg(RTAPI_MSG_ERR, "VTI: ERROR: bad config info counter.\n"); return -1; @@ -341,6 +341,7 @@ int rtapi_app_main(void) if (retval != 0) { rtapi_print_msg(RTAPI_MSG_ERR, "VTI: ERROR: vti.counter-capture funct export failed\n"); + rtapi_pci_put_device(dev); hal_exit(comp_id); return -1; } @@ -352,6 +353,7 @@ int rtapi_app_main(void) if (retval != 0) { rtapi_print_msg(RTAPI_MSG_ERR, "VTI: ERROR: vti.write-dacs funct export failed\n"); + rtapi_pci_put_device(dev); hal_exit(comp_id); return -1; } @@ -362,6 +364,7 @@ int rtapi_app_main(void) if (retval != 0) { rtapi_print_msg(RTAPI_MSG_ERR, "VTI: ERROR: vti.read-adcs funct export failed\n"); + rtapi_pci_put_device(dev); hal_exit(comp_id); return -1; } @@ -372,6 +375,7 @@ int rtapi_app_main(void) if (retval != 0) { rtapi_print_msg(RTAPI_MSG_ERR, "VTI: ERROR: vti.di-read funct export failed\n"); + rtapi_pci_put_device(dev); hal_exit(comp_id); return -1; } @@ -384,6 +388,7 @@ int rtapi_app_main(void) if (retval != 0) { rtapi_print_msg(RTAPI_MSG_ERR, "VTI: ERROR: vti.do-write funct export failed\n"); + rtapi_pci_put_device(dev); hal_exit(comp_id); return -1; } @@ -441,6 +446,11 @@ static int vti_parse_dio(void) void rtapi_app_exit(void) { + rtapi_pci_iounmap(dev, (void __iomem *)encoder); + rtapi_pci_iounmap(dev, (void __iomem *)dac); + rtapi_pci_iounmap(dev, (void __iomem *)timer); + rtapi_pci_iounmap(dev, (void __iomem *)ip); + rtapi_pci_put_device(dev); hal_exit(comp_id); } @@ -792,16 +802,10 @@ static int vti_init_card() { int retval=vti_autodetect(); if (retval == 0) { - encoder = (volatile struct encoder *) - ioremap(pci_resource_start(dev, 2), sizeof(encoder)); - dac = - (volatile struct dac *) ioremap(pci_resource_start(dev, - 4), sizeof(dac)); - timer = - (volatile struct timer *) ioremap(pci_resource_start(dev, - 3), sizeof(timer)); - ip = (volatile struct ip *) ioremap(pci_resource_start(dev, 5), - sizeof(ip)); + encoder = (volatile struct encoder *) rtapi_pci_ioremap(dev, 2, sizeof(encoder)); + dac = (volatile struct dac *) rtapi_pci_ioremap(dev, 4, sizeof(dac)); + timer = (volatile struct timer *) rtapi_pci_ioremap(dev, 3, sizeof(timer)); + ip = (volatile struct ip *) rtapi_pci_ioremap(dev, 5, sizeof(ip)); } else { return (retval); } @@ -822,11 +826,11 @@ static int vti_init_card() /* scans possible addresses for vti cards */ static int vti_autodetect() { - dev = pci_get_device(VENDOR, DEVICE, dev); + dev = rtapi_pci_get_device(VENDOR, DEVICE, NULL); if (dev) { - pci_dev_put(dev); + rtapi_pci_put_device(dev); rtapi_print_msg(RTAPI_MSG_INFO, - "VTI: Card detected in slot: %2x\n", PCI_SLOT(dev->devfn)); + "VTI: Card detected in slot"); return (0); } else { rtapi_print_msg(RTAPI_MSG_INFO, "VTI: Exiting with auto detect failed\n"); diff --git a/src/hal/drivers/hal_vti.h b/src/hal/drivers/hal_vti.h index ebcf76aa2..9e26ca4f6 100644 --- a/src/hal/drivers/hal_vti.h +++ b/src/hal/drivers/hal_vti.h @@ -47,6 +47,8 @@ information, go to www.linuxcnc.org. **/ +#include "rtapi.h" + /* Vigilant Technologies' board decls */ diff --git a/src/hal/drivers/pci_8255.c b/src/hal/drivers/pci_8255.c index 6fc4c6fcc..e1f680214 100644 --- a/src/hal/drivers/pci_8255.c +++ b/src/hal/drivers/pci_8255.c @@ -56,16 +56,15 @@ static void read_all(struct state *inst, long period); static void extra_cleanup(void); -#include #define SHIFT 4 static inline void WRITE(int value, hal_u32_t base, int offset) { // int *mem = (int*) base; - outb(value, base + SHIFT*offset); + rtapi_outb(value, base + SHIFT*offset); // mem[offset] = value; } static inline int READ(hal_u32_t base, int offset) { - return inb(base + SHIFT*offset); + return rtapi_inb(base + SHIFT*offset); // int *mem = (int*) base; // return mem[offset]; } diff --git a/src/hal/drivers/probe_parport.c b/src/hal/drivers/probe_parport.c index 14ff78f1f..ff9e5c291 100644 --- a/src/hal/drivers/probe_parport.c +++ b/src/hal/drivers/probe_parport.c @@ -38,10 +38,32 @@ * Updated probing logic - Adam Belay */ +#include "config.h" #include "hal.h" #include "rtapi.h" #include "rtapi_app.h" +static int comp_id; + +#ifdef RTAPI_LINUX + +int rtapi_app_main(void) { + comp_id = hal_init("probe_parport"); + if (comp_id < 0) { + rtapi_print_msg(RTAPI_MSG_ERR, "PROBE_PARPORT: ERROR: hal_init() failed\n"); + return -1; + } + hal_ready(comp_id); + + return 0; +} + +void rtapi_app_exit(void) { + hal_exit(comp_id); +} + +#else + #include #include #include @@ -65,7 +87,6 @@ MODULE_AUTHOR("Jeff Epler"); MODULE_DESCRIPTION("Parallel Port PNP driver for EMC HAL"); MODULE_LICENSE("GPL"); -static int comp_id; static int pnp_registered_parport = 0; static const struct pnp_device_id probe_parport_pnp_tbl[] = { @@ -140,3 +161,5 @@ void rtapi_app_exit(void) { pnp_unregister_driver (&probe_parport_pnp_driver); hal_exit(comp_id); } + +#endif diff --git a/src/hal/hal_parport.h b/src/hal/hal_parport.h index fc498dc97..887490197 100644 --- a/src/hal/hal_parport.h +++ b/src/hal/hal_parport.h @@ -26,8 +26,196 @@ typedef struct hal_parport_t struct pardevice *linux_dev; void *region; void *region_hi; + int dev_fd; } hal_parport_t; + +#ifdef RTAPI_LINUX /***** REALTIME CAPABLE LINUX *****/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned int hal_parport_error_count; + +static int +hal_parport_get(int comp_id, hal_parport_t *port, + unsigned short base, unsigned short base_hi, unsigned int modes) +{ + FILE *fd; + char devname[64] = { 0, }; + char devpath[96] = { 0, }; + + memset(port, 0, sizeof(*port)); + port->dev_fd = -1; + port->base = base; + port->base_hi = base_hi; + + if (base < 0x20) { + /* base is the parallel port number. */ + snprintf(devname, sizeof(devname), "parport%u", base); + goto found_dev; + } else { + char *buf = NULL; + size_t bufsize = 0; + + /* base is the I/O port base. */ + fd = fopen("/proc/ioports", "r"); + if (!fd) { + rtapi_print_msg(RTAPI_MSG_ERR, "Failed to open /proc/ioports: %s\n", + strerror(errno)); + return -ENODEV; + } + while (getline(&buf, &bufsize, fd) > 0) { + char *b = buf; + unsigned int start, end; + int count; + + while (b[0] == ' ' || b[0] == '\t') /* Strip leading whitespace */ + b++; + count = sscanf(b, "%x-%x : %63s", &start, &end, devname); + if (count != 3) + continue; + if (strncmp(devname, "parport", 7) != 0) + continue; + if (start == base) { + fclose(fd); + free(buf); + goto found_dev; + } + } + fclose(fd); + free(buf); + } + rtapi_print_msg(RTAPI_MSG_ERR, + "Did not find parallel port with base address 0x%03X\n", + base); + return -ENODEV; +found_dev: + snprintf(devpath, sizeof(devpath), "/dev/%s", devname); + rtapi_print_msg(RTAPI_MSG_INFO, "Using parallel port %s (base 0x%03X)\n", + devpath, base); + + port->dev_fd = open(devpath, O_RDWR); + if (port->dev_fd < 0) { + rtapi_print_msg(RTAPI_MSG_ERR, "Failed to open parallel port %s: %s\n", + devpath, strerror(errno)); + return -ENODEV; + } + if (ioctl(port->dev_fd, PPEXCL)) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Failed to get exclusive access to parallel port %s\n", + devpath); + close(port->dev_fd); + return -ENODEV; + } + if (ioctl(port->dev_fd, PPCLAIM)) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Failed to claim parallel port %s\n", + devpath); + close(port->dev_fd); + return -ENODEV; + } + + return 0; +} + +static void hal_parport_release(hal_parport_t *port) +{ + if (port->dev_fd < 0) + return; + ioctl(port->dev_fd, PPRELEASE); + close(port->dev_fd); +} + +static inline unsigned char hal_parport_read_status(hal_parport_t *port) +{ + unsigned char x; + + if (ioctl(port->dev_fd, PPRSTATUS, &x)) { + if (hal_parport_error_count < 10) { + hal_parport_error_count++; + rtapi_print_msg(RTAPI_MSG_ERR, "Failed to read parport status.\n"); + return 0; + } + } + + return x; +} + +static inline unsigned char hal_parport_read_data(hal_parport_t *port) +{ + unsigned char x; + + if (ioctl(port->dev_fd, PPRDATA, &x)) { + if (hal_parport_error_count < 10) { + hal_parport_error_count++; + rtapi_print_msg(RTAPI_MSG_ERR, "Failed to read parport data.\n"); + return 0; + } + } + + return x; +} + +static inline void hal_parport_write_data(hal_parport_t *port, unsigned char x) +{ + if (ioctl(port->dev_fd, PPWDATA, &x)) { + if (hal_parport_error_count < 10) { + hal_parport_error_count++; + rtapi_print_msg(RTAPI_MSG_ERR, "Failed to write parport data.\n"); + return; + } + } +} + +static inline unsigned char hal_parport_read_control(hal_parport_t *port) +{ + unsigned char x; + + if (ioctl(port->dev_fd, PPRCONTROL, &x)) { + if (hal_parport_error_count < 10) { + hal_parport_error_count++; + rtapi_print_msg(RTAPI_MSG_ERR, "Failed to read parport control.\n"); + return 0; + } + } + + return x; +} + +static inline void hal_parport_write_control(hal_parport_t *port, unsigned char x) +{ + if (ioctl(port->dev_fd, PPWCONTROL, &x)) { + if (hal_parport_error_count < 10) { + hal_parport_error_count++; + rtapi_print_msg(RTAPI_MSG_ERR, "Failed to write parport control.\n"); + return; + } + } +} + +static inline void hal_parport_set_datadir(hal_parport_t *port, int enable_inputs) +{ + enable_inputs = !!enable_inputs; + if (ioctl(port->dev_fd, PPDATADIR, &enable_inputs)) { + if (hal_parport_error_count < 10) { + hal_parport_error_count++; + rtapi_print_msg(RTAPI_MSG_ERR, "Failed to set parport data direction.\n"); + return; + } + } +} + + + +#else /***** REALTIME HYPERVISOR *****/ + static int hal_parport_get(int comp_id, hal_parport_t *port, unsigned short base, unsigned short base_hi, unsigned int modes) @@ -163,4 +351,40 @@ void hal_parport_release(hal_parport_t *port) } memset(port, 0, sizeof(hal_parport_t)); } + +static inline unsigned char hal_parport_read_status(hal_parport_t *port) +{ + return rtapi_inb(port->base + 1); +} + +static inline unsigned char hal_parport_read_data(hal_parport_t *port) +{ + return rtapi_inb(port->base + 0); +} + +static inline void hal_parport_write_data(hal_parport_t *port, unsigned char x) +{ + rtapi_outb(x, port->base + 0); +} + +static inline unsigned char hal_parport_read_control(hal_parport_t *port) +{ + return rtapi_inb(port->base + 2); +} + +static inline void hal_parport_write_control(hal_parport_t *port, unsigned char x) +{ + rtapi_outb(x, port->base + 2); +} + +static inline void hal_parport_set_datadir(hal_parport_t *port, int enable_inputs) +{ + if (enable_inputs) + hal_parport_write_control(port, hal_parport_read_control(port) | 0x20); + else + hal_parport_write_control(port, hal_parport_read_control(port) & ~0x20); +} + +#endif /* RTAPI_LINUX */ + #endif diff --git a/src/hal/hal_priv.h b/src/hal/hal_priv.h index 1ef1f745c..686d781a1 100644 --- a/src/hal/hal_priv.h +++ b/src/hal/hal_priv.h @@ -287,7 +287,11 @@ typedef struct { int funct_ptr; /* pointer to function */ } hal_funct_entry_t; -#define HAL_STACKSIZE 16384 /* realtime task stacksize */ +#ifdef RTAPI_LINUX +#define HAL_STACKSIZE 4194304 /* realtime task stacksize for PREEMPT_RT */ +#else +#define HAL_STACKSIZE 16384 /* realtime task stacksize for RTAI (RT-Linux?) */ +#endif typedef struct { int next_ptr; /* next thread in linked list */ diff --git a/src/hal/utils/Submakefile b/src/hal/utils/Submakefile index daa1e4c30..456937469 100644 --- a/src/hal/utils/Submakefile +++ b/src/hal/utils/Submakefile @@ -67,7 +67,7 @@ $(call TOOBJSDEPS, $(HALGTKSRCS)) : EXTRAFLAGS = $(GTK_CFLAGS) $(call TOOBJS, $(HALGTKSRCS)): Makefile.inc endif -ifneq ($(BUILD_SYS),sim) +ifeq "$(filter sim linux,$(BUILD_SYS))" "" PCIWRITESRCS := hal/utils/pci_write.c hal/utils/upci.c USERSRCS += $(PCIWRITESRCS) ../bin/pci_write: $(call TOOBJS, $(PCIWRITESRCS)) diff --git a/src/hal/utils/halcmd_commands.c b/src/hal/utils/halcmd_commands.c index cf776e81e..c98580e4d 100644 --- a/src/hal/utils/halcmd_commands.c +++ b/src/hal/utils/halcmd_commands.c @@ -510,7 +510,7 @@ int do_newinst_cmd(char *comp_name, char *inst_name) { return -EINVAL; } -#if defined(RTAPI_SIM) +#if defined(RTAPI_SIM) || defined(RTAPI_LINUX) { char *argv[MAX_TOK]; int m = 0, result; @@ -1054,7 +1054,7 @@ int do_loadrt_cmd(char *mod_name, char *args[]) hal_comp_t *comp; char *argv[MAX_TOK+3]; char *cp1; -#if defined(RTAPI_SIM) +#if defined(RTAPI_SIM) || defined(RTAPI_LINUX) argv[m++] = "-Wn"; argv[m++] = mod_name; argv[m++] = EMC2_BIN_DIR "/rtapi_app"; @@ -1118,7 +1118,7 @@ int do_loadrt_cmd(char *mod_name, char *args[]) if ( retval != 0 ) { halcmd_error("insmod failed, returned %d\n" -#if !defined(RTAPI_SIM) +#if !defined(RTAPI_SIM) && !defined(RTAPI_LINUX) "See the output of 'dmesg' for more information.\n" #endif , retval ); @@ -1313,7 +1313,7 @@ static int unloadrt_comp(char *mod_name) int retval; char *argv[4]; -#if defined(RTAPI_SIM) +#if defined(RTAPI_SIM) || defined(RTAPI_LINUX) argv[0] = EMC2_BIN_DIR "/rtapi_app"; argv[1] = "unload"; #else diff --git a/src/hal/utils/halrmt.c b/src/hal/utils/halrmt.c index 49622af2a..518f910a3 100644 --- a/src/hal/utils/halrmt.c +++ b/src/hal/utils/halrmt.c @@ -1135,7 +1135,7 @@ static int doLoadRt(char *mod_name, char *args[], connectionRecType *context) char *cp1; const char *nakStr = "SET LOADRT NAK"; -#if defined(RTAPI_SIM) +#if defined(RTAPI_SIM) || defined(RTAPI_LINUX) argv[m++] = "-Wn"; argv[m++] = mod_name; argv[m++] = EMC2_BIN_DIR "/rtapi_app"; diff --git a/src/module_helper/Submakefile b/src/module_helper/Submakefile index 145631c8b..04583da20 100644 --- a/src/module_helper/Submakefile +++ b/src/module_helper/Submakefile @@ -1,4 +1,4 @@ -ifneq ("$(RTPREFIX)","sim") +ifeq "$(filter sim linux,$(RTPREFIX))" "" MODULE_HELPERSRCS := \ module_helper/module_helper.c USERSRCS += $(MODULE_HELPERSRCS) diff --git a/src/rtapi/Submakefile b/src/rtapi/Submakefile index b8fbcbf5c..f6f5a000a 100644 --- a/src/rtapi/Submakefile +++ b/src/rtapi/Submakefile @@ -6,6 +6,7 @@ INCLUDES += rtapi cp $^ $@ ifeq ($(BUILD_SYS),sim) +# Simulator RTAPI_APP_SRCS := \ rtapi/sim_rtapi_app.cc \ @@ -21,3 +22,19 @@ $(call TOOBJSDEPS, $(RTAPI_APP_SRCS)): EXTRAFLAGS += $(PTH_CFLAGS) -DSIM @$(CXX) -rdynamic $(LDFLAGS) -o $@ $^ -ldl $(PTH_LINK) TARGETS += ../bin/rtapi_app endif + +ifeq ($(BUILD_SYS),linux) +# Realtime capable linux + +RTAPI_APP_SRCS := \ + rtapi/linux_rtapi_app.cc \ + rtapi/linux_rtapi.c +USERSRCS += $(RTAPI_APP_SRCS) + +$(call TOOBJSDEPS, $(RTAPI_APP_SRCS)): EXTRAFLAGS += -DLINUX_REALTIME +../bin/rtapi_app: $(call TOOBJS, $(RTAPI_APP_SRCS)) + $(ECHO) Linking $(notdir $@) + @$(CXX) -rdynamic $(LDFLAGS) -o $@ $^ -ldl -lpthread -lrt +TARGETS += ../bin/rtapi_app +endif + diff --git a/src/rtapi/linux_common.h b/src/rtapi/linux_common.h new file mode 100644 index 000000000..12fe04c8b --- /dev/null +++ b/src/rtapi/linux_common.h @@ -0,0 +1,259 @@ +#include +#include +#include + +static int msg_level = RTAPI_MSG_INFO; /* message printing level */ //XXX + +#include /* IPC_* */ +#include /* shmget() */ +#include +#include + + +/* These structs hold data associated with objects like tasks, etc. */ +/* Task handles are pointers to these structs. */ + +typedef struct { + int magic; /* to check for valid handle */ + int key; /* key to shared memory area */ + int id; /* OS identifier for shmem */ + int count; /* count of maps in this process */ + unsigned long int size; /* size of shared memory area */ + void *mem; /* pointer to the memory */ +} rtapi_shmem_handle; + +#define MAX_SHM 64 +#define SHM_PERMISSIONS 0666 + +#define SHMEM_MAGIC 25453 /* random numbers used as signatures */ + + +static rtapi_shmem_handle shmem_array[MAX_SHM]; +static pthread_mutex_t shmem_array_mutex = PTHREAD_MUTEX_INITIALIZER; + + +int rtapi_shmem_new(int key, int module_id, unsigned long int size) +{ + rtapi_shmem_handle *shmem; + int is_new = 0, i; + + pthread_mutex_lock(&shmem_array_mutex); + for (i = 0; i < MAX_SHM; i++) { + if (shmem_array[i].magic == SHMEM_MAGIC + && shmem_array[i].key == key) { + shmem_array[i].count++; + pthread_mutex_unlock(&shmem_array_mutex); + return i; + } + if (shmem_array[i].magic != SHMEM_MAGIC) + break; + } + if (i == MAX_SHM) { + pthread_mutex_unlock(&shmem_array_mutex); + return -ENOMEM; + } + shmem = &shmem_array[i]; + + /* now get shared memory block from OS */ + shmem->id = shmget((key_t)key, size, SHM_PERMISSIONS); + if (shmem->id == -1) { + if (errno == ENOENT) { + shmem->id = shmget((key_t)key, size, SHM_PERMISSIONS | IPC_CREAT); + is_new = 1; + } + if (shmem->id == -1) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Failed to allocate shared memory\n"); + pthread_mutex_unlock(&shmem_array_mutex); + return -ENOMEM; + } + } + /* and map it into process space */ + shmem->mem = shmat(shmem->id, 0, 0); + if ((ssize_t)(shmem->mem) == -1) { + pthread_mutex_unlock(&shmem_array_mutex); + return -ENOMEM; + } + /* Touch each page by either zeroing the whole mem (if it's a new SHM region), + * or by reading from it. */ + if (is_new) { + memset(shmem->mem, 0, size); + } else { + unsigned int i, pagesize; + + pagesize = sysconf(_SC_PAGESIZE); + for (i = 0; i < size; i += pagesize) { + unsigned int x = *(volatile unsigned int *)((unsigned char *)shmem->mem + i); + /* Use rand_r to clobber the read so GCC won't optimize it out. */ + rand_r(&x); + } + } + + /* label as a valid shmem structure */ + shmem->magic = SHMEM_MAGIC; + /* fill in the other fields */ + shmem->size = size; + shmem->key = key; + shmem->count = 1; + + pthread_mutex_unlock(&shmem_array_mutex); + + /* return handle to the caller */ + return i; +} + +int rtapi_shmem_getptr(int handle, void **ptr) +{ + rtapi_shmem_handle *shmem; + + if (handle < 0 || handle >= MAX_SHM) + return -EINVAL; + + shmem = &shmem_array[handle]; + + /* validate shmem handle */ + if (shmem->magic != SHMEM_MAGIC) + return -EINVAL; + + /* pass memory address back to caller */ + *ptr = shmem->mem; + + return 0; +} + +int rtapi_shmem_delete(int handle, int module_id) +{ + struct shmid_ds d; + int r1, r2; + rtapi_shmem_handle *shmem; + + if (handle < 0 || handle >= MAX_SHM) + return -EINVAL; + + pthread_mutex_lock(&shmem_array_mutex); + shmem = &shmem_array[handle]; + + /* validate shmem handle */ + if (shmem->magic != SHMEM_MAGIC) { + pthread_mutex_unlock(&shmem_array_mutex); + return -EINVAL; + } + + shmem->count--; + if (shmem->count) { + pthread_mutex_unlock(&shmem_array_mutex); + return 0; + } + + /* unmap the shared memory */ + r1 = shmdt(shmem->mem); + + /* destroy the shared memory */ + r2 = shmctl(shmem->id, IPC_STAT, &d); + if (r2 == 0 && d.shm_nattch == 0) { + r2 = shmctl(shmem->id, IPC_RMID, &d); + } + + /* free the shmem structure */ + shmem->magic = 0; + + pthread_mutex_unlock(&shmem_array_mutex); + + if ((r1 != 0) || (r2 != 0)) + return -EINVAL; + return 0; +} + +#define PRINTBUF_LEN 1024 + +void default_rtapi_msg_handler(msg_level_t level, const char *fmt, va_list ap) +{ + if (level == RTAPI_MSG_ALL) + vfprintf(stdout, fmt, ap); + else + vfprintf(stderr, fmt, ap); +} + +static rtapi_msg_handler_t rtapi_msg_handler = default_rtapi_msg_handler; + +rtapi_msg_handler_t rtapi_get_msg_handler(void) +{ + return rtapi_msg_handler; +} + +void rtapi_set_msg_handler(rtapi_msg_handler_t handler) +{ + if (handler == NULL) + rtapi_msg_handler = default_rtapi_msg_handler; + else + rtapi_msg_handler = handler; +} + +void rtapi_print(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + rtapi_msg_handler(RTAPI_MSG_ALL, fmt, args); + va_end(args); +} + +void rtapi_print_msg(int level, const char *fmt, ...) +{ + va_list args; + + if ((level <= msg_level) && (msg_level != RTAPI_MSG_NONE)) { + va_start(args, fmt); + rtapi_msg_handler(level, fmt, args); + va_end(args); + } +} + +int rtapi_snprintf(char *buffer, unsigned long int size, const char *msg, ...) +{ + va_list args; + int result; + + va_start(args, msg); + /* call the normal library vnsprintf() */ + result = vsnprintf(buffer, size, msg, args); + va_end(args); + + return result; +} + +int rtapi_vsnprintf(char *buffer, unsigned long int size, const char *fmt, + va_list args) +{ + return vsnprintf(buffer, size, fmt, args); +} + +int rtapi_set_msg_level(int level) +{ + msg_level = level; + return 0; +} + +int rtapi_get_msg_level() +{ + return msg_level; +} + +#ifdef MSR_H_USABLE +#include +#elif defined(__i386__) || defined(__x86_64__) +#define rdtscll(val) \ + __asm__ __volatile__("rdtsc" : "=A" (val)) +#else +#warning No implementation of rtapi_get_clocks available +#define rdtscll(val) (val)=0 +#endif + +long long rtapi_get_clocks(void) +{ + long long int retval; + + rdtscll(retval); + + return retval; +} diff --git a/src/rtapi/linux_rtapi.c b/src/rtapi/linux_rtapi.c new file mode 100644 index 000000000..c0c7fc500 --- /dev/null +++ b/src/rtapi/linux_rtapi.c @@ -0,0 +1,1024 @@ +/******************************************************************** +* Description: linux_rtapi.c +* This file, 'linux_rtapi.c', implements the RT API +* functions for machines with Linux-realtime +* +* Author: John Kasunich, Paul Corner +* Copyright (c) 2004 All rights reserved. +* +* Copyright (c) 2009 Michael Buesch +* +* License: GPL Version 2 +* +********************************************************************/ + +#define _GNU_SOURCE +#include /* vprintf() */ +#include /* malloc(), sizeof() */ +#include /* va_* */ +#include /* usleep() */ +#include /* IPC_* */ +#include /* shmget() */ +#include /* shmget() */ +#include /* clock_gettime etc */ +#include "rtapi.h" /* these decls */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +extern int realtime_cpuset_add_task(pid_t pid); /* Defined in rtapi_app */ + + +/* These structs hold data associated with objects like tasks, etc. */ +/* Task handles are pointers to these structs. */ + +struct rtapi_module { + int magic; +}; + +struct rtapi_task { + int magic; /* to check for valid handle */ + int owner; + int deleted; + + /* The realtime thread. */ + pthread_t thread; + pthread_barrier_t thread_init_barrier; + void *stackaddr; + size_t stacksize; + + int prio; + int period; + int ratio; + int destroyed; + int deadline_scheduling; + struct timespec next_time; + void *arg; + void (*taskcode)(void *); /* pointer to task function */ + + /* Statistics */ + unsigned long minfault_base; + unsigned long majfault_base; + unsigned int failures; +}; + +#define MODULE_MAGIC 30812 +#define TASK_MAGIC 21979 /* random numbers used as signatures */ + +#define MAX_TASKS 64 +#define MAX_MODULES 64 +#define MODULE_OFFSET 32768 + +#ifndef max +# define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + + +/* data for all tasks */ +static struct rtapi_task task_array[MAX_TASKS]; +static struct rtapi_module module_array[MAX_MODULES]; +/* Lock for task_array and module_array allocations. */ +static pthread_mutex_t array_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* local functions and data */ + +static pthread_key_t task_key; +static pthread_once_t task_key_once = PTHREAD_ONCE_INIT; + +static int period; + + +static inline int task_id(struct rtapi_task *task) +{ + return (int)(task - task_array); +} + +static unsigned long rtapi_get_pagefault_count(struct rtapi_task *task) +{ + struct rusage rusage; + unsigned long minor, major; + + getrusage(RUSAGE_SELF, &rusage); + minor = rusage.ru_minflt; + major = rusage.ru_majflt; + if (minor < task->minfault_base || major < task->majfault_base) { + rtapi_print_msg(RTAPI_MSG_ERR, "rtapi task %d: Got invalid fault counts.\n", + task_id(task)); + return 0; + } + minor -= task->minfault_base; + major -= task->majfault_base; + + return minor + major; +} + +static void rtapi_reset_pagefault_count(struct rtapi_task *task) +{ + struct rusage rusage; + + getrusage(RUSAGE_SELF, &rusage); + if (task->minfault_base != rusage.ru_minflt || + task->majfault_base != rusage.ru_majflt) { + task->minfault_base = rusage.ru_minflt; + task->majfault_base = rusage.ru_majflt; + rtapi_print_msg(RTAPI_MSG_INFO, "rtapi task %d: Reset pagefault counter\n", + task_id(task)); + } +} + +static void rtapi_advance_time(struct timespec *tv, unsigned long ns, + unsigned long s) +{ + ns += tv->tv_nsec; + while (ns > 1000000000) { + s++; + ns -= 1000000000; + } + tv->tv_nsec = ns; + tv->tv_sec += s; +} + +static void rtapi_key_alloc() +{ + pthread_key_create(&task_key, NULL); +} + +static void rtapi_set_task(struct rtapi_task *t) +{ + pthread_once(&task_key_once, rtapi_key_alloc); + pthread_setspecific(task_key, (void *)t); +} + +static struct rtapi_task *rtapi_this_task() +{ + pthread_once(&task_key_once, rtapi_key_alloc); + return (struct rtapi_task *)pthread_getspecific(task_key); +} + +int rtapi_prio_highest(void) +{ + return sched_get_priority_max(SCHED_FIFO); +} + +int rtapi_prio_lowest(void) +{ + return sched_get_priority_min(SCHED_FIFO); +} + +int rtapi_prio_next_higher(int prio) +{ + /* return a valid priority for out of range arg */ + if (prio >= rtapi_prio_highest()) + return rtapi_prio_highest(); + if (prio < rtapi_prio_lowest()) + return rtapi_prio_lowest(); + + /* return next higher priority for in-range arg */ + return prio + 1; +} + +int rtapi_prio_next_lower(int prio) +{ + /* return a valid priority for out of range arg */ + if (prio <= rtapi_prio_lowest()) + return rtapi_prio_lowest(); + if (prio > rtapi_prio_highest()) + return rtapi_prio_highest(); + + /* return next lower priority for in-range arg */ + return prio - 1; +} + +int rtapi_init(const char *modname) +{ + int n, result = -ENOMEM; + + pthread_mutex_lock(&array_mutex); + for (n = 0; n < MAX_MODULES; n++) { + if (module_array[n].magic != MODULE_MAGIC) { + result = n + MODULE_OFFSET; + module_array[n].magic = MODULE_MAGIC; + break; + } + } + pthread_mutex_unlock(&array_mutex); + + return result; +} + +int rtapi_exit(int id) +{ + int n = id - MODULE_OFFSET; + + if (n < 0 || n >= MAX_MODULES) + return -1; + /* Remove the module from the module_array. */ + pthread_mutex_lock(&array_mutex); + module_array[n].magic = 0; + pthread_mutex_unlock(&array_mutex); + + return 0; +} + +int rtapi_clock_set_period(unsigned long int nsecs) +{ + struct timespec res = { 0, 0 }; + + if (nsecs == 0) + return period; + if (period != 0) { + rtapi_print_msg(RTAPI_MSG_ERR, "attempt to set period twice\n"); + return -EINVAL; + } + clock_getres(CLOCK_MONOTONIC, &res); + period = (nsecs / res.tv_nsec) * res.tv_nsec; + if (period < 1) + period = res.tv_nsec; + rtapi_print_msg(RTAPI_MSG_INFO, + "rtapi_clock_set_period (res=%ld) -> %d\n", res.tv_nsec, + period); + + return period; +} + +int rtapi_task_new(void (*taskcode)(void *), void *arg, + int prio, int owner, unsigned long int stacksize, + int uses_fp) +{ + int n; + struct rtapi_task *task; + void *stackaddr; + + stacksize = max(stacksize, 16384); + stackaddr = malloc(stacksize); + if (!stackaddr) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Failed to allocate realtime thread stack\n"); + return -ENOMEM; + } + memset(stackaddr, 0, stacksize); + + /* find an empty entry in the task array */ + pthread_mutex_lock(&array_mutex); + n = 0; + while ((n < MAX_TASKS) && (task_array[n].magic == TASK_MAGIC)) + n++; + if (n == MAX_TASKS) { + pthread_mutex_unlock(&array_mutex); + free(stackaddr); + return -ENOMEM; + } + task = &(task_array[n]); + task->magic = TASK_MAGIC; + pthread_mutex_unlock(&array_mutex); + + /* check requested priority */ + { + int highest = rtapi_prio_highest(); + int lowest = rtapi_prio_lowest(); + if (prio < lowest || prio > highest) { + rtapi_print_msg(RTAPI_MSG_ERR, + "New task invalid priority %d (highest=%d lowest=%d)\n", + prio, highest, lowest); + free(stackaddr); + return -EINVAL; + } + rtapi_print_msg(RTAPI_MSG_INFO, + "Creating new task with requested priority %d (highest=%d lowest=%d)\n", + prio, highest, lowest); + } + + task->owner = owner; + task->arg = arg; + task->stacksize = stacksize; + task->stackaddr = stackaddr; + task->destroyed = 0; + task->taskcode = taskcode; + task->prio = prio; + + /* and return handle to the caller */ + + return n; +} + +int rtapi_task_delete(int id) +{ + struct rtapi_task *task; + void *returncode; + int err; + + if (id < 0 || id >= MAX_TASKS) + return -EINVAL; + + task = &(task_array[id]); + /* validate task handle */ + if (task->magic != TASK_MAGIC) + return -EINVAL; + + /* Signal thread termination and wait for the thread to exit. */ + if (!task->deleted) { + task->deleted = 1; + err = pthread_join(task->thread, &returncode); + if (err) + rtapi_print_msg(RTAPI_MSG_ERR, "pthread_join() on realtime thread failed\n"); + } + /* Free the thread stack. */ + free(task->stackaddr); + task->stackaddr = NULL; + /* Remove the task from the task_array. */ + pthread_mutex_lock(&array_mutex); + task->magic = 0; + pthread_mutex_unlock(&array_mutex); + + return 0; +} + +#ifndef CPU_SETSIZE +#define CPU_SETSIZE (8*sizeof(cpu_set_t)) +#endif + +static int realtime_set_affinity(struct rtapi_task *task) +{ + cpu_set_t set; + int err, cpu_nr, use_cpu = -1; + +printf("Setting affinity of %d\n", task_id(task)); + pthread_getaffinity_np(task->thread, sizeof(set), &set); + for (cpu_nr = CPU_SETSIZE - 1; cpu_nr >= 0; cpu_nr--) { + if (CPU_ISSET(cpu_nr, &set)) { + use_cpu = cpu_nr; + break; + } + } + if (use_cpu < 0) { + rtapi_print_msg(RTAPI_MSG_ERR, "Unable to get ID of the last CPU\n"); + return -1; + } + rtapi_print_msg(RTAPI_MSG_INFO, "Using CPU %d\n", use_cpu); + CPU_ZERO(&set); + CPU_SET(use_cpu, &set); +printf("Calling pthread_setaffinity_np() for %d\n", task_id(task)); + err = pthread_setaffinity_np(task->thread, sizeof(set), &set); + if (err) { + rtapi_print_msg(RTAPI_MSG_ERR, "Failed to set CPU affinity to CPU %d (%s)\n", + use_cpu, strerror(errno)); + return -1; + } +printf("pthread_setaffinity_np() for %d done\n", task_id(task)); + + err = realtime_cpuset_add_task(getpid()); + if (err) { + rtapi_print_msg(RTAPI_MSG_ERR, "Failed to add realtime task to realtime cpuset\n"); + return -1; + } + +printf("Affinity set for %d\n", task_id(task)); + return 0; +} + +#define ENABLE_SCHED_DEADLINE 0 /*XXX set to 1 to enable deadline scheduling. */ + +#ifndef __NR_sched_setscheduler_ex +# if defined(__x86_64__) +# define __NR_sched_setscheduler_ex 299 +# define __NR_sched_wait_interval 302 +# elif defined(__i386__) +# define __NR_sched_setscheduler_ex 337 +# define __NR_sched_wait_interval 340 +# else +# warning "SCHED_DEADLINE syscall numbers unknown" +# endif +#endif + +#ifndef SCHED_DEADLINE +#define SCHED_DEADLINE 6 + +struct sched_param_ex { + int sched_priority; + struct timespec sched_runtime; + struct timespec sched_deadline; + struct timespec sched_period; + int sched_flags; +}; + +#define SCHED_SIG_RORUN 0x80000000 +#define SCHED_SIG_DMISS 0x40000000 + +static inline int sched_setscheduler_ex(pid_t pid, int policy, unsigned len, struct sched_param_ex *param) +{ +#ifdef __NR_sched_setscheduler_ex + return syscall(__NR_sched_setscheduler_ex, pid, policy, len, param); +#endif + return -ENOSYS; +} +static inline int sched_wait_interval(int flags, const struct timespec *rqtp, + struct timespec *rmtp) +{ +#ifdef __NR_sched_wait_interval + return syscall(__NR_sched_wait_interval, flags, rqtp, rmtp); +#endif + return -ENOSYS; +} +#endif /* SCHED_DEADLINE */ + +static void deadline_exception(int signr) +{ + if (signr != SIGXCPU) { + rtapi_print_msg(RTAPI_MSG_ERR, "Received unknown signal %d\n", signr); + return; + } + rtapi_print_msg(RTAPI_MSG_ERR, "Missed scheduling deadline or overran " + "scheduling runtime!\n"); +} + +static int realtime_set_priority(struct rtapi_task *task) +{ + struct sched_param schedp; + struct sched_param_ex ex; + struct sigaction sa; + + task->deadline_scheduling = 0; + if (ENABLE_SCHED_DEADLINE) { + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sa.sa_handler = deadline_exception; + if (sigaction(SIGXCPU, &sa, NULL)) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Unable to register SIGXCPU handler.\n"); + return -1; + } + + memset(&ex, 0, sizeof(ex)); + ex.sched_deadline.tv_nsec = period; + ex.sched_runtime.tv_nsec = 8000; //FIXME + ex.sched_flags = SCHED_SIG_RORUN | SCHED_SIG_DMISS; +printf("Setting deadline scheduler for %d\n", task_id(task)); + if (sched_setscheduler_ex(0, SCHED_DEADLINE, sizeof(ex), &ex)) { + rtapi_print_msg(RTAPI_MSG_INFO, + "Unable to set DEADLINE scheduling policy (%s). Trying FIFO.\n", + strerror(errno)); + } else { + rtapi_print_msg(RTAPI_MSG_INFO, + "Running DEADLINE scheduling policy.\n"); + task->deadline_scheduling = 1; + return 0; + } + } + + memset(&schedp, 0, sizeof(schedp)); + schedp.sched_priority = task->prio; + if (sched_setscheduler(0, SCHED_FIFO, &schedp)) { + rtapi_print_msg(RTAPI_MSG_ERR, "Unable to set FIFO scheduling policy: %s", + strerror(errno)); + return 1; + } + + return 0; +} + +static void *realtime_thread(void *arg) +{ + struct rtapi_task *task = arg; + +printf("Hello world, I am task %d\n", task_id(task)); + rtapi_set_task(task); + + /* The task should not pagefault at all. So reset the counter now. + * Note that currently we _do_ receive a few pagefaults in the taskcode + * init. This is noncritical and probably not worth fixing. */ + rtapi_reset_pagefault_count(task); + + if (task->period < period) + task->period = period; + task->ratio = task->period / period; + rtapi_print_msg(RTAPI_MSG_INFO, "task %p period = %d ratio=%d\n", + task, task->period, task->ratio); + + if (realtime_set_affinity(task)) + goto error; + if (realtime_set_priority(task)) + goto error; + + /* We're done initializing. Open the barrier. */ + pthread_barrier_wait(&task->thread_init_barrier); + + clock_gettime(CLOCK_MONOTONIC, &task->next_time); + rtapi_advance_time(&task->next_time, task->period, 0); + + /* call the task function with the task argument */ + task->taskcode(task->arg); + + rtapi_print_msg(RTAPI_MSG_ERR, "ERROR: reached end of realtime thread for task %d\n", + task_id(task)); + task->deleted = 1; + + return NULL; +error: + /* Signal that we're dead and open the barrier. */ + task->deleted = 1; + pthread_barrier_wait(&task->thread_init_barrier); + return NULL; +} + +int rtapi_task_start(int task_id, unsigned long int period_nsec) +{ + struct rtapi_task *task; + pthread_attr_t attr; + int retval; + + if (task_id < 0 || task_id >= MAX_TASKS) + return -EINVAL; + + task = &task_array[task_id]; + + /* validate task handle */ + if (task->magic != TASK_MAGIC) + return -EINVAL; + + if (period_nsec < period) + period_nsec = period; + task->period = period_nsec; + task->ratio = period_nsec / period; + task->deleted = 0; + + /* create the thread - use the wrapper function, pass it a pointer + to the task structure so it can call the actual task function */ + + pthread_barrier_init(&task->thread_init_barrier, NULL, 2); + pthread_attr_init(&attr); + pthread_attr_setstack(&attr, task->stackaddr, task->stacksize); +printf("About to pthread_create task %d\n", task_id); + retval = pthread_create(&task->thread, &attr, realtime_thread, (void *)task); +printf("Created task %d\n", task_id); + pthread_attr_destroy(&attr); + if (retval) { + pthread_barrier_destroy(&task->thread_init_barrier); + rtapi_print_msg(RTAPI_MSG_ERR, "Failed to create realtime thread\n"); + return -ENOMEM; + } + /* Wait for the thread to do basic initialization. */ + pthread_barrier_wait(&task->thread_init_barrier); + pthread_barrier_destroy(&task->thread_init_barrier); + if (task->deleted) { /* The thread died in the init phase. */ + rtapi_print_msg(RTAPI_MSG_ERR, "Realtime thread initialization failed\n"); + return -ENOMEM; + } +printf("Task %d finished its basic init\n", task_id); + + return 0; +} + +int rtapi_task_stop(int task_id) +{ + struct rtapi_task *task; + + if (task_id < 0 || task_id >= MAX_TASKS) + return -EINVAL; + + task = &task_array[task_id]; + + /* validate task handle */ + if (task->magic != TASK_MAGIC) + return -EINVAL; + + task->destroyed = 1; + + return 0; +} + +int rtapi_task_pause(int task_id) +{ + struct rtapi_task *task; + + if (task_id < 0 || task_id >= MAX_TASKS) + return -EINVAL; + + task = &task_array[task_id]; + + /* validate task handle */ + if (task->magic != TASK_MAGIC) + return -EINVAL; + + return -ENOSYS; +} + +int rtapi_task_resume(int task_id) +{ + struct rtapi_task *task; + + if (task_id < 0 || task_id >= MAX_TASKS) + return -EINVAL; + + task = &task_array[task_id]; + + /* validate task handle */ + if (task->magic != TASK_MAGIC) + return -EINVAL; + + return -ENOSYS; +} + +int rtapi_task_set_period(int task_id, unsigned long int period_nsec) +{ + struct rtapi_task *task; + + if (task_id < 0 || task_id >= MAX_TASKS) + return -EINVAL; + + task = &task_array[task_id]; + + /* validate task handle */ + if (task->magic != TASK_MAGIC) + return -EINVAL; + + task->period = period_nsec; + + return 0; +} + +int rtapi_wait(void) +{ + struct timespec ts; + struct rtapi_task *task = rtapi_this_task(); + + if (task->deleted) + pthread_exit(0); + + if (task->deadline_scheduling) + sched_wait_interval(TIMER_ABSTIME, &task->next_time, NULL); + else + clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &task->next_time, NULL); + rtapi_advance_time(&task->next_time, task->period, 0); + clock_gettime(CLOCK_MONOTONIC, &ts); + if (ts.tv_sec > task->next_time.tv_sec + || (ts.tv_sec == task->next_time.tv_sec + && ts.tv_nsec > task->next_time.tv_nsec)) { + int msglevel = RTAPI_MSG_NONE; + + task->failures++; + if (task->failures == 1) + msglevel = RTAPI_MSG_ERR; + else if (task->failures < 10 || (task->failures % 10000 == 0)) + msglevel = RTAPI_MSG_WARN; + + if (msglevel != RTAPI_MSG_NONE) { + rtapi_print_msg(msglevel, + "ERROR: Missed scheduling deadline for task %d [%d times]\n" + "Now is %ld.%09ld, deadline was %ld.%09ld\n" + "Absolute number of pagefaults in realtime context: %lu\n", + task_id(task), task->failures, + (long)ts.tv_sec, (long)ts.tv_nsec, + (long)task->next_time.tv_sec, + (long)task->next_time.tv_nsec, + rtapi_get_pagefault_count(task)); + } + } + + return 0; +} + +void rtapi_outb(unsigned char byte, unsigned int port) +{ + outb(byte, port); +} + +unsigned char rtapi_inb(unsigned int port) +{ + return inb(port); +} + +void rtapi_outw(unsigned short word, unsigned int port) +{ + outw(word, port); +} + +unsigned short rtapi_inw(unsigned int port) +{ + return inw(port); +} + +long int simple_strtol(const char *nptr, char **endptr, int base) +{ + return strtol(nptr, endptr, base); +} + +long long rtapi_get_time(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; +} + +/*********************************************************************** +* PCI DEVICE SUPPORT * +************************************************************************/ + +struct rtapi_pcidev_mmio { + int bar; /* The PCI BAR */ + void *mmio; /* The MMIO address */ + size_t length; /* Length of the mapping */ +}; + +struct rtapi_pcidev { + __u16 vendor; /* Vendor ID */ + __u16 device; /* Device ID */ + char busid[32]; /* PCI bus ID (0000:00:00.0) */ + char devnode[32]; /* UIO /dev node */ + int fd; /* UIO /dev file descriptor */ + int mmio_refcnt; /* MMIO resource reference count */ + struct rtapi_pcidev_mmio mmio[8]; /* Mappings */ +}; + +#define UIO_PCI_PATH "/sys/bus/pci/drivers/uio_pci_generic" + +static ssize_t readfile(const char *path, char *buf, size_t buflen) +{ + int fd; + ssize_t res; + + fd = open(path, O_RDONLY); + if (!fd) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Failed to open \"%s\" (%s)\n", + path, strerror(errno)); + return -1; + } + memset(buf, 0, buflen); + res = read(fd, buf, buflen - 1); + close(fd); + if (res < 0) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Failed to read \"%s\" (%s)\n", + path, strerror(errno)); + return -1; + } + + return res; +} + +static int writefile(const char *path, const char *buf, size_t len) +{ + int fd; + ssize_t res; + + fd = open(path, O_RDWR); + if (!fd) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Failed to open \"%s\" (%s)\n", + path, strerror(errno)); + return -1; + } + res = write(fd, buf, len); + close(fd); + if (res != len) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Failed to write \"%s\" (%s)\n", + path, strerror(errno)); + return -1; + } + + return 0; +} + +struct rtapi_pcidev * rtapi_pci_get_device(__u16 vendor, __u16 device, + struct rtapi_pcidev *from) +{ + int err; + DIR *dir; + struct dirent dirent_buf, *dirent; + ssize_t res; + char buf[256], path[256]; + struct rtapi_pcidev *dev = NULL; + int found_start = 0; + + /* Register the new device IDs */ + snprintf(buf, sizeof(buf), "%04X %04X", vendor, device); + err = writefile(UIO_PCI_PATH "/new_id", buf, strlen(buf)); + if (err) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Failed to register PCI device to UIO-pci-generic. " + "Is the \"uio-pci-generic\" kernel module loaded?\n"); + goto error; + } + + /* UIO-pci-generic should bind to the device now. Wait to avoid races. */ + { + struct timespec time = { + .tv_sec = 0, + .tv_nsec = 1000 * 1000 * 100, + }; + do { + err = nanosleep(&time, &time); + if (err && errno != EINTR) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Nanosleep failure (%s)\n", + strerror(errno)); + break; + } + } while (time.tv_sec || time.tv_nsec); + } + + /* Find the device */ + dir = opendir(UIO_PCI_PATH); + if (!dir) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Failed to open UIO-pci-generic sysfs directory. (%s)\n", + strerror(errno)); + goto error; + } + while (1) { + unsigned int tmp; + + err = readdir_r(dir, &dirent_buf, &dirent); + if (err) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Failed to read UIO-pci-generic sysfs directory. (%s)\n", + strerror(errno)); + closedir(dir); + goto error; + } + if (from && !found_start) { + if (strcmp(dirent->d_name, from->busid) == 0) { + /* Found the start entry. */ + found_start = 1; + } + continue; + } + res = sscanf(dirent->d_name, "%X:%X:%X.%X", &tmp, &tmp, &tmp, &tmp); + if (res != 4) + continue; + /* Check the vendor ID */ + snprintf(path, sizeof(path), UIO_PCI_PATH "/%s/vendor", dirent->d_name); + res = readfile(path, buf, sizeof(buf)); + if (res <= 0) + continue; + res = sscanf(buf, "%X", &tmp); + if (res != 1 || tmp != vendor) + continue; + /* Check the device ID */ + snprintf(path, sizeof(path), UIO_PCI_PATH "/%s/device", dirent->d_name); + res = readfile(path, buf, sizeof(buf)); + if (res <= 0) + continue; + res = sscanf(buf, "%X", &tmp); + if (res != 1 || tmp != device) + continue; + + /* We got a device! */ + dev = malloc(sizeof(*dev)); + if (!dev) { + rtapi_print_msg(RTAPI_MSG_ERR, "Out of memory\n"); + closedir(dir); + goto error; + } + memset(dev, 0, sizeof(*dev)); + strncpy(dev->busid, dirent->d_name, sizeof(dev->busid) - 1); + break; + } + closedir(dir); + if (!dev) { + rtapi_print_msg(RTAPI_MSG_INFO, "PCI device %04X:%04X not found\n", + vendor, device); + goto error; + } + + dev->vendor = vendor; + dev->device = device; + + /* Check which /dev node the device is on. */ + snprintf(path, sizeof(path), UIO_PCI_PATH "/%s/uio", dev->busid); + dir = opendir(path); + if (!dir) { + rtapi_print_msg(RTAPI_MSG_ERR, "Failed to open UIO directory. (%s)\n", + strerror(errno)); + goto error; + } + while (1) { + unsigned int tmp; + + err = readdir_r(dir, &dirent_buf, &dirent); + if (err) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Failed to read UIO directory. (%s)\n", + strerror(errno)); + closedir(dir); + goto error; + } + res = sscanf(dirent->d_name, "uio%u", &tmp); + if (res != 1) + continue; + snprintf(dev->devnode, sizeof(dev->devnode), "/dev/uio%u", tmp); + break; + } + closedir(dir); + if (strlen(dev->devnode) == 0) { + rtapi_print_msg(RTAPI_MSG_ERR, "Could not determine UIO /dev node.\n"); + goto error; + } + + /* Open the device node */ + dev->fd = open(dev->devnode, O_RDWR); + if (dev->fd < 0) { + rtapi_print_msg(RTAPI_MSG_ERR, "Could not open UIO node \"%s\". (%s)\n", + dev->devnode, strerror(errno)); + goto error; + } + + return dev; + +error: + if (dev) + free(dev); + return NULL; +} + +void rtapi_pci_put_device(struct rtapi_pcidev *dev) +{ + int err; + char buf[256]; + + if (!dev) + return; + + if (dev->mmio_refcnt != 0) { + rtapi_print_msg(RTAPI_MSG_ERR, "Nonzero PCI MMIO reference count (%d). " + "Check your ioremap/iounmap calls.\n", dev->mmio_refcnt); + } + + /* Remove the device IDs */ + snprintf(buf, sizeof(buf), "%04X %04X", dev->vendor, dev->device); + err = writefile(UIO_PCI_PATH "/remove_id", buf, strlen(buf)); + if (err) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Failed to remove PCI device ID from UIO-pci-generic.\n"); + } + + /* Unbind the device from the UIO-pci-generic driver. */ + err = writefile(UIO_PCI_PATH "/unbind", dev->busid, strlen(dev->busid)); + if (err) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Failed to unbind the PCI device %s\n", dev->busid); + } + + close(dev->fd); + + memset(dev, 0, sizeof(*dev)); + free(dev); +} + +void * rtapi_pci_ioremap(struct rtapi_pcidev *dev, int bar, size_t size) +{ + size_t pagesize; + void *mmio; + + if (bar < 0 || bar >= sizeof(dev->mmio)) { + rtapi_print_msg(RTAPI_MSG_ERR, "Invalid PCI BAR %d\n", bar); + return NULL; + } + + pagesize = sysconf(_SC_PAGESIZE); + + mmio = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, + dev->fd, bar * pagesize); + if (mmio == NULL || mmio == MAP_FAILED) { + if (mmio == NULL) + munmap(mmio, size); + rtapi_print_msg(RTAPI_MSG_ERR, "Failed to remap MMIO %d of PCI device %s\n", + bar, dev->busid); + return NULL; + } + dev->mmio[bar].bar = bar; + dev->mmio[bar].mmio = mmio; + dev->mmio[bar].length = size; + dev->mmio_refcnt++; + + return mmio; +} + +void rtapi_pci_iounmap(struct rtapi_pcidev *dev, void *mmio) +{ + unsigned int i; + + if (!dev || !mmio) + return; + + for (i = 0; i < sizeof(dev->mmio); i++) { + if (dev->mmio[i].mmio == mmio) { + munmap(mmio, dev->mmio[i].length); + memset(&dev->mmio[i], 0, sizeof(dev->mmio[i])); + dev->mmio_refcnt--; + return; + } + } + rtapi_print_msg(RTAPI_MSG_ERR, "IO-unmap: Did not find PCI mapping %p", mmio); +} + +#include "rtapi/linux_common.h" diff --git a/src/rtapi/linux_rtapi_app.cc b/src/rtapi/linux_rtapi_app.cc new file mode 100644 index 000000000..89180b45b --- /dev/null +++ b/src/rtapi/linux_rtapi_app.cc @@ -0,0 +1,751 @@ +/* Copyright (C) 2006-2008 Jeff Epler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#include "rtapi.h" +#include "hal.h" +#include "hal/hal_priv.h" + +extern "C" { + int capset(cap_user_header_t hdrp, const cap_user_data_t datap); + int capget(cap_user_header_t hdrp, cap_user_data_t datap); +} + +using namespace std; + +#define SOCKET_PATH "\0/tmp/rtapi_fifo" + +/* Pre-allocation size. Must be enough for the whole application life to avoid + * pagefaults by new memory requested from the system. */ +#define PRE_ALLOC_SIZE (30 * 1024 * 1024) + + +template T DLSYM(void *handle, const string & name) +{ + return (T) (dlsym(handle, name.c_str())); +} + +template T DLSYM(void *handle, const char *name) +{ + return (T) (dlsym(handle, name)); +} + +static map modules; + +static int instance_count = 0; +static int force_exit = 0; + +static int do_newinst_cmd(string type, string name, string arg) +{ + void *module = modules["hal_lib"]; + if (!module) { + rtapi_print_msg(RTAPI_MSG_ERR, + "newinst: hal_lib is required, but not loaded\n"); + return -1; + } + + hal_comp_t *(*find_comp_by_name) (char *) = + DLSYM (module, + "halpr_find_comp_by_name"); + if (!find_comp_by_name) { + rtapi_print_msg(RTAPI_MSG_ERR, + "newinst: halpr_find_comp_by_name not found\n"); + return -1; + } + + hal_comp_t *comp = find_comp_by_name((char *)type.c_str()); + if (!comp) { + rtapi_print_msg(RTAPI_MSG_ERR, + "newinst: component %s not found\n", + type.c_str()); + return -1; + } + + return comp->make((char *)name.c_str(), (char *)arg.c_str()); +} + +static int do_one_item(char item_type_char, const string & param_name, + const string & param_value, void *vitem, int idx = 0) +{ + char *endp; + switch (item_type_char) { + case 'l':{ + long *litem = *(long **)vitem; + litem[idx] = strtol(param_value.c_str(), &endp, 0); + if (*endp) { + rtapi_print_msg(RTAPI_MSG_ERR, + "`%s' invalid for parameter `%s'", + param_value.c_str(), + param_name.c_str()); + return -1; + } + return 0; + } + case 'i':{ + int *iitem = *(int **)vitem; + iitem[idx] = strtol(param_value.c_str(), &endp, 0); + if (*endp) { + rtapi_print_msg(RTAPI_MSG_ERR, + "`%s' invalid for parameter `%s'", + param_value.c_str(), + param_name.c_str()); + return -1; + } + return 0; + } + case 's':{ + char **sitem = *(char ***)vitem; + sitem[idx] = strdup(param_value.c_str()); + return 0; + } + default: + rtapi_print_msg(RTAPI_MSG_ERR, + "%s: Invalid type character `%c'\n", + param_name.c_str(), item_type_char); + return -1; + } + return 0; +} + +void remove_quotes(string & s) +{ + s.erase(remove_copy(s.begin(), s.end(), s.begin(), '"'), s.end()); +} + +static int do_comp_args(void *module, vector args) +{ + for (unsigned i = 1; i < args.size(); i++) { + string & s = args[i]; + remove_quotes(s); + size_t idx = s.find('='); + if (idx == string::npos) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Invalid paramter `%s'\n", s.c_str()); + return -1; + } + string param_name(s, 0, idx); + string param_value(s, idx + 1); + void *item = + DLSYM < void *>(module, "rtapi_info_address_" + param_name); + if (!item) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Unknown parameter `%s'\n", s.c_str()); + return -1; + } + char **item_type = + DLSYM < char **>(module, "rtapi_info_type_" + param_name); + if (!item_type || !*item_type) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Unknown parameter `%s' (type information missing)\n", + s.c_str()); + return -1; + } + string item_type_string = *item_type; + + if (item_type_string.size() > 1) { + int a, b; + char item_type_char; + int r = sscanf(item_type_string.c_str(), "%d-%d%c", + &a, &b, &item_type_char); + if (r != 3) { + rtapi_print_msg(RTAPI_MSG_ERR, + "Unknown parameter `%s' (corrupt array type information)\n", + s.c_str()); + return -1; + } + size_t idx = 0; + int i = 0; + while (idx != string::npos) { + if (i == b) { + rtapi_print_msg(RTAPI_MSG_ERR, + "%s: can only take %d arguments\n", + s.c_str(), b); + return -1; + } + size_t idx1 = param_value.find(",", idx); + string substr(param_value, idx, idx1 - idx); + int result = + do_one_item(item_type_char, s, substr, item, + i); + if (result != 0) + return result; + i++; + idx = idx1 == string::npos ? idx1 : idx1 + 1; + } + } else { + char item_type_char = item_type_string[0]; + int result = + do_one_item(item_type_char, s, param_value, item); + if (result != 0) + return result; + } + } + return 0; +} + +static int do_load_cmd(string name, vector args) +{ + void *w = modules[name]; + if (w == NULL) { + char what[LINELEN + 1]; + snprintf(what, LINELEN, "%s/%s.so", EMC2_RTLIB_DIR, + name.c_str()); + void *module = modules[name] = + dlopen(what, RTLD_GLOBAL | RTLD_LAZY); + if (!module) { + rtapi_print_msg(RTAPI_MSG_ERR, "%s: dlopen: %s\n", + name.c_str(), dlerror()); + return -1; + } + /// XXX handle arguments + int (*start) (void) = + DLSYM(module, "rtapi_app_main"); + if (!start) { + rtapi_print_msg(RTAPI_MSG_ERR, "%s: dlsym: %s\n", + name.c_str(), dlerror()); + return -1; + } + int result; + + result = do_comp_args(module, args); + if (result < 0) { + dlclose(module); + return -1; + } + + if ((result = start()) < 0) { + rtapi_print_msg(RTAPI_MSG_ERR, + "%s: rtapi_app_main: %d\n", + name.c_str(), result); + return result; + } else { + instance_count++; + return 0; + } + } else { + rtapi_print_msg(RTAPI_MSG_ERR, "%s: already exists\n", + name.c_str()); + return -1; + } +} + +static int do_unload_cmd(string name) +{ + void *w = modules[name]; + if (w == NULL) { + rtapi_print_msg(RTAPI_MSG_ERR, "%s: not loaded\n", + name.c_str()); + return -1; + } else { + int (*stop) (void) = + DLSYM(w, "rtapi_app_exit"); + if (stop) + stop(); + modules.erase(modules.find(name)); + dlclose(w); + instance_count--; + } + return 0; +} + +static int read_number(int fd) +{ + int r = 0, neg = 1; + char ch; + + while (1) { + int res = read(fd, &ch, 1); + if (res != 1) + return -1; + if (ch == '-') + neg = -1; + else if (ch == ' ') + return r * neg; + else + r = 10 * r + ch - '0'; + } +} + +static string read_string(int fd) +{ + int len = read_number(fd); + char buf[len]; + read(fd, buf, len); + return string(buf, len); +} + +static vector read_strings(int fd) +{ + vector result; + int count = read_number(fd); + for (int i = 0; i < count; i++) { + result.push_back(read_string(fd)); + } + return result; +} + +static void write_number(string &buf, int num) +{ + char numbuf[10]; + sprintf(numbuf, "%d ", num); + buf = buf + numbuf; +} + +static void write_string(string &buf, string s) +{ + write_number(buf, s.size()); + buf += s; +} + +static void write_strings(int fd, vector strings) +{ + string buf; + write_number(buf, strings.size()); + for (unsigned int i = 0; i < strings.size(); i++) { + write_string(buf, strings[i]); + } + write(fd, buf.data(), buf.size()); +} + +static int handle_command(vector args) +{ + if (args.size() == 0) { + return 0; + } + if (args.size() == 1 && args[0] == "exit") { + force_exit = 1; + return 0; + } else if (args.size() >= 2 && args[0] == "load") { + string name = args[1]; + args.erase(args.begin()); + return do_load_cmd(name, args); + } else if (args.size() == 2 && args[0] == "unload") { + return do_unload_cmd(args[1]); + } else if (args.size() == 3 && args[0] == "newinst") { + return do_newinst_cmd(args[1], args[2], ""); + } else if (args.size() == 4 && args[0] == "newinst") { + return do_newinst_cmd(args[1], args[2], args[3]); + } else { + rtapi_print_msg(RTAPI_MSG_ERR, + "Unrecognized command starting with %s\n", + args[0].c_str()); + return -1; + } +} + +static int slave(int fd, vector args) +{ + write_strings(fd, args); + int result = read_number(fd); + return result; +} + +static int master(int fd, vector args) +{ + dlopen(NULL, RTLD_GLOBAL); + do_load_cmd("hal_lib", vector()); + instance_count = 0; + if (args.size()) { + int result = handle_command(args); + if (result != 0) + return result; + if (force_exit || instance_count == 0) + return 0; + } + do { + struct sockaddr_un client_addr; + memset(&client_addr, 0, sizeof(client_addr)); + socklen_t len = sizeof(client_addr); + + int fd1 = accept(fd, (sockaddr *) & client_addr, &len); + if (fd1 < 0) { + perror("accept"); + return -1; + } else { + int result = handle_command(read_strings(fd1)); + string buf; + write_number(buf, result); + write(fd1, buf.data(), buf.size()); + close(fd1); + } + } while (!force_exit && instance_count > 0); + + return 0; +} + +static int configure_memory(void) +{ + unsigned int i, pagesize; + char *buf; + + /* Lock all memory. This includes all current allocations (BSS/data) + * and future allocations. */ + if (mlockall(MCL_CURRENT | MCL_FUTURE)) { + perror("Failed to lock memory (mlockall)"); + return 1; + } + /* Turn off malloc trimming.*/ + mallopt(M_TRIM_THRESHOLD, -1); + /* Turn off mmap usage. */ + mallopt(M_MMAP_MAX, 0); + + buf = static_cast(malloc(PRE_ALLOC_SIZE)); + pagesize = sysconf(_SC_PAGESIZE); + /* Touch each page in this piece of memory to get it mapped into RAM */ + for (i = 0; i < PRE_ALLOC_SIZE; i += pagesize) { + /* Each write to this buffer will generate a pagefault. + * Once the pagefault is handled a page will be locked in + * memory and never given back to the system. */ + buf[i] = 0; + } + /* buffer will now be released. As Glibc is configured such that it + * never gives back memory to the kernel, the memory allocated above is + * locked for this process. All malloc() and new() calls come from + * the memory pool reserved and locked above. Issuing free() and + * delete() does NOT make this locking undone. So, with this locking + * mechanism we can build C++ applications that will never run into + * a major/minor pagefault, even with swapping enabled. */ + free(buf); + + return 0; +} + +/* Get the number of CPUs in the system. */ +static unsigned int get_number_of_cpus(void) +{ + char buf[256] = { 0, }; + ifstream fd; + string line; + + static unsigned int nr_cpus; + + if (nr_cpus) + return nr_cpus; + + fd.open("/proc/cpuinfo"); + if (!fd) { + cerr << "Failed to open /proc/cpuinfo" << endl; + return 0; + } + while (fd.getline(buf, sizeof(buf) - 1)) { + line = buf; + if (line.substr(0, 9) == "processor") + nr_cpus++; + } + if (!nr_cpus) + cerr << "Found zero CPUs in the system. Confused..." << endl; + + return nr_cpus; +} + +/* Get cpuset-FS mountpoint. */ +static string cpusetfs_mountpoint(void) +{ + char buf[256] = { 0, }; + ifstream fd; + bool ok; + string::size_type start, length; + string line; + + static string mountpoint; + + if (mountpoint.size()) + return mountpoint; + + fd.open("/proc/mounts"); + if (!fd) + goto error; + ok = false; + while (fd.getline(buf, sizeof(buf) - 1)) { + line = buf; + if (line.find("cpuset") != string::npos) { + ok = true; + break; + } + } + if (!ok) + goto error; + start = line.find_first_of(" \t"); + if (start == string::npos) + goto error; + start++; + length = line.find_first_of(" \t"); + if (length == string::npos) + goto error; + mountpoint = line.substr(start, length); + +// cout << "cpuset-FS mount point: " << mountpoint << endl; + + return mountpoint; +error: + cerr << "Could not find cpusetfs mount point" << endl; + return ""; +} + +#define CPUSET_NAME "emc2_realtime" + +static int reset_cpusets(void) +{ + unsigned int nr_cpus; + string mountpoint; + + nr_cpus = get_number_of_cpus(); + if (nr_cpus < 2) + return -1; + mountpoint = cpusetfs_mountpoint(); + if (!mountpoint.size()) + return -1; + + rmdir(string(mountpoint + "/" + CPUSET_NAME).c_str()); + + return 0; +} + +extern "C" int realtime_cpuset_add_task(pid_t pid) +{ + string mountpoint, dir; + unsigned int nr_cpus; + ofstream fd; + char buf[32]; + +return 0; + nr_cpus = get_number_of_cpus(); + if (!nr_cpus) + return -1; + if (nr_cpus < 2) + return 0; + mountpoint = cpusetfs_mountpoint(); + if (!mountpoint.size()) + return -1; + dir = mountpoint + "/" + CPUSET_NAME; + + fd.open(string(dir + "/tasks").c_str()); + if (!fd) + return -1; + snprintf(buf, sizeof(buf), "%u\n", (unsigned int)pid); + fd.write(buf, strlen(buf)); + if (!fd) + return -1; + fd.close(); + + return 0; +} + +static int configure_cpusets(void) +{ + unsigned int nr_cpus; + string mountpoint, dir; + int err; + ofstream fd; + char buf[32]; + +return 0; + nr_cpus = get_number_of_cpus(); + if (!nr_cpus) + return -1; + if (nr_cpus < 2) + return 0; /* No need to configure cpusets. */ + + reset_cpusets(); + + mountpoint = cpusetfs_mountpoint(); + if (!mountpoint.size()) + return -1; + + /* Create the new cpuset for realtime tasks. */ + dir = mountpoint + "/" + CPUSET_NAME; + err = mkdir(dir.c_str(), 0644); + if (err && errno != EEXIST) { + cerr << "Failed to create cpuset: " << strerror(errno) << endl; + return -1; + } + + /* Set cpu_exclusive */ + fd.open(string(dir + "/cpu_exclusive").c_str()); + if (!fd) { + cerr << "Failed to open cpuset cpu_exclusive file" << endl; + reset_cpusets(); + return -1; + } + snprintf(buf, sizeof(buf), "%u\n", 1); + fd.write(buf, strlen(buf)); + if (!fd) { + cerr << "Failed to write cpuset cpu_exclusive file" << endl; + reset_cpusets(); + return -1; + } + fd.close(); + + /* Put the last CPU into the set. */ + fd.open(string(dir + "/cpus").c_str()); + if (!fd) { + cerr << "Failed to open cpuset cpus file" << endl; + reset_cpusets(); + return -1; + } + snprintf(buf, sizeof(buf), "%u-%u\n", nr_cpus - 1, nr_cpus - 1); + fd.write(buf, strlen(buf)); + if (!fd) { + cerr << "Failed to write cpuset cpus file" << endl; + reset_cpusets(); + return -1; + } + fd.close(); + + /* Put the first NUMA node into the set. + * This probably needs fixing for NUMA machines. */ + fd.open(string(dir + "/mems").c_str()); + if (!fd) { + cerr << "Failed to open cpuset mems file" << endl; + reset_cpusets(); + return -1; + } + snprintf(buf, sizeof(buf), "%u\n", 0); + fd.write(buf, strlen(buf)); + if (!fd) { + cerr << "Failed to write cpuset mems file" << endl; + reset_cpusets(); + return -1; + } + fd.close(); + + /* Remove the last CPU from the root-set. */ + //FIXME that doesn't work + fd.open(string(mountpoint + "/cpus").c_str()); + if (!fd) { + cerr << "Failed to open root cpuset cpus file" << endl; + reset_cpusets(); + return -1; + } + snprintf(buf, sizeof(buf), "%u-%u\n", 0, nr_cpus - 2); + fd.write(buf, strlen(buf)); + if (!fd) { + cerr << "Failed to write root cpuset cpus file" << endl; + reset_cpusets(); + return -1; + } + fd.close(); + + return 0; +} + +int main(int argc, char **argv) +{ + /* Request RAW-I/O */ + if (iopl(3)) { + perror("Failed to request RAW-I/O permissions (iopl)"); + return 1; + } + if (configure_memory()) + return 1; + +#if 0 + cap_user_header_t header; + cap_user_data_t data; + capget(header, data); + data->effective |= CAP_SYS_NICE | CAP_SYS_RAWIO; + if (capset(header, data) != 0) { + perror("capset"); + } + seteuid(getuid()); +#endif + + vector args; + for (int i = 1; i < argc; i++) { + args.push_back(string(argv[i])); + } + +become_master: + int fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + perror("socket"); + exit(1); + } + + int enable = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)); + struct sockaddr_un addr = { AF_UNIX, SOCKET_PATH }; + int result = bind(fd, (sockaddr *)&addr, sizeof(addr)); + + if (result == 0) { + if (configure_cpusets()) + return 1; + int result = listen(fd, 10); + if (result != 0) { + perror("listen"); + exit(1); + } + result = master(fd, args); + unlink(SOCKET_PATH); + reset_cpusets(); + return result; + } else if (errno == EADDRINUSE) { + struct timeval t0, t1; + gettimeofday(&t0, NULL); + gettimeofday(&t1, NULL); + for (int i = 0; i < 3 || (t1.tv_sec < 3 + t0.tv_sec); i++) { + result = connect(fd, (sockaddr *)&addr, sizeof(addr)); + if (result == 0) + break; + if (i == 0) + srand48(t0.tv_sec ^ t0.tv_usec); + usleep(lrand48() % 100000); + gettimeofday(&t1, NULL); + } + if (result < 0 && errno == ECONNREFUSED) { + unlink(SOCKET_PATH); + fprintf(stderr, + "Waited 3 seconds for master. giving up.\n"); + close(fd); + goto become_master; + } + if (result < 0) { + perror("connect"); + exit(1); + } + return slave(fd, args); + } else { + perror("bind"); + exit(1); + } +} diff --git a/src/rtapi/linux_ulapi.c b/src/rtapi/linux_ulapi.c new file mode 100644 index 000000000..fd3f5d839 --- /dev/null +++ b/src/rtapi/linux_ulapi.c @@ -0,0 +1,63 @@ +/******************************************************************** +* Description: linux_ulapi.c +* This file, 'linux_ulapi.c', implements the user-level +* API functions for machines with Linux-realtime +* +* Author: John Kasunich, Paul Corner +* Copyright (c) 2004 All rights reserved. +* +* License: LGPL Version 2 +* +********************************************************************/ + +#include /* NULL */ +#include /* printf */ +#include /* malloc(), free() */ +#include +#include +#include +#include "rtapi.h" +#include + +int rtapi_init(const char *modname) +{ + /* does nothing, for now */ + return getpid(); +} + +int rtapi_exit(int module_id) +{ + /* does nothing, for now */ + return 0; +} + +/* FIXME - no support for fifos */ + +int rtapi_fifo_new(int key, int module_id, unsigned long int size, char mode) +{ + return -ENOSYS; +} + +int rtapi_fifo_delete(int fifo_id, int module_id) +{ + return -ENOSYS; +} + +int rtapi_fifo_read(int fifo_id, char *buf, unsigned long size) +{ + return -ENOSYS; +} + +int rtapi_fifo_write(int fifo_id, char *buf, unsigned long int size) +{ + return -ENOSYS; +} + +long long rtapi_get_time(void) +{ + struct timeval tv; + gettimeofday(&tv, 0); + return tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000; +} + +#include "rtapi/linux_common.h" diff --git a/src/rtapi/rtapi.h b/src/rtapi/rtapi.h index b67499fc8..f1f647f6c 100644 --- a/src/rtapi/rtapi.h +++ b/src/rtapi/rtapi.h @@ -59,6 +59,8 @@ information, go to www.linuxcnc.org. */ +#include "config.h" + #if ( !defined RTAPI ) && ( !defined ULAPI ) #error "Please define either RTAPI or ULAPI!" #endif @@ -72,7 +74,26 @@ only. Since we have a simulator that runs everything in user space, the non-underscore types should NEVER be used. */ -#include +#ifdef RTAPI_LINUX +# include +# include +typedef uint8_t u8; +typedef uint8_t __u8; +typedef uint16_t u16; +typedef uint16_t __u16; +typedef uint32_t u32; +typedef uint32_t __u32; +typedef int8_t s8; +typedef int8_t __s8; +typedef int16_t s16; +typedef int16_t __s16; +typedef int32_t s32; +typedef int32_t __s32; +#define __iomem /* Nothing */ +#else +# include +#endif + #include #define RTAPI_NAME_LEN 31 /* length for module, etc, names */ @@ -721,7 +742,21 @@ RTAPI_BEGIN_DECLS */ extern unsigned char rtapi_inb(unsigned int port); -#if defined(RTAPI) && !defined(SIM) +/** 'rtapi_outw() writes 'word' to 'port'. May be called from + init/cleanup code, and from within realtime tasks. + Note: This function does nothing on the simulated RTOS. + Note: Many platforms provide an inline outw() that is faster. +*/ + extern void rtapi_outw(unsigned short word, unsigned int port); + +/** 'rtapi_inw() gets a word from 'port'. Returns the word. May + be called from init/cleanup code, and from within realtime tasks. + Note: This function always returns zero on the simulated RTOS. + Note: Many platforms provide an inline inw() that is faster. +*/ + extern unsigned short rtapi_inw(unsigned int port); + +#if (defined(RTAPI) && !defined(SIM)) || defined(RTAPI_LINUX) /** 'rtapi_request_region() reserves I/O memory starting at 'base', going for 'size' bytes, for component 'name'. @@ -731,11 +766,13 @@ RTAPI_BEGIN_DECLS a non-NULL value. */ #include -#include +#ifndef RTAPI_LINUX +# include +#endif static __inline__ void *rtapi_request_region(unsigned long base, unsigned long size, const char *name) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) && !defined(RTAPI_LINUX) return (void*)request_region(base, size, name); #else return (void*)-1; @@ -749,12 +786,108 @@ RTAPI_BEGIN_DECLS */ static __inline__ void rtapi_release_region(unsigned long base, unsigned long int size) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) && !defined(RTAPI_LINUX) release_region(base, size); #endif } #endif +/*********************************************************************** +* PCI DEVICE SUPPORT * +************************************************************************/ + +/** struct rtapi_pcidev - Opaque data structure for the PCI device */ +struct rtapi_pcidev; + +/** rtapi_pci_get_device - Find a PCI device + * @vendor: The vendor ID to search for + * @device: The device ID to search for + * @from: The device to start searching from. Can be NULL. + */ +extern +struct rtapi_pcidev * rtapi_pci_get_device(__u16 vendor, __u16 device, + struct rtapi_pcidev *from); + +/** rtapi_pci_put_device - Free a PCI device obtained by rtapi_pci_get_device() */ +extern +void rtapi_pci_put_device(struct rtapi_pcidev *dev); + +/** rtapi_pci_ioremap - Remap I/O memory + * Returns NULL on error. + * @dev: The device + * @bar: The PCI BAR to remap. + * @size: The size of the mapping. + */ +extern +void __iomem * rtapi_pci_ioremap(struct rtapi_pcidev *dev, int bar, size_t size); + +/** rtapi_pci_iounmap - Unmap an MMIO region + * @dev: The device + * @mmio: The MMIO region obtained by rtapi_pci_ioremap() + */ +extern +void rtapi_pci_iounmap(struct rtapi_pcidev *dev, void __iomem *mmio); + +static inline +__u8 rtapi_pci_readb(const void __iomem *mmio) +{ +#ifdef RTAPI_LINUX + return *((volatile const __u8 __iomem *)mmio); +#else + return readb(mmio); +#endif +} + +static inline +__u16 rtapi_pci_readw(const void __iomem *mmio) +{ +#ifdef RTAPI_LINUX + return *((volatile const __u16 __iomem *)mmio); +#else + return readw(mmio); +#endif +} + +static inline +__u32 rtapi_pci_readl(const void __iomem *mmio) +{ +#ifdef RTAPI_LINUX + return *((volatile const __u32 __iomem *)mmio); +#else + return readl(mmio); +#endif +} + +static inline +void rtapi_pci_writeb(void __iomem *mmio, unsigned int offset, __u8 value) +{ +#ifdef RTAPI_LINUX + *((volatile __u8 __iomem *)mmio) = value; +#else + writeb(value, mmio); +#endif +} + +static inline +void rtapi_pci_writew(void __iomem *mmio, unsigned int offset, __u16 value) +{ +#ifdef RTAPI_LINUX + *((volatile __u16 __iomem *)mmio) = value; +#else + writew(value, mmio); +#endif +} + +static inline +void rtapi_pci_writel(void __iomem *mmio, unsigned int offset, __u32 value) +{ +#ifdef RTAPI_LINUX + *((volatile __u32 __iomem *)mmio) = value; +#else + writel(value, mmio); +#endif +} + /*********************************************************************** * MODULE PARAMETER MACROS * ************************************************************************/ diff --git a/src/rtapi/rtapi_bitops.h b/src/rtapi/rtapi_bitops.h index 2b2a9b521..81045c7a6 100644 --- a/src/rtapi/rtapi_bitops.h +++ b/src/rtapi/rtapi_bitops.h @@ -24,7 +24,7 @@ static __inline__ void set_bit(int nr, volatile void * addr) { __asm__ __volatile__( "btsl %1,%0" - :"=m" (ADDR) + :"+m" (ADDR) :"Ir" (nr)); } @@ -72,7 +72,7 @@ static __inline__ void clear_bit(int nr, volatile void * addr) { __asm__ __volatile__( "btrl %1,%0" - :"=m" (ADDR) + :"+m" (ADDR) :"Ir" (nr)); } @@ -90,7 +90,7 @@ static __inline__ int test_and_set_bit(int nr, volatile void * addr) __asm__ __volatile__( LOCK_PREFIX "btsl %2,%1\n\tsbbl %0,%0" - :"=r" (oldbit),"=m" (ADDR) + :"=r" (oldbit),"+m" (ADDR) :"Ir" (nr) : "memory"); return oldbit; } @@ -110,7 +110,7 @@ static __inline__ int test_and_clear_bit(int nr, volatile void * addr) __asm__ __volatile__( "btrl %2,%1\n\tsbbl %0,%0" - :"=r" (oldbit),"=m" (ADDR) + :"=r" (oldbit),"+m" (ADDR) :"Ir" (nr) : "memory"); return oldbit; } @@ -138,7 +138,7 @@ static __inline__ void set_bit(int nr, volatile void * addr) { __asm__ __volatile__( LOCK_PREFIX "btsl %1,%0" - :"=m" (ADDR) + :"+m" (ADDR) :"dIr" (nr) : "memory"); } @@ -157,7 +157,7 @@ static __inline__ void clear_bit(int nr, volatile void * addr) { __asm__ __volatile__( LOCK_PREFIX "btrl %1,%0" - :"=m" (ADDR) + :"+m" (ADDR) :"dIr" (nr)); } @@ -198,9 +198,10 @@ static __inline__ int test_and_set_bit(int nr, volatile void * addr) __asm__ __volatile__( LOCK_PREFIX "btsl %2,%1\n\tsbbl %0,%0" - :"=r" (oldbit),"=m" (ADDR) + :"=r" (oldbit),"+m" (ADDR) :"dIr" (nr) : "memory"); return oldbit; + } /** @@ -217,7 +218,7 @@ static __inline__ int test_and_clear_bit(int nr, volatile void * addr) __asm__ __volatile__( LOCK_PREFIX "btrl %2,%1\n\tsbbl %0,%0" - :"=r" (oldbit),"=m" (ADDR) + :"=r" (oldbit),"+m" (ADDR) :"dIr" (nr) : "memory"); return oldbit; } diff --git a/tests/hm2-idrom/skip b/tests/hm2-idrom/skip index 9ab677af6..28fa3df1e 100755 --- a/tests/hm2-idrom/skip +++ b/tests/hm2-idrom/skip @@ -1,7 +1,7 @@ #!/bin/sh . rtapi.conf -if [ "$RTPREFIX" = sim ]; then +if [ "$RTPREFIX" = sim -o "$RTPREFIX" = linux ]; then exit 1 fi