Process Concurrence
Introduction
linux Process Concurrence all conform to the same structure and interface: they have message handling main loop for accepting and handling interrupt messages (from the hardware device, via the kernel), and request messages from other processes.
In this project, you will write a linux device task to manipulate the keyboard's LEDs (the ones that indicate the state of the Caps Lock, Num Lock, and Scroll Lock keys).
Goals
See how the operating system and hardware interface.
Examine the linux architecture in detail.
Write some interesting code.
Tasks
You should implement this project in three phases:
Construct a simple device driver task that just loops, receiving messages and handling DEV_READ messages by returning dummy data.
Elaborate the simple driver to toggle the LEDs if it receives a DEV_WRITE message (with any data), and returns their status (on or off) if it receives a DEV_READ message.
Complete the project by interpreting the data sent with a DEV_WRITE message as a command to turn the LEDs on or off.
To accomplish these phases, you have to implement a new ``LED'' device task, make a name for it in the file system (/dev/led), give it a fixed task number and major device number, and install the task in the kernel and file system tables.
Implement your device task.
Create a directory src/drivers/led to contain your device implementation.
Create a file src/drivers/led/led.c, that has the following initial contents (this implements the behavior of phase 1 above; you have to write the do_ functions, of course):
--------------------------------------------------------------------------------
/* Query/set keyboard leds.
*
* John Noll 2/17/99 coen177.
* Modeled after clock.c, with code from keyboard.c
*/
#include "..drivers.h"
FORWARD _PROTOTYPE( int do_read, (message *) );
FORWARD _PROTOTYPE( int do_write, (message *) );
FORWARD _PROTOTYPE( int do_open, (message *) );
FORWARD _PROTOTYPE( int do_close, (message *) );
FORWARD _PROTOTYPE( int led_reply, (int, int, int, int) );
/*===========================================================================*
* led_task *
*===========================================================================*/
PUBLIC void led_task()
{
/* Main routine of the led task, phase 1. */
int r;
message msg; /* buffer for all incoming messages */
printf("LED Task is up and running!\n");
while (TRUE) {
receive(ANY, &msg);
/* Execute the requested function. */
switch (msg.m_type) {
case DEV_OPEN: r = do_open(&msg); break;
case DEV_READ: r = do_read(&msg); break;
case DEV_WRITE: r = do_write(&msg); break;
case DEV_CLOSE: r = do_close(&msg); break;
default:
printf("LED: unimplemented message from %d\n",
msg.m_source);
r = EINVAL;
break;
}
led_reply(TASK_REPLY, msg.m_source, msg.PROC_NR, r);
}
}
--------------------------------------------------------------------------------
Add your device implementation to the src/drivers/Makefile. Use the tty driver entry as an example.
Add an entry for your device task to src/include/com.h, in the ``User-space processes'' section. You should place it before INIT_PROC_NR and adjust the entries that follow accordingly.
Add an entry for your device task to src/kernel/table.c. Use the tty task's entry as a model, and be sure to put your entry in the location corresponding to its process number (LED_PROC_NR).
Add your led task directory to the PROGRAMS macro in src/tools/Makefile. The location is important, as the tasks get placed in the boot image according to the order they are listed in the PROGRAMS macro.
Build a new kernel containing your modifications; upon success make a boot floppy and reboot the system using your new kernel. If it boots successfully, you should see the led task's initialization message on the console. Once you complete this step, you know that you have successfully installed your new device driver and controlled them.

