The ‘ioctl’ driver-function On implementing ‘show’ and ‘hide’ for the SiS 315 hardware cursor ‘struct file_operations’ • For a Linux device-driver’s ‘init_module()’ function, there are two main actions: – Initializing the driver’s global data-structures (this includes verifying the device’s presence) – Registering the driver’s service-functions with the kernel (i.e., the ‘file_operations’ structure) • The driver’s ‘cleanup_module()’ function has the duty to ‘unregister’ those services Driver services • For character-mode device-drivers (such as our ‘dram.c’, ‘mbr.c’, and ‘vramm.c’), we have implemented some (or all) of the following service-functions (i.e., ‘methods’) – – – – read() llseek() write() mmap() The ‘file’ paradigm • The UNIX approach to device-control is to create objects that represent i/o-devices, but which behave like ‘files’ do, insofar as the application programmer is concerned • So ‘read()’, ‘llseek()’, ‘write()’ and ‘mmap() use the same function-call syntax – and in most respects the same semantics – for both ‘files’ and ‘devices’ An imperfect paradigm • But often there are a few ways in which the file-object paradigm doesn’t quite fit with important features of an i/o device • In these cases, device-drivers can provide a ‘workaround’ that allows applications to perform device-actions that deviate from customary ‘read/write/seek’ file-like actions • This ‘workaround’ mechanism is ‘ioctl()’ The graphics display • Our PC’s graphics display device offers an easy example of desirable behavior that is outside the traditional ‘file’ paradigm • In order to display graphical images that are full-screen renderings of artistic work, we want to avoid seeing a mouse-cursor (it’s an ugly and disruptive and distraction) • How can a program ‘turn off’ that cursor? The GPU ‘resources’ • The SiS 315 graphics processing units in our workstations are each equipped with 32-megabytes of video display memory (designated as PCI resource 0) • These graphics adapters also implement a set of memory-mapped registers known as the 2D graphics engine (and designated as PCI resource 1) ‘pci_resource_start()’ • Device-drivers can use this Linux kernel function to discover the physical address where resource 0, or resource 1, resides struct pci_dev *devp = NULL: devp = pci_find_device( VEN, DEV, devp ); vram = pci_resource_start( devp, 0 ); mmio = pci_resource_start( devp, 1 ); SiS 315 information • Programming manual for the SiS 315 GPU is not usually made available to the public • But some information can be derived from reading Linux device-driver source-code • Examples are: – The ‘/usr/src/linux/drivers/video/sis’ directory – Also download the ‘svgalib-1.9.17’ package Graphics Cursor 31 30 0x8500 0 cursor-image source-offset cursor visibility control bit: 0=hide, 1=show cursor starting command bit: 0=no, 1=yes 0x850C cursor-image horizontal coordinate 0x8510 cursor-image vertical coordinate Algorithm to hide cursor • Map physical page containing the registers to a virtual address (with ‘ioremap()’) • Read current values of these registers • Clear bit #30 (to make cursor invisible) • Set bit #31 (to initiate a new command) • Write these adjusted register values • Undo the mapping (with ‘iounmap()’) Algorithm to show cursor • Map physical page containing the registers to a virtual address (with ‘ioremap()’) • Read current values of these registers • Set bit #30 (to make cursor visible) • Set bit #31 (to initiate a new command) • Write these adjusted register values • Undo the mapping (with ‘iounmap()’) The ‘ioctl.c’ module • These techniques are demonstrated in this device-driver module’s ‘ioctl()’ function • Two IOCTL commands are implemented – #define CURSOR_HIDE – #define CURSOR_SHOW 0 1 • Applications can open the device-file, then use an ioctl-command; for example: int fd = open( “/dev/vram”, O_RDWR ); ioctl( fd, CURSOR_HIDE); In-class exercise #1 • Try adding new IOCTL commands to the ‘ioctl.c’ driver which lets applications find or move the cursor’s screen-position; #define CURSOR_FIND 2 #define CURSOR_MOVE 3 struct { long x, y; } location; ioctl( fd, CURSOR_FIND, &location ); location.x += 40; location.y += 40; ioctl( fd, CURSOR_MOVE, &location ); In-class exercise #2 • We are not told what function is served by two of the SiS engine’s i/o locations: – 0x8500 (longword) cursor-image source-offset – 0x8504 (longword) <??? Unknown ???> – 0x8508 (longword) <??? Unknown ???> – 0x850C (longword) cursor-image horiz-coord – 0x8510 (longword) cursor-image vertl-coord • So can you ‘discover’ their purpose?