[Linux-parport] Parport irq handler patch
Eerin Rosenström
eerin.rosenstrom at xylogas.fi
Sun Dec 6 07:26:19 EST 2009
> Frederick Barnes (frmb at mail.cern.ch)
> Sun, 26 Sep 1999 11:21:03 +0200 (CEST)
>
> Hi,
>
> I've added two IOCTLs to ppdev to get and set the device timeout (as set
Hi, now ten years later I added three more IOCTLs to improve port usage in
time sensitive tasks.
Broblem:
I have (turbine) axle that turns ~120rpm and I want measure it speed.
Simple circuit that feeds pulses to parport irq pin and linux handles
rest.
With userspace select() irq wait I ended to find only kernel internal
timings jitter.
Solution is quite simpe - move time recording to kernel irq handler.
If use rdtsc instruction it make almost zero overheard.
I used kernel getnstimeofday() for compatibility.
Some fast moving signals it is good that kernel also record status port.
It is quite easy add more irq handlers features. I used only three bits of
irqresponse vector.
Feel free to modify that patch.
I wonder why that don't exist yet?
I keep it 100% sure that I can do timings with linux parport..
It wasn't fun to find it unusable idea..
But now it is here, enjoy
Main idea is to make free (GPL) software and simple parport circuit for
genset monitoring, speed controlling and syncronized connection to mains.
Old PCs are junk and there are millions standalone gensets.
If interested, drop mail. I am not parport list subscriber.
ICTLs explanation
SIRQHDLR selects which irq handlers are active. Bit0 is old "write byte to
control" method.
Bit1 is time recording handler
Bit2 is status recorder. It may generate some (hardware) latency, but
people who use it can tolerate situation..
TSCONIRQ, returns struct timeval from last irq
RSTAONIRQ, returns status register from last irq
These boost timings accuracy ~two decades
Comments?
My C skills are quite limited (8 years ago one C prog course, no C coding
after it) It take whole day for me
to do and test such simpe patch..
So feel free to make my patch better.
I used 2.6.31 vanilla sources.
/usr/include/linux/ppdev.h may need patch too if system have it
standalone.
--- include/linux/ppdev-orig.h 2009-12-04 15:41:20.000000000 +0200
+++ include/linux/ppdev.h 2009-12-04 17:30:08.000000000 +0200
@@ -88,6 +88,13 @@
#define PPGETFLAGS _IOR(PP_IOCTL, 0x9a, int)
#define PPSETFLAGS _IOW(PP_IOCTL, 0x9b, int)
+/* set irq handler behavior */
+#define SIRQHDLR _IOW(PP_IOCTL, 0x9c, int)
+
+/* get time and statusreg on irq */
+#define TSCONIRQ _IOR(PP_IOCTL, 0x9d, struct timeval)
+#define RSTAONIRQ _IOR(PP_IOCTL, 0x9e, int)
+
/* flags visible to the world */
#define PP_FASTWRITE (1<<2)
#define PP_FASTREAD (1<<3)
--- drivers/char/ppdev-orig.c 2009-12-04 15:04:57.000000000 +0200
+++ drivers/char/ppdev.c 2009-12-05 15:37:20.000000000 +0200
@@ -41,6 +41,9 @@
* GETPHASE gets the current IEEE1284 phase
* GETFLAGS gets current (user-visible) flags
* SETFLAGS sets current (user-visible) flags
+ * SIRQHDLR select irq handler (bits 0, 1, 2 currently, 0=WCTLONIRQ,
1=TSCONIRQ, 2=RCTLONIRQ )
+ * TSCONIRQ rctsc on interrupt
+ * RSTAONIRQ status on interrupt
* read/write read or write in current IEEE 1284 protocol
* select wait for interrupt (in readfds)
*
@@ -54,6 +57,14 @@
*
* Added GETMODES/GETMODE/GETPHASE ioctls, Fred Barnes <frmb2 at ukc.ac.uk>,
03/01/2001.
* Added GETFLAGS/SETFLAGS ioctls, Fred Barnes, 04/2001
+ *
+ * Added ioctls to boost port timings usage, Eerin Rosenström
<eros at iki.fi>, 4.12.2009
+ * SIRQHDLR - select irq handler
+ * TSCONIRQ - rctsc on interrupt
+ * RSTAONIRQ - control on interrupt
+ * #define SIRQHDLR _IOW(PP_IOCTL, 0x9c, int)
+ * #define TSCONIRQ _IOR(PP_IOCTL, 0x9d, struct timeval)
+ * #define RSTAONIRQ _IOR(PP_IOCTL, 0x9e, int)
*/
#include <linux/module.h>
@@ -77,11 +88,13 @@
wait_queue_head_t irq_wait;
atomic_t irqc;
unsigned int flags;
- int irqresponse;
+ unsigned int irqresponse;
unsigned char irqctl;
struct ieee1284_info state;
struct ieee1284_info saved_state;
long default_inactivity;
+ struct timespec irqtv;
+ unsigned char irqsta;
};
/* pp_struct.flags bitfields */
@@ -270,9 +283,17 @@
{
struct pp_struct *pp = private;
- if (pp->irqresponse) {
- parport_write_control (pp->pdev->port, pp->irqctl);
- pp->irqresponse = 0;
+ if ((pp->irqresponse) & (1 << 0)) { //
0bit=1
+ parport_write_control (pp->pdev->port, pp->irqctl); //
write to control
+ pp->irqresponse &= ~(1 << 0); //
0bit=0
+ }
+
+ if ((pp->irqresponse) & (1 << 1)) { //
1bit=1, save time
+ getnstimeofday(&pp->irqtv);
+ }
+
+ if ((pp->irqresponse) & (1 << 2)) { //
2bit=1, read status
+ pp->irqsta = parport_read_status (pp->pdev->port);
}
atomic_inc (&pp->irqc);
@@ -585,7 +606,7 @@
/* Remember what to set the control lines to, for next
* time we get an interrupt. */
pp->irqctl = reg;
- pp->irqresponse = 1;
+ pp->irqresponse |= (1 << 0); //
set 0bit=1 to trigger ctrl write
return 0;
case PPCLRIRQ:
@@ -619,6 +640,25 @@
return -EFAULT;
return 0;
+ case SIRQHDLR:
+ if (copy_from_user (®, argp, sizeof (reg)))
+ return -EFAULT;
+ pp->irqresponse = reg;
+ return 0;
+
+ case TSCONIRQ:
+ par_timeout.tv_sec = pp->irqtv.tv_sec;
// recycled par_timeout, thanks Barnes
+ par_timeout.tv_usec = ((pp->irqtv.tv_nsec) / 1000) ;
+ if (copy_to_user (argp, &par_timeout, sizeof(struct
timeval)))
+ return -EFAULT;
+ return 0;
+
+ case RSTAONIRQ:
+ reg = pp->irqsta;
+ if (copy_to_user (argp, ®, sizeof (reg)))
+ return -EFAULT;
+ return 0;
+
default:
pr_debug(CHRDEV "%x: What? (cmd=0x%x)\n", minor, cmd);
return -EINVAL;
@@ -653,7 +693,7 @@
pp->state.mode = IEEE1284_MODE_COMPAT;
pp->state.phase = init_phase (pp->state.mode);
pp->flags = 0;
- pp->irqresponse = 0;
+ pp->irqresponse = 0x00; // turn
irq handlers off
atomic_set (&pp->irqc, 0);
init_waitqueue_head (&pp->irq_wait);
More information about the Linux-parport
mailing list