deviceModule
Low-level Lua interface for creating Linux character device drivers.
This module allows Lua scripts to implement character device drivers by providing callback functions for standard file operations likeopen, read, write, and release.
A file operation runs on the task performing it, in process context, so its
callback may sleep. It runs under the lock of the runtime that made the device,
so one the runtime’s own code performs, a
callback or a thread body opening the node it made, fails with EDEADLK:
it would wait on the lock its task holds. An open, read or write
callback fails its operation with an errno by returning it negated, as
-errno.EBUSY does with linux.errno. A callback that raises, or that
returns a length or an offset that is not an integer, or an errno that is not
one, the kernel’s own from ERESTARTSYS on included, invalid errno in the
log, fails its operation with ECANCELED, and the error goes to the kernel
log.
Class device
| device:stop () | Stops a character device driver and removes it from the system. |
device
| new (driver) | Creates and installs a new character device driver in the system. |
Class device in detail
device.new(). It encapsulates
the necessary kernel structures (struct cdev, dev_t) to manage a
character device, linking file operations to Lua callback functions.
- device:stop ()
-
Stops a character device driver and removes it from the system.
This method is called on a device object returned by
device.new(): the device file (/dev/<name>) and its region go with it. Without stop, the device lives until its runtime stops, since device.new keeps the object for the runtime. A file still open on the device gets ENXIO from read and write until it is closed. A to-be-closed variable holding the device stops it the same way.Returns
-
nil
Does not return any value to Lua.
Raises
if the argument is not a device.See also
Usage
-- Assuming 'dev' is a device object: dev:stop()
device in detail
- new (driver)
-
Creates and installs a new character device driver in the system.
This function binds a Lua table (the
drivertable) to a new character device file (/dev/<name>), allowing Lua functions to handle file operations on that device.Parameters
- driver
table
A table defining the device driver’s properties and callbacks. It must contain the field:
-
name(string): The name of the device. This name will be used to create the device file/dev/<name>.
It might optionally contain the following fields (callback functions), each of which receives, after its own arguments,
file: a table private to one open of the device, the same in every callback that open reaches from itsopento itsrelease, where the driver keeps what belongs to that open.-
open(function): Callback for theopen(2)system call. Signature:function(driver_table, file) -> [errno]. Returning nothing or zero opens the file, and returning a negative errno,-errno.EBUSYsay, fails the open with it. -
read(function): Callback for theread(2)system call. Signature:function(driver_table, length, offset, file) -> string [, updated_offset]. Receives the driver table, the requested read length (integer), and the current file offset (integer). Should return the data as a string and optionally the updated file offset (integer), or a negative errno,-errno.EAGAINsay, which fails the read with it. Ifupdated_offsetis not returned, the offset is advanced by the length of the returned string (or the requested length if the string is longer). -
write(function): Callback for thewrite(2)system call. Signature:function(driver_table, buffer_string, offset, file) -> [written_length] [, updated_offset]. Receives the driver table, the data to write as a string, and the current file offset (integer). May return the number of bytes successfully written (integer), or a negative errno,-errno.ENOSPCsay, which fails the write with it, and optionally the updated file offset (integer). Ifwritten_lengthis not returned, it’s assumed all provided data was written. Ifupdated_offsetis not returned, the offset is advanced by thewritten_length. -
release(function): runs when the last reference to an open file is closed, the final close(2). Signature:function(driver_table, file). Expected to return nothing.
A read returns end of file when its callback returns an empty string,
nilor zero.It might also contain the field:
-
mode(integer): Optional permission bits of the device file, withinS_IALLUGO: the file type is the kernel’s, a character device. Use constants from linux.stat (e.g.,stat.IRUGO).
-
Returns
-
device
the device, which device.new keeps for its runtime: dropping it
stops nothing, and the device stays until stop or the end of the runtime.
Raises
Error if the device cannot be allocated or registered in the kernel, if thenamefield is missing or not a string, or if called from a percpu runtime;bad field 'mode' (number expected, got <type>)ifmodeis present and not a number;bad field '<field>' (function expected, got <type>)ifopen,read,writeorreleaseis present and not a function;bad field 'mode' (out of bounds)if it is negative or pastS_IALLUGO, as a mode that carries a file type is;'device': process-context class in interrupt-context runtimein a softirq or hardirq runtime (run it in process context, the default oflunatik run);not allowed while the runtime closesfrom a finalizer that runs at its close.Usage
local device = require("device") local stat = require("linux.stat") local function read(drv, len, off) local data = "Hello from " .. drv.name .. "!\n" return data:sub(off + 1, off + len) end local my_driver = { name = "my_lua_device", mode = stat.IRUGO, -- Read-only for all read = read, } local dev_obj = device.new(my_driver) -- To remove it: dev_obj:stop(), or stop the runtime.
- driver
table