Browse Source

Work on input driver using Linux syscalls.

Beoran 4 years ago
parent
commit
17edcf3d7f

+ 66 - 0
controller/controller.go

@@ -0,0 +1,66 @@
+package gamepad
+
+
+var Driver ControllerDriver = nil 
+
+func Install(out chan<-Event) {
+    Driver = InstallDriver(out)
+}
+
+
+func Uninstall() {
+   if (Driver != nil) {
+        Driver.Exit()
+        Driver = nil
+    }
+}
+
+
+func IsInstalled() bool {
+    return Driver != nil
+}
+
+func Recofigure() bool {
+    if Driver == nil {
+        return false
+    }
+    return Driver.Reconfigure()
+
+}
+
+
+func Source() Driver {
+    return Driver
+}
+
+func emitEvent(event Event) {
+    Driver.Emit(event)
+}
+
+
+func NumberOfControllers() int {
+    if Driver == nil {
+        return 0
+    }
+    return Driver.NumberOfControllers()
+}
+
+type Controller interface {
+    Release() error
+    Active() bool
+    Name() string
+    NumberOfAxes() int
+    NumberOfButtons() int
+    Flags() int
+} 
+
+func ControllerById(id int) Controller {
+    if Driver == nil {
+        return nil
+    }
+    if id < 0 || id >= NumberOfControllers() {
+        return nil
+    } 
+    return Driver.ControllerById()    
+} 
+

+ 22 - 0
controller/controller_linux.go

@@ -0,0 +1,22 @@
+package controller
+
+
+// suseconds_t varies by platform, 32 on 32 bits, 64 on 64 bits
+type suseconds_t = long
+// time_t is aways 64 bits signed, even on 32 bits platforms.
+type time_t = int64
+
+// A time value that is accurate to the nearest
+// microsecond but also has a range of years.
+type timeval struct {
+    tv_sec time_t	// Seconds.
+    tv_usec susecond_t  // Microseconds.
+}
+
+
+
+
+
+
+
+

+ 1 - 0
controller/haptic.go

@@ -0,0 +1 @@
+package gamepad

+ 3 - 0
controller/haptic_linux.go

@@ -0,0 +1,3 @@
+package gamepad
+
+

+ 228 - 0
event/event.go

@@ -0,0 +1,228 @@
+// Copyright 2019 Beoran
+//
+// Licensed under the MIT LICENSE.
+
+// Package event is a package that models events that occur during
+// the execution of a program.
+package event
+
+// Event is an interface that custom events should implement.
+// It is empty for now because there are no general methods
+// required of events yet.
+type Event interface {
+}
+
+// KeyCharacter is an event that occurs when a character is actually typed on
+// the keyboard. This may be provided by an input method.
+type KeyCharacter struct {
+	// Code is the key code of the key typed.
+	// TODO: this should change later from an int to an enumeration type.
+	Code int
+	// Modifiers are the modifiers pressed together with the key.
+	// TODO: this should change later from an int to an enumeration type.
+	Modifiers int
+	// Character is the character that was typed.
+	Character rune
+}
+
+// KeyDown is an event that occurs when a key is pressed on the keyboard.
+type KeyDown struct {
+	// Code is the key code of the key pressed or released.
+	// TODO: this should change later from an int to an enumeration type.
+	Code int
+	// Modifiers are the modifiers pressed together with the key.
+	// TODO: this should change later from an int to an enumeration type.
+	Modifiers int
+}
+
+// KeyUp is an event that occurs when a key is released on the keyboard.
+// The data is the same as for a KeyDown event.
+type KeyUp KeyDown
+
+// GamepadAxis is for event where an axis on a gamepad changes.
+type GamepadAxis struct {
+	// ID represents which gamepad caused the event.
+	ID int
+	// Axis is the axis of the game pad that changed position.
+	Axis int
+	// Position is the psoition of the axis after the change.
+	// It varies between -1.0 and 1.0.
+	Position float32
+}
+
+// GamepadButtonDown is a gamepad button press event.
+type GamepadButtonDown struct {
+	// ID represents which gamepad caused the event.
+	ID int
+	// Button is the button that was pressed on the game pad.
+	Button int
+	// Pressure is the pressure that is applied to the gamepad button.
+	// It varies between 0.0 for not pressed, and 1.0 for completely pressed.
+	Pressure float32
+}
+
+// GamepadButtonDown is a gamepad button release event.
+// The data is identical to a GamePadButtonDown event.
+type GamepadButtonUp GamepadButtonDown
+
+// GamepadAttach happens when a new gamepad is attached.
+type GamepadAttach struct {
+	// ID represents which gamepad caused the event.
+	ID int
+	// Axes represents the amount of axes the gamepad has.
+	Axes int
+	// Buttons represents the amount of buttons the gamepad has.
+	Buttons int
+}
+
+// GamepadDetach happens when a gamepad is detached.
+type GamepadDetach struct {
+	// ID represents which gamepad caused the event.
+	ID int
+}
+
+// MouseMove is a mouse movement event.
+type MouseMove struct {
+	// X is the X position of the mouse pointer.
+	// This value is expressed in device independent pixels.
+	X float32
+	// Y is the Y position of the mouse pointer.
+	// This value is expressed in device independent pixels.
+	Y float32
+	// DeltaX is the change in X since the last MouseMove event.
+	// This value is expressed in device independent pixels.
+	DeltaX float32
+	// DeltaY is the change in Y since the last MouseMove event.
+	// This value is expressed in device independent pixels.
+	DeltaY float32
+}
+
+// MouseWheel is a mouse wheel event.
+type MouseWheel struct {
+	// X is the X position of the mouse wheel.
+	// This value is expressed in arbitrary units.
+	// It increases when the mouse wheel is scrolled downwards,
+	// and decreases when the mouse is scrolled upwards.
+	X float32
+	// Y is the Y position of the mouse wheel.
+	// This value is expressed in arbitrary units.
+	// It increases when the mouse wheel is scrolled to the right,
+	// and decreases when the mouse is scrolled to the left.
+	Y float32
+	// DeltaX is the change in X since the last MouseWheel event.
+	// This value is expressed in arbitrary units.
+	// It is positive when the mouse wheel is scrolled downwards,
+	// and negative when the mouse is scrolled upwards.
+	DeltaX float32
+	// DeltaY is the change in Y since the last MouseWheel event.
+	// This value is expressed in arbitrary units.
+	// It is positive when the mouse wheel is scrolled to the right,
+	// and negative when the mouse is scrolled to the left.
+	DeltaY float32
+}
+
+// MouseButtonDown is a mouse button press event.
+type MouseButtonDown struct {
+	// X is the X position of the mouse pointer.
+	// This value is expressed in device independent pixels.
+	X float32
+	// Y is the Y position of the mouse pointer.
+	// This value is expressed in device independent pixels.
+	Y float32
+	// Button is the button on the mouse that was pressed.
+	// TODO: this should change later from an int to an enumeration type.
+	Button int
+	// Pressure is the pressure applied on the mouse button.
+	// It varies between 0.0 for not pressed, and 1.0 for completely pressed.
+	Pressure float32
+}
+
+// MouseButtonDown is a mouse button Release event.
+// The data is identical to a MouseButtonDown event.
+type MouseButtonUp MouseButtonDown
+
+// MouseEnter occurs when the mouse enters the view window.
+type MouseEnter struct {
+	// X is the X position of the mouse pointer.
+	// This value is expressed in device independent pixels.
+	X float32
+	// Y is the Y position of the mouse pointer.
+	// This value is expressed in device independent pixels.
+	Y float32
+}
+
+// MouseLeave occurs when the mouse leaves the view window.
+// The data is identical to MouseEnter.
+type MouseLeave MouseEnter
+
+// ViewUpdate occurs when the application is ready to update
+// the next frame on the view port.
+type ViewUpdate struct {
+	// No data neccesary, for now.
+}
+
+// ViewSize occurs when the size of the application's view port changes.
+type ViewSize struct {
+	// Width is the width of the view.
+	// This value is expressed in device independent pixels.
+	Width int
+	// Height is the height of the view.
+	// This value is expressed in device independent pixels.
+	Height int
+}
+
+// TouchBegin occurs when a touch begins.
+type TouchBegin struct {
+	// ID identifies the touch that caused the touch event.
+	ID int
+	// X is the X position of the touch.
+	// This value is expressed in device independent pixels.
+	X float32
+	// Y is the Y position of the touch.
+	// This value is expressed in device independent pixels.
+	Y float32
+	// Pressure is the pressure applied to the touch.
+	// It varies between 0.0 for not pressed, and 1.0 for completely pressed.
+	Pressure float32
+	// Primary represents whether the touch event is the primary touch or not.
+	// If it is true, then it is a primary touch.
+	// Otherwise it is false.
+	Primary bool
+}
+
+// TouchMove occurs when a touch moved, or in other words, is dragged.
+type TouchMove struct {
+	// ID identifies the touch that caused the touch event.
+	ID int
+	// X is the X position of the touch.
+	// This value is expressed in device independent pixels.
+	X float32
+	// Y is the Y position of the touch.
+	// This value is expressed in device independent pixels.
+	Y float32
+	// DeltaX is the change in X since last touch event.
+	// This value is expressed in device independent pixels.
+	DeltaX float32
+	// Deltay is the change in Y since last touch event.
+	// This value is expressed in device independent pixels.
+	DeltaY float32
+	// Pressure of applied touch.
+	// It varies between 0.0 for not pressed, and 1.0 for completely pressed.
+	Pressure float32
+	// Primary represents whether the touch event is the primary touch or not.
+	// If it is true, then it is a primary touch.
+	// If it is false then it is not.
+	Primary bool
+}
+
+// TouchEnd occurs when a touch ends.
+// The data is the same as for a TouchMove event.
+type TouchEnd TouchMove
+
+// TouchCancel occurs when a touch is canceled.
+// This can happen in various situations, depending on the underlying platform,
+// for example when the aplication loses focus.
+type TouchCancel struct {
+	// ID identifies the touch that caused the touch event.
+	ID int
+}

+ 561 - 0
os/linux/input_linux.go

@@ -0,0 +1,561 @@
+package linux
+
+import "unsafe"
+
+
+// This file is a Go version of <linux/input.h>
+
+type input_event struct {
+	time    timeval
+	type_   uint16
+	code    uint16
+	value   int32
+}
+
+/*
+ * Protocol version.
+ */
+
+const EV_VERSION=0x010001
+
+/*
+ * IOCTLs (0x00 - 0x7f)
+ */
+
+type input_id struct {
+	bustype uint16
+	vendor uint16
+	product uint16
+    version uint16
+}
+
+/**
+ * struct input_absinfo - used by EVIOCGABS/EVIOCSABS ioctls
+ * @value: latest reported value for the axis.
+ * @minimum: specifies minimum value for the axis.
+ * @maximum: specifies maximum value for the axis.
+ * @fuzz: specifies fuzz value that is used to filter noise from
+ *	the event stream.
+ * @flat: values that are within this value will be discarded by
+ *	joydev interface and reported as 0 instead.
+ * @resolution: specifies resolution for the values reported for
+ *	the axis.
+ *
+ * Note that input core does not clamp reported values to the
+ * [minimum, maximum] limits, such task is left to userspace.
+ *
+ * Resolution for main axes (ABS_X, ABS_Y, ABS_Z) is reported in
+ * units per millimeter (units/mm), resolution for rotational axes
+ * (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian.
+ */
+type input_absinfo struct {
+	value int32;
+	minimum int32;
+	maximum int32;
+	fuzz int32;
+	flat int32;
+	resolution int32;
+}
+
+const INPUT_KEYMAP_BYINDEX	= (1 << 0)
+
+
+/**
+ * struct input_keymap_entry - used by EVIOCGKEYCODE/EVIOCSKEYCODE ioctls
+ * @scancode: scancode represented in machine-endian form.
+ * @len: length of the scancode that resides in @scancode buffer.
+ * @index: index in the keymap, may be used instead of scancode
+ * @flags: allows to specify how kernel should handle the request. For
+ *	example, setting INPUT_KEYMAP_BYINDEX flag indicates that kernel
+ *	should perform lookup in keymap by @index instead of @scancode
+ * @keycode: key code assigned to this scancode
+ *
+ * The structure is used to retrieve and modify keymap data. Users have
+ * option of performing lookup either by @scancode itself or by @index
+ * in keymap entry. EVIOCGKEYCODE will also return scancode or index
+ * (depending on which element was used to perform lookup).
+ */
+type input_keymap_entry struct {
+	flags uint8;
+	len uint8;
+	index uint16;
+	keycode uint32;
+	scancode [32]uint8;
+};
+
+type input_mask struct {
+	type_ uint32;
+	codes_size uint32;
+	codes_ptr uint32;
+};
+
+
+type uint32p = [2]uint32
+const sizeof_uint32p = unsafe.Sizeof(*((*uint32p)(nil)))
+const sizeof_int32 = unsafe.Sizeof(*((*int32)(nil)))
+const sizeof_uint32 = unsafe.Sizeof(*((*uint32)(nil)))
+const sizeof_input_id = unsafe.Sizeof(*((*input_id)(nil)))
+const sizeof_input_keymap_entry = unsafe.Sizeof(*((*input_keymap_entry)(nil)))
+const sizeof_input_absinfo = unsafe.Sizeof(*((*input_absinfo)(nil)))
+const sizeof_input_mask = unsafe.Sizeof(*((*input_mask)(nil)))
+const sizeof_ff_effect = unsafe.Sizeof(*((*ff_effect)(nil)))
+
+
+
+var EVIOCGVERSION =	IOR('E', 0x01, sizeof_int32)		/* get driver version */
+var EVIOCGID	  = IOR('E', 0x02, sizeof_input_id)	/* get device ID */
+var EVIOCGREP	  = IOR('E', 0x03, sizeof_uint32p)	/* get repeat settings */
+var EVIOCSREP	  = IOW('E', 0x03, sizeof_uint32p)	/* set repeat settings */
+
+var EVIOCGKEYCODE	= IOR('E', 0x04, sizeof_uint32)        /* get keycode */
+var EVIOCGKEYCODE_V2= IOR('E', 0x04, sizeof_input_keymap_entry)
+var EVIOCSKEYCODE	= IOW('E', 0x04, sizeof_uint32p)        /* set keycode */
+var EVIOCSKEYCODE_V2= IOW('E', 0x04, sizeof_input_keymap_entry)
+
+func EVIOCGNAME(len uintptr) uint32{	
+    return IOC(IOC_READ, 'E', 0x06, len)		/* get device name */
+}
+
+func EVIOCGPHYS(len uintptr) uint32	{
+    return IOC(IOC_READ, 'E', 0x07, len)		/* get physical location */
+}
+
+func EVIOCGUNIQ(len uintptr) uint32	{	
+    return IOC(IOC_READ, 'E', 0x08, len)		/* get unique identifier */
+}
+
+func EVIOCGPROP(len uintptr) uint32 { 
+    return IOC(IOC_READ, 'E', 0x09, len)		/* get device properties */
+}
+
+/**
+ * EVIOCGMTSLOTS(len uintptr) uint32 { - get MT slot values
+ * @len: size of the data buffer in bytes
+ *
+ * The ioctl buffer argument should be binary equivalent to
+ *
+ * type input_mt_request_layout struct {
+ *	__u32 code;
+ *	__s32 values[num_slots];
+ * };
+ *
+ * where num_slots is the (arbitrary) number of MT slots to extract.
+ *
+ * The ioctl size argument (len uintptr) uint32 { is the size of the buffer, which
+ * should satisfy len = (num_slots + 1) * sizeof(__s32).  If len is
+ * too small to fit all available slots, the first num_slots are
+ * returned.
+ *
+ * Before the call, code is set to the wanted ABS_MT event type. On
+ * return, values[] is filled with the slot values for the specified
+ * ABS_MT code.
+ *
+ * If the request code is not an ABS_MT value, -EINVAL is returned.
+ */
+func EVIOCGMTSLOTS(len uintptr) uint32 {
+    return IOC(IOC_READ, 'E', 0x0a, len)
+}
+
+func EVIOCGKEY(len uintptr) uint32 {		
+    return IOC(IOC_READ, 'E', 0x18, len)		/* get global key state */
+}
+
+func EVIOCGLED(len uintptr) uint32 {		
+    return IOC(IOC_READ, 'E', 0x19, len)		/* get all LEDs */
+}
+
+func EVIOCGSND(len uintptr) uint32 {		
+    return IOC(IOC_READ, 'E', 0x1a, len)		/* get all sounds status */
+}
+
+func EVIOCGSW(len uintptr) uint32 {		
+    return IOC(IOC_READ, 'E', 0x1b, len)		/* get all switch states */
+}
+
+func EVIOCGBIT(ev uint32, len uintptr) uint32 {	
+    return IOC(IOC_READ, 'E', 0x20 + (ev), len)	/* get event bits */
+}
+
+func EVIOCGABS(abs uint32) uint32 { 
+    return IOR('E', 0x40 + (abs), sizeof_input_absinfo)	/* get abs value/limits */
+}
+
+func EVIOCSABS(abs uint32) uint32 {	
+    return IOW('E', 0xc0 + (abs), sizeof_input_absinfo)	/* set abs value/limits */
+}
+
+var EVIOCSFF = IOW('E', 0x80, sizeof_ff_effect)	/* send a force effect to a force feedback device */
+var EVIOCRMFF = IOW('E', 0x81, sizeof_int32)			/* Erase a force effect */
+var EVIOCGEFFECTS = IOR('E', 0x84, sizeof_int32)		/* Report number of effects playable at the same time */
+
+var EVIOCGRAB = IOW('E', 0x90, sizeof_int32)			/* Grab/Release device */
+var EVIOCREVOKE = IOW('E', 0x91, sizeof_int32)			/* Revoke device access */
+
+/**
+ * EVIOCGMASK - Retrieve current event mask
+ *
+ * This ioctl allows user to retrieve the current event mask for specific
+ * event type. The argument must be of type "struct input_mask" and
+ * specifies the event type to query, the address of the receive buffer and
+ * the size of the receive buffer.
+ *
+ * The event mask is a per-client mask that specifies which events are
+ * forwarded to the client. Each event code is represented by a single bit
+ * in the event mask. If the bit is set, the event is passed to the client
+ * normally. Otherwise, the event is filtered and will never be queued on
+ * the client's receive buffer.
+ *
+ * Event masks do not affect global state of the input device. They only
+ * affect the file descriptor they are applied to.
+ *
+ * The default event mask for a client has all bits set, i.e. all events
+ * are forwarded to the client. If the kernel is queried for an unknown
+ * event type or if the receive buffer is larger than the number of
+ * event codes known to the kernel, the kernel returns all zeroes for those
+ * codes.
+ *
+ * At maximum, codes_size bytes are copied.
+ *
+ * This ioctl may fail with ENODEV in case the file is revoked, EFAULT
+ * if the receive-buffer points to invalid memory, or EINVAL if the kernel
+ * does not implement the ioctl.
+ */
+var EVIOCGMASK = IOR('E', 0x92, sizeof_input_mask)	/* Get event-masks */
+
+/**
+ * EVIOCSMASK - Set event mask
+ *
+ * This ioctl is the counterpart to EVIOCGMASK. Instead of receiving the
+ * current event mask, this changes the client's event mask for a specific
+ * type.  See EVIOCGMASK for a description of event-masks and the
+ * argument-type.
+ *
+ * This ioctl provides full forward compatibility. If the passed event type
+ * is unknown to the kernel, or if the number of event codes specified in
+ * the mask is bigger than what is known to the kernel, the ioctl is still
+ * accepted and applied. However, any unknown codes are left untouched and
+ * stay cleared. That means, the kernel always filters unknown codes
+ * regardless of what the client requests.  If the new mask doesn't cover
+ * all known event-codes, all remaining codes are automatically cleared and
+ * thus filtered.
+ *
+ * This ioctl may fail with ENODEV in case the file is revoked. EFAULT is
+ * returned if the receive-buffer points to invalid memory. EINVAL is returned
+ * if the kernel does not implement the ioctl.
+ */
+var EVIOCSMASK = IOW('E', 0x93, sizeof_input_mask)	/* Set event-masks */
+
+var EVIOCSCLOCKID = IOW('E', 0xa0, sizeof_int32) /* Set clockid to be used for timestamps */
+
+/*
+ * IDs.
+ */
+
+const ID_BUS = 0
+const ID_VENDOR = 1
+const ID_PRODUCT = 2
+const ID_VERSION = 3
+
+const BUS_PCI = 0x01
+const BUSISAPNP = 0x02
+const BUS_USB = 0x03
+const BUS_HIL = 0x04
+const BUS_BLUETOOTH = 0x05
+const BUS_VIRTUAL = 0x06
+
+const BUSISA = 0x10
+const BUSI8042 = 0x11
+const BUS_XTKBD = 0x12
+const BUS_RS232 = 0x13
+const BUS_GAMEPORT = 0x14
+const BUS_PARPORT = 0x15
+const BUS_AMIGA = 0x16
+const BUS_ADB = 0x17
+const BUSI2C = 0x18
+const BUS_HOST = 0x19
+const BUS_GSC = 0x1A
+const BUS_ATARI = 0x1B
+const BUS_SPI = 0x1C
+
+/*
+ * MT_TOOL types
+ */
+const MT_TOOL_FINGER = 0
+const MT_TOOL_PEN = 1
+const MT_TOOL_PALM = 2
+const MT_TOOL_MAX = 2
+
+/*
+ * Values describing the status of a force-feedback effect
+ */
+const FF_STATUS_STOPPED = 0x00
+const FF_STATUS_PLAYING = 0x01
+const FF_STATUS_MAX = 0x01
+
+/*
+ * Structures used in ioctls to upload effects to a device
+ * They are pieces of a bigger structure (called ff_effect)
+ */
+
+/*
+ * All duration values are expressed in ms. Values above 32767 ms (0x7fff)
+ * should not be used and have unspecified results.
+ */
+
+/**
+ * struct ff_replay - defines scheduling of the force-feedback effect
+ * @length: duration of the effect
+ * @delay: delay before effect should start playing
+ */
+type ff_replay struct {
+	length uint16
+	delay uint16
+};
+
+/**
+ * struct ff_trigger - defines what triggers the force-feedback effect
+ * @button: number of the button triggering the effect
+ * @interval: controls how soon the effect can be re-triggered
+ */
+type ff_trigger struct {
+	button uint16
+	interval uint16
+};
+
+/**
+ * struct ff_envelope - generic force-feedback effect envelope
+ * @attack_length: duration of the attack (ms)
+ * @attack_level: level at the beginning of the attack
+ * @fade_length: duration of fade (ms)
+ * @fade_level: level at the end of fade
+ *
+ * The @attack_level and @fade_level are absolute values; when applying
+ * envelope force-feedback core will convert to positive/negative
+ * value based on polarity of the default level of the effect.
+ * Valid range for the attack and fade levels is 0x0000 - 0x7fff
+ */
+type ff_envelope struct {
+	attack_length uint16
+	attack_level uint16
+	fade_length uint16
+	fade_level uint16
+};
+
+/**
+ * struct ff_constant_effect - defines parameters of a constant force-feedback effect
+ * @level: strength of the effect; may be negative
+ * @envelope: envelope data
+ */
+type ff_constant_effect struct {
+	level int16
+	envelope ff_envelope
+};
+
+/**
+ * struct ff_ramp_effect - defines parameters of a ramp force-feedback effect
+ * @start_level: beginning strength of the effect; may be negative
+ * @end_level: final strength of the effect; may be negative
+ * @envelope: envelope data
+ */
+type ff_ramp_effect struct {
+	start_level int16
+	end_level int16
+	envelope ff_envelope
+};
+
+/**
+ * struct ff_condition_effect - defines a spring or friction force-feedback effect
+ * @right_saturation: maximum level when joystick moved all way to the right
+ * @left_saturation: same for the left side
+ * @right_coeff: controls how fast the force grows when the joystick moves
+ *	to the right
+ * @left_coeff: same for the left side
+ * @deadband: size of the dead zone, where no force is produced
+ * @center: position of the dead zone
+ */
+type ff_condition_effect struct {
+	right_saturation uint16
+	left_saturation uint16
+
+	right_coeff int16
+	left_coeff int16
+
+	deadband uint16
+	center int16
+};
+
+/**
+ * struct ff_periodic_effect - defines parameters of a periodic force-feedback effect
+ * @waveform: kind of the effect (wave)
+ * @period: period of the wave (ms)
+ * @magnitude: peak value
+ * @offset: mean value of the wave (roughly)
+ * @phase: 'horizontal' shift
+ * @envelope: envelope data
+ * @custom_len: number of samples (FF_CUSTOM only)
+ * @custom_data: buffer of samples (FF_CUSTOM only)
+ *
+ * Known waveforms - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP,
+ * FF_SAW_DOWN, FF_CUSTOM. The exact syntax FF_CUSTOM is undefined
+ * for the time being as no driver supports it yet.
+ *
+ * Note: the data pointed by custom_data is copied by the driver.
+ * You can therefore dispose of the memory after the upload/update.
+ */
+type ff_periodic_effect struct {
+	waveform uint16
+	period uint16
+	magnitude int16
+	offset int16
+	phase uint16
+
+	envelope ff_envelope
+
+	custom_len uint32
+	custom_data *int16;
+};
+
+/**
+ * struct ff_rumble_effect - defines parameters of a periodic force-feedback effect
+ * @strong_magnitude: magnitude of the heavy motor
+ * @weak_magnitude: magnitude of the light one
+ *
+ * Some rumble pads have two motors of different weight. Strong_magnitude
+ * represents the magnitude of the vibration generated by the heavy one.
+ */
+type ff_rumble_effect struct {
+	strong_magnitude uint16
+	weak_magnitude uint16
+};
+
+const ff_effect_union_size = unsafe.Sizeof(*((*ff_periodic_effect)(nil)))
+
+/**
+ * struct ff_effect - defines force feedback effect
+ * @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING,
+ *	FF_FRICTION, FF_DAMPER, FF_RUMBLE, FFINERTIA, or FF_CUSTOM)
+ * @id: an unique id assigned to an effect
+ * @direction: direction of the effect
+ * @trigger: trigger conditions (struct ff_trigger)
+ * @replay: scheduling of the effect (struct ff_replay)
+ * @u: effect-specific structure (one of ff_constant_effect, ff_ramp_effect,
+ *	ff_periodic_effect, ff_condition_effect, ff_rumble_effect) further
+ *	defining effect parameters
+ *
+ * This structure is sent through ioctl from the application to the driver.
+ * To create a new effect application should set its @id to -1; the kernel
+ * will return assigned @id which can later be used to update or delete
+ * this effect.
+ *
+ * Direction of the effect is encoded as follows:
+ *	0 deg -> 0x0000 (down)
+ *	90 deg -> 0x4000 (left)
+ *	180 deg -> 0x8000 (up)
+ *	270 deg -> 0xC000 (right)
+ */
+type ff_effect struct {
+	type_ uint16
+	id int16
+	direction uint16
+	trigger ff_trigger
+	replay ff_replay
+    // This was a union in C, somulate with a byte buffer with size of largest element
+    u [ff_effect_union_size]byte
+};
+
+type ff_effect_u_constant struct {
+	type_ uint16
+	id int16
+	direction uint16
+	trigger ff_trigger
+	replay ff_replay
+    constant ff_constant_effect
+};
+
+
+type ff_effect_u_ramp struct {
+	type_ uint16
+	id int16
+	direction uint16
+	trigger ff_trigger
+	replay ff_replay
+	ramp ff_ramp_effect
+};
+
+
+type ff_effect_u_periodic struct {
+	type_ uint16
+	id int16
+	direction uint16
+	trigger ff_trigger
+	replay ff_replay
+    periodic ff_periodic_effect
+};
+
+type ff_effect_u_condition struct {
+	type_ uint16
+	id int16
+	direction uint16
+	trigger ff_trigger
+	replay ff_replay
+    condition [2]ff_condition_effect; /* One for each axis */
+};
+
+type ff_effect_u_rumble struct {
+	type_ uint16
+	id int16
+	direction uint16
+	trigger ff_trigger
+	replay ff_replay
+    rumble ff_rumble_effect
+};
+
+
+/*
+ * Force feedback effect types
+ */
+
+const FF_RUMBLE = 0x50
+const FF_PERIODIC = 0x51
+const FF_CONSTANT = 0x52
+const FF_SPRING = 0x53
+const FF_FRICTION = 0x54
+const FF_DAMPER = 0x55
+const FFINERTIA = 0x56
+const FF_RAMP = 0x57
+
+const FF_EFFECT_MIN = FF_RUMBLE
+const FF_EFFECT_MAX = FF_RAMP
+
+/*
+ * Force feedback periodic effect types
+ */
+
+const FF_SQUARE = 0x58
+const FF_TRIANGLE = 0x59
+const FF_SINE = 0x5a
+const FF_SAW_UP = 0x5b
+const FF_SAW_DOWN = 0x5c
+const FF_CUSTOM = 0x5d
+
+const FF_WAVEFORM_MIN = FF_SQUARE
+const FF_WAVEFORM_MAX = FF_CUSTOM
+
+/*
+ * Set ff device properties
+ */
+
+const FF_GAIN = 0x60
+const FF_AUTOCENTER = 0x61
+
+/*
+ * ff->playback(effect_id = FF_GAIN) is the first effect_id to
+ * cause a collision with another ff method, in this case ff->set_gain().
+ * Therefore the greatest safe value for effect_id is FF_GAIN - 1,
+ * and thus the total number of effects should never exceed FF_GAIN.
+ */
+const FF_MAX_EFFECTS = FF_GAIN
+
+const FF_MAX = 0x7f
+const FF_CNT = (FF_MAX+1)
+

+ 106 - 0
os/linux/ioctl_linux.go

@@ -0,0 +1,106 @@
+package linux
+
+// ioctl for linux 
+
+
+/* ioctl command encoding: 32 bits total, command in lower 16 bits,
+ * size of the parameter structure in the lower 14 bits of the
+ * upper 16 bits.
+ * Encoding the size of the parameter structure in the ioctl request
+ * is useful for catching programs compiled with old versions
+ * and to avoid overwriting user space outside the user buffer area.
+ * The highest 2 bits are reserved for indicating the ``access mode''.
+ * NOTE: This limits the max parameter size to 16kB -1 !
+ */
+
+/*
+ * The following is for compatibility across the various Linux
+ * platforms.  The generic ioctl numbering scheme doesn't really enforce
+ * a type_ field.  De facto, however, the top 8 bits of the lower 16
+ * bits are indeed used as a type_ field, so we might just as well make
+ * this explicit here.  Please be sure to use the decoding macros
+ * below from now on.
+ */
+const IOC_NRBITS = 8
+// XXX might be 13 on some platforms
+const IOC_TYPEBITS	= 14
+// XXX might be 3 on some platforms
+const IOC_SIZEBITS	= 2
+// XXX might be 3 on some platforms
+const IOC_DIRBITS	= 2
+
+
+const  IOC_NRMASK	= ((1 << IOC_NRBITS)-1)
+const IOC_TYPEMASK	= ((1 << IOC_TYPEBITS)-1)
+const IOC_SIZEMASK	= ((1 << IOC_SIZEBITS)-1)
+const IOC_DIRMASK	= ((1 << IOC_DIRBITS)-1)
+
+const IOC_NRSHIFT	    = 0
+const IOC_TYPESHIFT	= (IOC_NRSHIFT+IOC_NRBITS)
+const IOC_SIZESHIFT	= (IOC_TYPESHIFT+IOC_TYPEBITS)
+const IOC_DIRSHIFT	    = (IOC_SIZESHIFT+IOC_SIZEBITS)
+
+/*
+ * Direction bits, which any architecture can choose to override
+ * before including this file.
+ */
+
+const IOC_NONE	= 0
+
+//XXX is 4 on some platforms
+const IOC_WRITE = 1
+
+const  IOC_READ = 2
+
+func IOC(dir uint32, type_ rune, nr uint32, size uintptr) uint32 {
+	return (((dir)  << IOC_DIRSHIFT) |
+	 ((uint32(type_)) << IOC_TYPESHIFT) |
+	 (uint32(nr)   << IOC_NRSHIFT) |
+	 (uint32(size) << IOC_SIZESHIFT))
+}
+
+/* used to create numbers */
+func IO(type_ rune,nr uint32) uint32 { 
+    return IOC(IOC_NONE,(type_),(nr),0)
+}
+
+func IOR(type_ rune, nr uint32, size uintptr)	uint32 { 
+     return IOC(IOC_READ,type_,nr, size)
+}
+
+func IOW(type_ rune ,nr uint32,size uintptr) uint32	{ 
+    return IOC(IOC_WRITE,(type_),(nr),((size)))
+}
+
+func IOWR(type_ rune,nr uint32,size uintptr) uint32 { 
+    return IOC(IOC_READ|IOC_WRITE,(type_),(nr),((size)))
+}
+
+/* used to decode ioctl numbers.. */
+func IOC_DIR(nr uint32) uint32 { 
+    return (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK)
+}
+
+
+func IOC_TYPE(nr uint32) uint32 {		
+    return (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK)
+}
+
+
+func IOC_NR(nr uint32) uint32 { 
+    return (((nr) >> IOC_NRSHIFT) & IOC_NRMASK)
+}
+
+func IOC_SIZE(nr uint32) uint32 { 		
+    return (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK)
+}
+
+/* ...and for the drivers/sound files... */
+
+const IOC_IN =		(IOC_WRITE << IOC_DIRSHIFT)
+const IOC_OUT =		(IOC_READ << IOC_DIRSHIFT)
+const IOCINOUT =	((IOC_WRITE|IOC_READ) << IOC_DIRSHIFT)
+const IOCSIZE_MASK =	(IOC_SIZEMASK << IOC_SIZESHIFT)
+const IOCSIZE_SHIFT =	(IOC_SIZESHIFT)
+
+

+ 16 - 0
os/linux/linux32.go

@@ -0,0 +1,16 @@
+
+
+// +build 386 arm mips mipsle s390x
+// +build linux
+
+
+
+package linux
+
+
+// platform specific for 64 bits linux platforms
+
+
+type long = int32
+
+

+ 12 - 0
os/linux/linux64.go

@@ -0,0 +1,12 @@
+
+
+// +build amd64 arm64 ppc64 ppc64le mips64 mips64le
+// +build linux 
+
+package linux
+
+// platform specific for 64 bits linux platforms
+
+type long = int64
+
+

+ 16 - 0
os/linux/types.go

@@ -0,0 +1,16 @@
+package linux 
+
+// suseconds_t varies by platform, 32 on 32 bits, 64 on 64 bits
+type suseconds_t = long
+// time_t is aways 64 bits signed, even on 32 bits platforms.
+type time_t = int64
+
+// A time value that is accurate to the nearest
+// microsecond but also has a range of years.
+type timeval struct {
+    tv_sec time_t	// Seconds.
+    tv_usec suseconds_t  // Microseconds.
+}
+
+
+