Deepen and enrich your understanding of character devices with a more concrete example
Review the kdlpdev
example from last week
open(2)
, close(2)
, and read(2)
implementationsIntroduce write(2)
, ioctl(2)
, and llseek(2)
Introduce the jiffies
counter and HZ
constant
Discuss the device class system and struct device
Overview of MIDI and our simplification
Work through the design and implementation of kkey
Listen to the sound of the kernel
kdlpdev.c
Remember what we needed to make cat
work?
We have to manually create the device file with mknod(7)
Annoying! Today we introduce an alternative
Guesses on what this might be?
write(2)
: reverse the polarity of read(2)
read(2)
and write(2)
considerationsMake sure special cases of count
value handled correctly
Properly advance the file position value
Take care to return sane error values if appropriate
ioctl(2)
: general purpose interface with a character device
Commonly used for device-specific operations
Originally used to control the terminal on earlier Unix systems
tty := teletype terminal
Historically controlled terminals
Kernel had a single lock long ago
IOCTL calls took the lock
Long since irrelevant
Kernel preferred way to define IOCTL commands with several macros
Can specify type of transferred data for validation
#include <linux/ioctl.h>
#define MYDEVICE_IOC_MAGIC 'k'
#define MYDEVICE_IOCRESET _IO(MYDEVICE_IOC_MAGIC, 0)
#define MYDEVICE_IOCSQUALITY _IOW(MYDEVICE_IOC_MAGIC, 1, int)
#define MYDEVICE_IOCGQUALITY _IOR(MYDEVICE_IOC_MAGIC, 2, int)
lseek(2)
: change the file position pointer
Three common modes:
Offset from current value
Negative offset from end
Set value directly
All fairly boilerplate
Any guesses why we find llseek
in file_operations instead of lseek
?
Hint: llseek
is short for "long long seek"
32-bit and 64-bit compatibility
The jiffies
counts CPU timer interrupts since boot
Allows calculating elapsed time between in-kernel events
HZ
kernel config value contains timer frequency
Units are in interrupts per second
jiffies
unit is timer interrupts (since boot)
HZ unit is interrupts/seconds
Therefore: seconds since boot = jiffies / HZ
Linux provides a device class representation
The kernel provides a specific device instance representation
Can create these by hand
Can instantiate using a device class
Represents device instance directly
Device instance identified by major/minor pair
Device class identified by name string
Both provide a sysfs interface
A character device can provide an interface for a device instance
The least abstract demo so far this semester
What kind of audio format would be suitable?
Encodes musical information in events
Series of event messages sent to MIDI device
Event messages relating to music, e.g. press, release
Meta messages e.g. time signature, tempo, track names, lyrics
Deltas placed in between messages
Deltas are variable-width, with 7 bits of information
Leading bit 1 until final byte to indicate end
One global MIDI header
Some some number of track headers
A series of meta or event messages
Write system calls to one of the /dev/kkeyXXX files
Input value is either:
0 - key release
1 - key press
Use read system call on any /dev/kkeyXXX
Output data is valid MIDI file
Listen to the music
kkey
detailsSimplify format with single track and channel
An IOCTL cmd emptires the internal buffer
But how do we calculate the delta values?
If the timer interrupt is the "heartbeat" of the kernel, then kkey
reads it's pulse
We cache the MIDI file when it's generated
Spot any flaws?
We will now tour kkey.c
All course demos and more are now published to this repo
Any suggestions or fixes? Contributions welcome!
makefile usage:
make
make reset
make play
make clean
middle_c.sh
Note table at bottom of https://faydoc.tripod.com/formats/mid.htm
c_major.sh
A classic musical "Hello world" tune
twinkle_twinkle.c
A modified C418 song used in Minecraft soundtrack IIRC
microvenus.c
Any guesses?
Any quesses?
kkey
produces slightly different outputThe six entries of struct file_operations
implemented by kkey
are the complete set required for the remaining assignments in this course
Using struct device
and struct class
, one can more easily group together and manage similar devices
Using jiffies
and HZ
, we can calculate the passage of real wall clock time relative to system boot
The interfaces provides to kernel modules allow for very flexible behavior and creative features
Coming up soon: concurrency and a race-free kkey
msg = (silence)
whoami = None
singularity v0.6-56-g8e52bc8 https://github.com/underground-software/singularity