How to write a plugin for your driver
You may know there is not a standard driver subsystem for sensors, such as HID or input system. Jonathan Cameron [jic23@cam.ac.uk] is working to check his iio (industry I/O), a driver system for sensor, into the upstream. I don't know when the kernel will accept it or when the sensor driver writers will follow it, so our framework has to work with various drivers for a long time. This is why we need a driver plugin system.
The current plugin system code is only an initial version or, in other words, a prototype. However,
the basic skeleton is ready. You may extend it for your purposes. Patches are always welcome.
Writing a module is very simple in sensor framework. Only two functions are required.
gint sf__init (SFModule* m);
void sf__exit (SFModule* m);#SFModule struct defines fields required by sensor daemon, generally you should not directly
touch it. Anyway, some fields may contain useful info for your module, please treat them as read only.
see below:
/**
* SFModule:
* @name: name of module. It's group name in module.conf.
* For example, in sample module.conf there is a [module-als-simulator]
* then module-als-simulator is treated as module name.
* @type: type of module. see #ModuleType
* @userdata: location for module save its private data. You can directly
* evaluate it.
* @gmodule: #GModule struct. Don't touch it
* @core: #SFCore. Don't touch it
* @keyfile: #GKeyFile contains parameters of module. Pls use key file function
* set of glib to get your parameter and don't free it.
* @init: pointer to sf_init() of your module. Don't touch
* @exit: pointer to sf_exit() of your module. Don't touch
*/
typedef struct _SFModule {
gchar* name;
ModuleType type;
gpointer userdata;
GModule* gmodule;
SFCore* core;
guint index;
GKeyFile* keyfile;
SFModuleInit init;
SFModuleExit exit;
} SFModule;All works of initialization should be finished in sf__init() and returned to 0 to indicate a success or -1 to indicate a fail/ sf__init() is responsible for freeing resource allocated by itself during initial period in its error handling. sf__exit() is called when module unloads, all resources allocated by module should be freed here.
The current module is called *driver module*. It should represent a sensor or sensor driver. Functional module will be introduced later, if there is a real need. You may create a struct of you sensor, for example:
struct my_accelerometer {
SFSensorDev parent;
...........
};#SFSensorDev is a parent object for all sensor structs, it must be always put as first element.
sf_sensordev_new () is the function that allocated memory and initialize #SFSensorDev for your struct, see below:
/**
* sf_sensordev_new:
* @c: A #SFCore object.
* @type: #SFSensorType indicates type of sensor
* @ops: A set of functions that provided by module for
* management of framework. see #DevOps
* @size: size of #SFSensorDev to create
*
* Create a new #SFSensorDev struct. The size is specified to allow creating
* structure derived from #SFSensorDev that contain additional data The size
* passed in must be at least sizeof (SFSensorDev);
*
* Returns: A newly-created #SFSensorDev
*/
SFSensorDev* sf_sensordev_new (SFCore* c, SFSensorType type, DevOps* ops, guint size);for @c, you can find #SFCore from #SFModule->core. #SFType defines as below:
typedef enum {s
TYPE_INVAILD = -1,
TYPE_MIN,
TYPE_ACCEL = 1,
TYPE_GRYO = 1 << 1,
TYPE_THERMAL = 1 << 2,
TYPE_COMAPSS = 1 << 3,
TYPE_ALS = 1 << 4,
TYPE_MAX,
} SFSensorType; #DevOps only has two functions now:
struct _DevOps {
gint (*dev_set_active) (SFSensorDev* se, DevActiveLevel level);
void (*dev_msg_process) (SFSensorDev* se, gint code, gpointer data, guint datalen, gpointer ret_val);
};dev_set_active() is used to enable/disable sensor. The enable/disable action is module-specific, so it's agnostic. Pls return 0 to indicate a success or -1 when an error happens, however, this function should not fail. #DevActiveLevel defines as followed:
/**
* DevActiveLevel:
* @DEV_STOP: Stop to inject data/event
* @DEV_ACTIVE: Begin to inject data/event
*/
typedef enum {
DEV_STOP,
DEV_ACTIVE,
} DevActiveLevel;Note that dev_set_active() is a mandatory requirement, so please always provide it. You may implement it as a void function.
dev_msg_process() is a part of module communication mechanism. Framework implements a communication channel based on asynchronous queues of glib.
/*
* dev_msg_process:
* @se: A #SFSensorDev object
* @code: option code indicates what action should be executed.
* @data: data passed in by sender
* @datalen: length of data
* @ret_val: a location to store return value. Note that memory
* should be allocated by sender, so memcpy() returns to @ret_val
* is ok.
*
* Handle message from framework or other modules.
*
* <note><para>
* Sender may call sf_asyncmsg_send_sync() to send a message and block
* until a signal of completion is received. This usually happens when the
* sender waits for a return value. So don't sleep in this function
* otherwise the whole framework may be blocked.
* </para></note>
*/
void (*dev_msg_process) (SFSensorDev* se, gint code, gpointer data, guint datalen, gpointer ret_val);Here option code is defined in sensor.h as:
typedef enum {
MSG_EXIT_THREAD,
MSG_STREAM_REGISTER,
MSG_STREAM_UNREGISTERED,
/* ALS message */
MSG_ALS_SET_RANGE,
MSG_ALS_GET_RANGE,
} DevMsgCode;To add your specific code, you have to extend this enumeration. Note that there are some messages for framework that module should not care about. Because the message queue will become blocked when it isn’t receiving anything, it must be run in a individual thread. To simplify work, sf_sensordev_run_msg_process() will be run on on your behalf to create a thread.
/**
* sf_sensordev_run_msg_process:
* @se: A #SFSensorDev object
*
* Create a thread to handle message
*/
void sf_sensordev_run_msg_process (SFSensorDev* se);This function should be called in sf__init() since your dev_msg_process () may be NULL. As mentioned before, there are some messages handled by the framework itself, so whatever you should call sf_sensordev_run_msg_process() in your sf__init().
To stop the message process, call sf_sensordev_stop_msg_process().
/**
* sf_sensordev_stop_msg_process:
* @se: A #SFSensorDev object
*
* Stop the message process and reclaim the thread.
*/
void sf_sensordev_stop_msg_process (SFSensorDev* se);You may create the thread by yourself if there is some stuff in your module that needs to be handled in a single thread. In this case, you should directly invoke sf_sensordev_process_msg() to deal with the message.
/**
* sf_sensordev_process_msg:
* @se: A #SFSensorDev object
* @timeout: period of time out. A -1 indicates to block until the message
* become available.
*
* Returns: 0 indicates a MSG_EXIT_THREAD is gotten, that means you should
* end your thread. 1 means to go on handling the message.
*
*/
gint sf_sensordev_process_msg (SFSensorDev* se, glong timeout);Please refer to module-accel-simulator.c to see how to create a thread by yourself to process messages.
To send a message to the module, call sf_asyncmsg_send() or sf_asyncmsg_send_sync(). See definitions:
/**
* sf_asyncmsg_send:
* @q: A #GAsyncQueue object
* @code: A option code
* @data: data pass to receiver
* @len: length of data
*
* Send a message to the owner of @q
*
* <note><para>
* This function send message in asynchronous mode.
* sf_asyncmsg_send_sync() is the synchronous version.
* </para></note>
*/
void sf_asyncmsg_send (GAsyncQueue* q, gint code, gpointer data, guint len);
/**
* sf_asyncmsg_send_sync:
* @q: A #GAsyncQueue object
* @code: A option code
* @data: data pass to receiver
* @len: length of data
* @ret_val: Location to store the return value. The sender is responsible for
* allocating and freeing memory.
*
* Send a message in synchronous mode and bring the return value back to
* the sender if there is any.
*/
void sf_asyncmsg_send_sync (GAsyncQueue* q, gint code, gpointer data,
guint len, gpointer ret_val);For #SFSensorDev, the #GAsyncQueue is #SFSensorDev->inq.
The last thing, framework uses a auto-produced header file to resolve a name conflict from sf__init()/sf__exit(). Add your header name in src/Makefile.am as below:
SYMDEF_FILES = \
modules/module-accel-simulator-symdef.h>-\
modules/module-als-simulator-symdef.hOk, by now you should have an overview of how to write a driver module. Some details are not
shown here, for example, the helper of polling data. As a Chinese speaker, writing in English is always
a big challenge. Anyway, referring to sample code is the fastest way to learn details. Please see
module-accel-simulator.c and module-als-simulator.c. And patches are always welcome.
- Printer-friendly version
- Login or register to post comments
Comments (1 total)
Nice job on this
I appreciate this documentation. An a native English speaker who has tried to write in Chinese, I can say that your English is superb!
I am just now getting started on the compass module. Do you have any more hints?
Clayne