Skip to content

Commit 64c8e7a

Browse files
committed
Subject: basic linux kernel modules
Description:
1 parent c2f57b1 commit 64c8e7a

File tree

10 files changed

+261
-2
lines changed

10 files changed

+261
-2
lines changed

Makefile renamed to hello/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Makefile for hello.c
2-
obj-m=hello3.o
2+
obj-m := hello.o
33

44
KDIR=/usr/src/linux-headers-$(shell uname -r)
55

@@ -8,3 +8,4 @@ all:
88

99
clean:
1010
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean # from lkmpg
11+
rm -rvf *~

hello.c renamed to hello/hello.c

File renamed without changes.

hello2/Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Makefile for hello2.c
2+
obj-m := hello2.o
3+
4+
KDIR=/usr/src/linux-headers-$(shell uname -r)
5+
6+
all:
7+
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
8+
9+
clean:
10+
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean # from lkmpg
11+
rm -rvf *~

hello2.c renamed to hello2/hello2.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
#include<linux/module.h> /* to recognise this module as a mmodule */
1111
#include<linux/moduleparam.h> /* needed for passsing params to a module */
1212

13+
/* additional module info. Can be displayed when calling 'modinfo hello3.ko' */
14+
MODULE_LICENSE("GPL"); /* license */
15+
MODULE_AUTHOR("Tas Devil"); /* who wrote it */
16+
MODULE_DESCRIPTION("hello2: Kernel module demo"); /* purpose of module */
17+
1318
/* deaclare a variable */
1419
int param_var = 83434;
1520

hello3/Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Makefile for hello3.c
2+
obj-m := hello3.o
3+
4+
KDIR=/usr/src/linux-headers-$(shell uname -r)
5+
6+
all:
7+
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
8+
9+
clean:
10+
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean # from lkmpg
11+
rm -rvf *~

hello3.c renamed to hello3/hello3.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
/* additional module info. Can be displayed when calling 'modinfo hello3.ko' */
1515
MODULE_LICENSE("GPL"); /* license */
1616
MODULE_AUTHOR("Tas Devil"); /* who wrote it */
17-
MODULE_DESCRIPTION("Kernel module demo"); /* purpose of module */
17+
MODULE_DESCRIPTION("hello3: Kernel module demo"); /* purpose of module */
1818

1919
/* deaclare a variable */
2020
int param_var[3] = {0,0,0};

test_char_device/Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Makefile for testCharDevice.c
2+
obj-m := testCharDevice.o
3+
4+
KDIR=/usr/src/linux-headers-$(shell uname -r)
5+
6+
all:
7+
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
8+
9+
clean:
10+
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean # from lkmpg
11+
rm -rvf *~

test_char_device/testCharDevice.c

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/* fake char device */
2+
/* Usage:
3+
% make
4+
% insmod testCharDevice.ko
5+
% sudo mknod /dev/<device_name> major_number 0
6+
*/
7+
8+
#include<linux/init.h> /* to initiate a module */
9+
#include<linux/module.h> /* to recognise this module as a mmodule */
10+
#include<linux/fs.h> /* file operation structure, which
11+
allows to use to open/close and
12+
read/write the device */
13+
#include<linux/cdev.h> /* needed for char device, make cdev
14+
available. userspace to kernel
15+
space */
16+
#include<linux/semaphore.h> /* used acces to semaphore, process management
17+
syncronization behaviour */
18+
#include<asm/uaccess.h> /* copy_to_user;copy_from_user */
19+
20+
21+
/* additional module info. Can be displayed when calling 'modinfo' */
22+
MODULE_LICENSE("GPL"); /* license */
23+
MODULE_AUTHOR("Tas Devil"); /* who wrote it */
24+
MODULE_DESCRIPTION("Kernel module for character device"); /* purpose of module */
25+
26+
/* (1)create structure for fake char device */
27+
struct fake_device
28+
{
29+
char data[100];
30+
struct semaphore sem;
31+
} virtual_device;
32+
33+
/* (2) to register our device */
34+
/* we need a cdev object and some other variables */
35+
struct cdev *mcdev; /* m --> my */
36+
int major_number; /* will store a major number extracted
37+
from dev_t using macro
38+
mknod /dev/file c major minor */
39+
int ret; /* will hold return value of the
40+
function; this is because the
41+
kernel stack is very small so
42+
declaring variable will eat up the
43+
stack very fast */
44+
dev_t dev_num; /* will hold the majjor number that
45+
the kernel gives; name appears in
46+
/proc/devices */
47+
48+
#define DEVICE_NAME "testCharDevice"
49+
50+
/* (7) called on device_open
51+
inode refer to file in disk
52+
and contains info about that file
53+
struct file : is refer to an abstract open file
54+
*/
55+
int device_open(struct inode *inode, struct file *filp) {
56+
/* only allow one person to open this device by using a semaphore as
57+
mutual exclusive lock - mutex */
58+
if(down_interruptible(&virtual_device.sem) != 0) {
59+
printk(KERN_ALERT "testCharDevice: could not lock device during open");
60+
return -1;
61+
}
62+
63+
printk(KERN_INFO "testCharDevice: opened device");
64+
return 0;
65+
}
66+
67+
/* (8) called when user want to get information about device */
68+
ssize_t device_read(struct file* filp, char* bufStoreData, size_t bufCount, loff_t* curOffset) {
69+
/* take data from kernel(device) to user space(process) */
70+
/* copy_to_user(destination, source, sizeToTransfer) */
71+
printk(KERN_INFO "testCharDevice: reading from device");
72+
ret = copy_to_user(bufStoreData, virtual_device.data, bufCount);
73+
return ret;
74+
}
75+
76+
/* (9) called when user wants to send information to device */
77+
ssize_t device_write(struct file* filp, const char* bufSourceData, size_t bufCount, loff_t* curOffset){
78+
/* send data from user to kernel */
79+
/* copy_from_user(dest, source, count) */
80+
printk(KERN_INFO "testCharDevice: writing to device");
81+
ret = copy_from_user(virtual_device.data, bufSourceData, bufCount);
82+
return ret;
83+
}
84+
85+
/* (10) called upon user close */
86+
int device_close(struct inode *inode, struct file *filp) {
87+
/* by calling up, which is opposite to down of semaphore, we release
88+
the mutex that we obtained at device open. This has the effect of
89+
other process can access thr device now */
90+
up(&virtual_device.sem);
91+
printk(KERN_INFO "testCharDevice: closed device");
92+
return 0;
93+
}
94+
95+
/* (6)tells the kernel which function to call when user operates on our
96+
device file */
97+
struct file_operations fops =
98+
{
99+
.owner = THIS_MODULE, /* prevent unloading of this module when operatons are in use */
100+
.open = device_open, /* points to the method to call opening the device */
101+
.release = device_close, /* closing the device */
102+
.write = device_write, /* writing a device */
103+
.read = device_read /* reading from device */
104+
};
105+
106+
static int driver_entry(void) {
107+
/* (3) r3gister device isa two step process: */
108+
109+
/* ---------(1)----------- */
110+
/* use dynamic allocation to assign our device a major number
111+
--
112+
alloc_chrdev_region(dev_t*,uint fminor, uint count, char* name);
113+
*/
114+
115+
ret = alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME);
116+
/* dev_name will hold both major number and minor number */
117+
/* start from 0 and count till 1 */
118+
/* DEVICE_NAME */
119+
if(ret<0) {
120+
/* if kernel returns a negative number, means failed to allocate
121+
major number */
122+
printk(KERN_ALERT "testCharDevice: failed to allocate major number");
123+
return ret; /* error */
124+
}
125+
major_number = MAJOR(dev_num); /* extract major number from dev_num
126+
and store it in our variable */
127+
printk(KERN_INFO "testCharDevice: major number is: %d", major_number);
128+
printk(KERN_INFO "testCharDevice: device file name: %s", DEVICE_NAME); /* dmesg */
129+
130+
/* ----------(2)---------- */
131+
mcdev = cdev_alloc(); /* create our cdev structure;
132+
initialize cdev and allocate using
133+
cdev_alloc() */
134+
mcdev->ops = &fops; /* struct file operation */
135+
mcdev->owner = THIS_MODULE;
136+
137+
/* now that we have created our cdev, we have to add it to kernel */
138+
/* int cdev_add(struct cdev*, dev, dev_t num, unsigned int count) */
139+
ret = cdev_add(mcdev, dev_num, 1);
140+
if(ret<0) {
141+
/* check errors */
142+
printk(KERN_ALERT "testCharDevice: unable to add cdev to kernel");
143+
return ret;
144+
}
145+
146+
/* (4) Initialize our semaphore */
147+
sema_init(&virtual_device.sem,1); /* initial value of one */
148+
149+
return 0;
150+
}
151+
152+
static void driver_exit(void) {
153+
/* (5) unregister everything in reverse order */
154+
// (a)
155+
cdev_del(mcdev);
156+
157+
// (b)
158+
unregister_chrdev_region(dev_num, 1);
159+
printk(KERN_INFO "testCharDevice: unloaded module");
160+
161+
}
162+
163+
/* inform kernel wher to start and stop our module */
164+
module_init(driver_entry);
165+
module_exit(driver_exit);
166+

userapplication/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Makefile userapp.c
2+
SOURCE="userapp.c"
3+
BIN="userapp"
4+
all: userapp.c
5+
gcc -o $(BIN) $(SOURCE)
6+
clean:
7+
rm -rvf *~ userapp

userapplication/userapp.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/* user application which reads and writes to a device */
2+
/*
3+
Usage:
4+
% make
5+
% ./userapp
6+
*/
7+
#include<stdio.h>
8+
#include<stdlib.h>
9+
#include<fcntl.h>
10+
11+
#define DEVICE "/dev/testCharDevice"
12+
13+
int main(int argc, char *argv[])
14+
{
15+
int i, fd;
16+
char ch, write_buf[100], read_buf[100];
17+
18+
fd = open(DEVICE, O_RDWR); /* open for read/write */
19+
20+
if(fd == -1){
21+
printf("file %s either doesnot exit, or locked by another process\n", DEVICE);
22+
exit(-1);
23+
}
24+
printf("r - read from device,\nw- write from device\nEnter command: ");
25+
scanf("%c", &ch);
26+
27+
switch (ch){
28+
case 'w':
29+
printf ("enter data: ");
30+
scanf("%s", write_buf);
31+
write(fd, write_buf, sizeof(write_buf));
32+
break;
33+
34+
case 'r':
35+
read(fd, read_buf, sizeof(read_buf));
36+
printf ("device: %s\n", read_buf);
37+
break;
38+
39+
default:
40+
printf ("command not recognized\n");
41+
break;
42+
}
43+
44+
close(fd);
45+
return 0;
46+
}
47+

0 commit comments

Comments
 (0)