Revision 72
logic/trunk/measurement_reader/src/startup/main.c | ||
---|---|---|
1 |
/* |
|
2 |
* main.c |
|
3 |
* |
|
4 |
* 2011, Janez Barbic (jhnsmth64@gmail.com) |
|
5 |
* |
|
6 |
*/ |
|
7 |
#include <stdio.h> |
|
8 |
#include <stdlib.h> |
|
9 |
#include <pthread.h> |
|
10 |
#include <syslog.h> |
|
11 |
#include <unistd.h> |
|
12 |
#include "../drv_comm/dev01/drv_comm.h" |
|
13 |
|
|
14 |
const char *dev1 = "/dev/dev_thermometer_01"; |
|
15 |
const char *dev2 = "/dev/dev_thermometer_02"; |
|
16 |
const char *dev3 = "/dev/dev_barometer_01"; |
|
17 |
const char *dev4 = "/dev/dev_hygrometer_01"; |
|
18 |
const char *dev5 = "/dev/dev_light_sensor_01"; |
|
19 |
const char *dev6 = "/dev/dev_smart_meter_01"; |
|
20 |
|
|
21 |
// Application entry point |
|
22 |
int main(int argc, char *argv[]) { |
|
23 |
/** //DAEMON |
|
24 |
pid_t pid, sid; |
|
25 |
|
|
26 |
pid = fork(); |
|
27 |
if (pid < 0) { |
|
28 |
exit(EXIT_FAILURE); |
|
29 |
} |
|
30 |
// EXIT PARENT |
|
31 |
if (pid > 0) { |
|
32 |
exit(EXIT_SUCCESS); |
|
33 |
} |
|
34 |
|
|
35 |
//umask(0); |
|
36 |
|
|
37 |
// Open any logs here |
|
38 |
|
|
39 |
// Create a new SID for the child process |
|
40 |
sid = setsid(); |
|
41 |
if (sid < 0) { |
|
42 |
// Log the failure |
|
43 |
exit(EXIT_FAILURE); |
|
44 |
} |
|
45 |
|
|
46 |
// Close out the standard file descriptors |
|
47 |
// Because daemons generally dont interact directly with user so there is no need of keeping these open |
|
48 |
close(STDIN_FILENO); |
|
49 |
close(STDOUT_FILENO); |
|
50 |
close(STDERR_FILENO); |
|
51 |
/**/ |
|
52 |
|
|
53 |
// read devices in a loop |
|
54 |
while(1) |
|
55 |
{ |
|
56 |
set_device_value(dev1,1); // termometer1 |
|
57 |
set_device_value(dev2,2); // |
|
58 |
set_device_value(dev3,3); // |
|
59 |
set_device_value(dev4,4); // |
|
60 |
set_device_value(dev5,5); // |
|
61 |
set_device_value(dev6,6); // |
|
62 |
sleep(60); //update every minute |
|
63 |
} |
|
64 |
|
|
65 |
exit(0); |
|
66 |
} |
logic/trunk/measurement_reader/src/drv_comm/dev01/drv_comm.h | ||
---|---|---|
1 |
/* |
|
2 |
* chardev.h − the header file with the ioctl definitions. |
|
3 |
* The declarations here have to be in a header file, because |
|
4 |
* they need to be known both to the kernel module |
|
5 |
* (in chardev.c) and the process calling ioctl (ioctl.c) |
|
6 |
*/ |
|
7 |
#ifndef DRV_COMM_H |
|
8 |
#define DRV_COMM_H |
|
9 |
#include <linux/ioctl.h> |
|
10 |
/* |
|
11 |
* The major device number. We can't rely on dynamic |
|
12 |
* registration any more, because ioctls need to know |
|
13 |
* it. |
|
14 |
*/ |
|
15 |
#define MAJOR_NUM_1 100 |
|
16 |
#define MAJOR_NUM_2 101 |
|
17 |
#define MAJOR_NUM_3 102 |
|
18 |
#define MAJOR_NUM_4 103 |
|
19 |
#define MAJOR_NUM_5 104 |
|
20 |
#define MAJOR_NUM_6 105 |
|
21 |
/* |
|
22 |
* Set the message of the device driver |
|
23 |
*/ |
|
24 |
#define IOCTL_SET_MSG_1 _IOR(MAJOR_NUM_1, 0, char *) |
|
25 |
#define IOCTL_SET_MSG_2 _IOR(MAJOR_NUM_1, 0, char *) |
|
26 |
#define IOCTL_SET_MSG_3 _IOR(MAJOR_NUM_1, 0, char *) |
|
27 |
#define IOCTL_SET_MSG_4 _IOR(MAJOR_NUM_1, 0, char *) |
|
28 |
#define IOCTL_SET_MSG_5 _IOR(MAJOR_NUM_1, 0, char *) |
|
29 |
#define IOCTL_SET_MSG_6 _IOR(MAJOR_NUM_1, 0, char *) |
|
30 |
|
|
31 |
ioctl_set_msg_1(int file_desc, char *message); |
|
32 |
ioctl_set_msg_2(int file_desc, char *message); |
|
33 |
ioctl_set_msg_3(int file_desc, char *message); |
|
34 |
ioctl_set_msg_4(int file_desc, char *message); |
|
35 |
ioctl_set_msg_5(int file_desc, char *message); |
|
36 |
ioctl_set_msg_6(int file_desc, char *message); |
|
37 |
void set_device_value(const char *dev,int devIdx); |
|
38 |
|
|
39 |
#endif //DRV_COMM_H |
logic/trunk/measurement_reader/src/drv_comm/dev01/generator.h | ||
---|---|---|
1 |
#ifndef GENERATOR_H_INCLUDED |
|
2 |
#define GENERATOR_H_INCLUDED |
|
3 |
int generate_value(); |
|
4 |
char *int_to_str(int nbr); |
|
5 |
|
|
6 |
#endif // GENERATOR_H_INCLUDED |
logic/trunk/measurement_reader/src/drv_comm/dev01/drv_comm.c | ||
---|---|---|
1 |
/* |
|
2 |
* ioctl.c − the process to use ioctl's to control the kernel module |
|
3 |
* |
|
4 |
* Until now we could have used cat for input and output. But now |
|
5 |
* we need to do ioctl's, which require writing our own process. |
|
6 |
*/ |
|
7 |
/* |
|
8 |
* device specifics, such as ioctl numbers and the |
|
9 |
* major device file. |
|
10 |
*/ |
|
11 |
#include "drv_comm.h" |
|
12 |
#include "generator.h" |
|
13 |
#include <stdio.h> |
|
14 |
#include <stdlib.h> |
|
15 |
#include <syslog.h> |
|
16 |
#include <fcntl.h> /* open */ |
|
17 |
#include <unistd.h> /* exit */ |
|
18 |
//#include <sys/ioctl.h> /* ioctl */ |
|
19 |
/* |
|
20 |
* Functions for the ioctl calls |
|
21 |
*/ |
|
22 |
ioctl_set_msg_1(int file_desc, char *message) |
|
23 |
{ |
|
24 |
int ret_val; |
|
25 |
ret_val = ioctl(file_desc, IOCTL_SET_MSG_1, message); |
|
26 |
if (ret_val < 0) { |
|
27 |
printf("ioctl_set_msg failed:%d\n", ret_val); |
|
28 |
exit(-1); |
|
29 |
} |
|
30 |
} |
|
31 |
|
|
32 |
ioctl_set_msg_2(int file_desc, char *message) |
|
33 |
{ |
|
34 |
int ret_val; |
|
35 |
ret_val = ioctl(file_desc, IOCTL_SET_MSG_2, message); |
|
36 |
if (ret_val < 0) { |
|
37 |
printf("ioctl_set_msg failed:%d\n", ret_val); |
|
38 |
exit(-1); |
|
39 |
} |
|
40 |
} |
|
41 |
|
|
42 |
ioctl_set_msg_3(int file_desc, char *message) |
|
43 |
{ |
|
44 |
int ret_val; |
|
45 |
ret_val = ioctl(file_desc, IOCTL_SET_MSG_3, message); |
|
46 |
if (ret_val < 0) { |
|
47 |
printf("ioctl_set_msg failed:%d\n", ret_val); |
|
48 |
exit(-1); |
|
49 |
} |
|
50 |
} |
|
51 |
|
|
52 |
ioctl_set_msg_4(int file_desc, char *message) |
|
53 |
{ |
|
54 |
int ret_val; |
|
55 |
ret_val = ioctl(file_desc, IOCTL_SET_MSG_4, message); |
|
56 |
if (ret_val < 0) { |
|
57 |
printf("ioctl_set_msg failed:%d\n", ret_val); |
|
58 |
exit(-1); |
|
59 |
} |
|
60 |
} |
|
61 |
|
|
62 |
ioctl_set_msg_5(int file_desc, char *message) |
|
63 |
{ |
|
64 |
int ret_val; |
|
65 |
ret_val = ioctl(file_desc, IOCTL_SET_MSG_5, message); |
|
66 |
if (ret_val < 0) { |
|
67 |
printf("ioctl_set_msg failed:%d\n", ret_val); |
|
68 |
exit(-1); |
|
69 |
} |
|
70 |
} |
|
71 |
|
|
72 |
ioctl_set_msg_6(int file_desc, char *message) |
|
73 |
{ |
|
74 |
int ret_val; |
|
75 |
ret_val = ioctl(file_desc, IOCTL_SET_MSG_6, message); |
|
76 |
if (ret_val < 0) { |
|
77 |
printf("ioctl_set_msg failed:%d\n", ret_val); |
|
78 |
exit(-1); |
|
79 |
} |
|
80 |
} |
|
81 |
|
|
82 |
void set_device_value(const char *dev, int devIdx) |
|
83 |
{ |
|
84 |
//TODO use mutex? |
|
85 |
int file_desc; |
|
86 |
|
|
87 |
char *msg = int_to_str(generate_value()); |
|
88 |
|
|
89 |
file_desc = open(dev, 0); |
|
90 |
|
|
91 |
if (file_desc < 0) { |
|
92 |
printf("Can't open device file: %s\n", dev); |
|
93 |
} |
|
94 |
else{ |
|
95 |
//printf("Open device file: %s\n", dev); |
|
96 |
switch(devIdx) |
|
97 |
{ |
|
98 |
case 1: |
|
99 |
//printf("Setting message dev %d\n", devIdx); |
|
100 |
ioctl_set_msg_1(file_desc, msg); |
|
101 |
break; |
|
102 |
case 2: |
|
103 |
//printf("Setting message dev %d\n", devIdx); |
|
104 |
ioctl_set_msg_2(file_desc, msg); |
|
105 |
break; |
|
106 |
case 3: |
|
107 |
//printf("Setting message dev %d\n", devIdx); |
|
108 |
ioctl_set_msg_3(file_desc, msg); |
|
109 |
break; |
|
110 |
case 4: |
|
111 |
//printf("Setting message dev %d\n", devIdx); |
|
112 |
ioctl_set_msg_4(file_desc, msg); |
|
113 |
break; |
|
114 |
case 5: |
|
115 |
//printf("Setting message dev %d\n", devIdx); |
|
116 |
ioctl_set_msg_5(file_desc, msg); |
|
117 |
break; |
|
118 |
case 6: |
|
119 |
//printf("Setting message dev %d\n", devIdx); |
|
120 |
ioctl_set_msg_6(file_desc, msg); |
|
121 |
break; |
|
122 |
|
|
123 |
} |
|
124 |
syslog(LOG_MAIL, "%s:%s", dev, msg); |
|
125 |
// TODO syslog |
|
126 |
} |
|
127 |
|
|
128 |
close(file_desc); |
|
129 |
} |
|
130 |
|
logic/trunk/measurement_reader/src/drv_comm/dev01/generator.c | ||
---|---|---|
1 |
#include <stdio.h> |
|
2 |
#include <stdlib.h> |
|
3 |
#include <time.h> |
|
4 |
#include <string.h> |
|
5 |
#include <unistd.h> |
|
6 |
|
|
7 |
#include "generator.h" |
|
8 |
|
|
9 |
//funkcija: |
|
10 |
int generate_value() { |
|
11 |
// nastavitev, minimalne in maksimalne temperature: |
|
12 |
//funkcija, torej od ure 00:00 raste od minimalne do maximalne, ki jo dosee pri uri 12:00 in nato spet pada do minimalne pri 24:00 |
|
13 |
double minimum=20; |
|
14 |
double maximum=27; |
|
15 |
|
|
16 |
time_t now; |
|
17 |
struct tm *ts; |
|
18 |
char buf1[80]; |
|
19 |
|
|
20 |
now = time(NULL); |
|
21 |
|
|
22 |
ts = localtime(&now); |
|
23 |
strcpy(buf1, asctime(ts)); |
|
24 |
|
|
25 |
int x1 = buf1[11]-48; |
|
26 |
int x2 = buf1[12]-48; |
|
27 |
int m1 = buf1[14]-48; |
|
28 |
int m2 = buf1[15]-48; |
|
29 |
|
|
30 |
int minutes = (x1*10+x2)*60 + m1*10+m2; |
|
31 |
int variable = minutes; |
|
32 |
|
|
33 |
if(variable>720) { |
|
34 |
variable= 720-(variable-720); |
|
35 |
} |
|
36 |
|
|
37 |
double k = ((double)variable)/((double)720); |
|
38 |
|
|
39 |
//funkcija vraca vrednost na eno decimalko natancno, podobno kot preproste i2c naprave |
|
40 |
return (int) (minimum + k * (maximum-minimum))*10; |
|
41 |
} |
|
42 |
//* |
|
43 |
char *int_to_str(int nbr) |
|
44 |
{ |
|
45 |
int div; |
|
46 |
int len; |
|
47 |
int i; |
|
48 |
char *res; |
|
49 |
|
|
50 |
res = malloc(4 * sizeof(*res)); |
|
51 |
i = 0; |
|
52 |
while (i < 3) |
|
53 |
res[i++] = '\0'; |
|
54 |
res[3] = '\0'; |
|
55 |
i = 0; |
|
56 |
div = 1; |
|
57 |
len = 1; |
|
58 |
while (nbr / div >= 10) |
|
59 |
{ |
|
60 |
div *= 10; |
|
61 |
len++; |
|
62 |
} |
|
63 |
while (len) |
|
64 |
{ |
|
65 |
res[i++] = '0' + (nbr / div); |
|
66 |
len--; |
|
67 |
nbr %= div; |
|
68 |
div /= 10; |
|
69 |
} |
|
70 |
return (res); |
|
71 |
} |
|
72 |
/**/ |
logic/trunk/measurement_reader/measurement_reader.cbp | ||
---|---|---|
1 |
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> |
|
2 |
<CodeBlocks_project_file> |
|
3 |
<FileVersion major="1" minor="6" /> |
|
4 |
<Project> |
|
5 |
<Option title="measurement_reader" /> |
|
6 |
<Option pch_mode="2" /> |
|
7 |
<Option compiler="gcc" /> |
|
8 |
<Build> |
|
9 |
<Target title="Debug"> |
|
10 |
<Option output="bin/Debug/measurement_reader" prefix_auto="1" extension_auto="1" /> |
|
11 |
<Option object_output="obj/Debug/" /> |
|
12 |
<Option type="1" /> |
|
13 |
<Option compiler="gcc" /> |
|
14 |
<Compiler> |
|
15 |
<Add option="-g" /> |
|
16 |
</Compiler> |
|
17 |
</Target> |
|
18 |
<Target title="Release"> |
|
19 |
<Option output="bin/Release/measurement_reader" prefix_auto="1" extension_auto="1" /> |
|
20 |
<Option object_output="obj/Release/" /> |
|
21 |
<Option type="1" /> |
|
22 |
<Option compiler="gcc" /> |
|
23 |
<Compiler> |
|
24 |
<Add option="-O2" /> |
|
25 |
</Compiler> |
|
26 |
<Linker> |
|
27 |
<Add option="-s" /> |
|
28 |
</Linker> |
|
29 |
</Target> |
|
30 |
</Build> |
|
31 |
<Compiler> |
|
32 |
<Add option="-Wall" /> |
|
33 |
</Compiler> |
|
34 |
<Unit filename="src/drv_comm/dev01/drv_comm.c"> |
|
35 |
<Option compilerVar="CC" /> |
|
36 |
</Unit> |
|
37 |
<Unit filename="src/drv_comm/dev01/drv_comm.h" /> |
|
38 |
<Unit filename="src/drv_comm/dev01/generator.c"> |
|
39 |
<Option compilerVar="CC" /> |
|
40 |
</Unit> |
|
41 |
<Unit filename="src/drv_comm/dev01/generator.h" /> |
|
42 |
<Unit filename="src/startup/main.c"> |
|
43 |
<Option compilerVar="CC" /> |
|
44 |
</Unit> |
|
45 |
<Extensions> |
|
46 |
<code_completion /> |
|
47 |
<debugger /> |
|
48 |
</Extensions> |
|
49 |
</Project> |
|
50 |
</CodeBlocks_project_file> |
logic/trunk/measurement_reader/Makefile | ||
---|---|---|
1 |
# |
|
2 |
# 2011, Aleksander Besir (alex.besir@gmail.com) |
|
3 |
# |
|
4 |
|
|
5 |
CC=arm-linux-gcc |
|
6 |
CFLAGS=-Wall -I. -pthread --sysroot=/home/arm/buildroot-2009.11-fri/output/staging |
|
7 |
BIN=bin |
|
8 |
SRC=src |
|
9 |
|
|
10 |
OBJ=$(SRC)/drv_comm/dev01/drv_comm.o $(SRC)/startup/main.o $(SRC)/drv_comm/dev01/generator.o |
|
11 |
|
|
12 |
all: $(BIN)/startup |
|
13 |
|
|
14 |
%.o: %.c |
|
15 |
$(CC) -c -o $@ $< $(CFLAGS) |
|
16 |
|
|
17 |
$(BIN)/startup: $(OBJ) |
|
18 |
$(CC) -o $(BIN)/measure_writer $^ $(CFLAGS) |
logic/trunk/driver/dev02/dev_thermometer_02.c | ||
---|---|---|
1 |
/* |
|
2 |
* chardev.c − Create an input/output character device |
|
3 |
*/ |
|
4 |
#include <linux/kernel.h> /* We're doing kernel work */ |
|
5 |
#include <linux/module.h> /* Specifically, a module */ |
|
6 |
#include <linux/fs.h> /* for get_user and put_user */ |
|
7 |
#include <linux/i2c.h> /* for get_user and put_user */ |
|
8 |
#include <linux/hwmon.h> /* for get_user and put_user */ |
|
9 |
#include <linux/err.h> /* for get_user and put_user */ |
|
10 |
#include <asm/uaccess.h> |
|
11 |
#include "dev_thermometer_02.h" |
|
12 |
|
|
13 |
#define SUCCESS 0 |
|
14 |
#define DEVICE_NAME "dev_thermometer_01" |
|
15 |
#define BUF_LEN 80 |
|
16 |
/* |
|
17 |
* Is the device open right now? Used to prevent |
|
18 |
* concurent access into the same device |
|
19 |
*/ |
|
20 |
static int Device_Open = 0; |
|
21 |
/* |
|
22 |
* The message the device will give when asked |
|
23 |
*/ |
|
24 |
static char Message[BUF_LEN]; |
|
25 |
/* |
|
26 |
* How far did the process reading the message get? |
|
27 |
* Useful if the message is larger than the size of the |
|
28 |
* buffer we get to fill in device_read. |
|
29 |
*/ |
|
30 |
static char *Message_Ptr; |
|
31 |
/* |
|
32 |
* This is called whenever a process attempts to open the device file |
|
33 |
*/ |
|
34 |
static int device_open(struct inode *inode, struct file *file) |
|
35 |
{ |
|
36 |
#ifdef DEBUG |
|
37 |
printk(KERN_INFO "device_open(%p)\n", file); |
|
38 |
#endif |
|
39 |
/* |
|
40 |
* We don't want to talk to two processes at the same time |
|
41 |
*/ |
|
42 |
if (Device_Open) |
|
43 |
return -EBUSY; |
|
44 |
Device_Open++; |
|
45 |
/* |
|
46 |
* Initialize the message |
|
47 |
*/ |
|
48 |
Message_Ptr = Message; |
|
49 |
try_module_get(THIS_MODULE); |
|
50 |
return SUCCESS; |
|
51 |
} |
|
52 |
|
|
53 |
static int device_release(struct inode *inode, struct file *file) |
|
54 |
{ |
|
55 |
#ifdef DEBUG |
|
56 |
printk(KERN_INFO "device_release(%p,%p)\n", inode, file); |
|
57 |
#endif |
|
58 |
/* |
|
59 |
* We're now ready for our next caller |
|
60 |
*/ |
|
61 |
Device_Open--; |
|
62 |
module_put(THIS_MODULE); |
|
63 |
return SUCCESS; |
|
64 |
} |
|
65 |
|
|
66 |
/* |
|
67 |
* This function is called whenever a process which has already opened the |
|
68 |
* device file attempts to read from it. |
|
69 |
*/ |
|
70 |
static ssize_t device_read(struct file *file, |
|
71 |
/* see include/linux/fs.h*/ |
|
72 |
char __user * buffer, |
|
73 |
/* buffer to be |
|
74 |
* filled with data */ |
|
75 |
size_t length, |
|
76 |
loff_t * offset) |
|
77 |
/* length of the buffer*/ |
|
78 |
{ |
|
79 |
/* |
|
80 |
* Number of bytes actually written to the buffer |
|
81 |
*/ |
|
82 |
int bytes_read = 0; |
|
83 |
#ifdef DEBUG |
|
84 |
printk(KERN_INFO "device_read(%p,%p,%d)\n", file, buffer, length); |
|
85 |
#endif |
|
86 |
/* |
|
87 |
* If we're at the end of the message, return 0 |
|
88 |
* (which signifies end of file) |
|
89 |
*/ |
|
90 |
if (*Message_Ptr == 0) |
|
91 |
return 0; |
|
92 |
/* |
|
93 |
* Actually put the data into the buffer |
|
94 |
*/ |
|
95 |
while (length && *Message_Ptr) { |
|
96 |
/* |
|
97 |
* Because the buffer is in the user data segment, |
|
98 |
* not the kernel data segment, assignment wouldn't |
|
99 |
* work. Instead, we have to use put_user which |
|
100 |
* copies data from the kernel data segment to the |
|
101 |
* user data segment. |
|
102 |
*/ |
|
103 |
put_user(*(Message_Ptr++), buffer++); |
|
104 |
length--; |
|
105 |
bytes_read++; |
|
106 |
} |
|
107 |
#ifdef DEBUG |
|
108 |
printk(KERN_INFO "Read %d bytes, %d left\n", bytes_read, length); |
|
109 |
#endif |
|
110 |
/* |
|
111 |
* Read functions are supposed to return the number |
|
112 |
* of bytes actually inserted into the buffer |
|
113 |
*/ |
|
114 |
return bytes_read; |
|
115 |
} |
|
116 |
|
|
117 |
/* |
|
118 |
* This function is called when somebody tries to |
|
119 |
* write into our device file. |
|
120 |
*/ |
|
121 |
static ssize_t |
|
122 |
device_write(struct file *file, |
|
123 |
const char __user * buffer, size_t length, loff_t * offset) |
|
124 |
{ |
|
125 |
int i; |
|
126 |
#ifdef DEBUG |
|
127 |
printk(KERN_INFO "device_write(%p,%s,%d)", file, buffer, length); |
|
128 |
#endif |
|
129 |
for (i = 0; i < length && i < BUF_LEN; i++) |
|
130 |
get_user(Message[i], buffer + i); |
|
131 |
Message_Ptr = Message; |
|
132 |
/* |
|
133 |
* Again, return the number of input characters used |
|
134 |
*/ |
|
135 |
return i; |
|
136 |
} |
|
137 |
|
|
138 |
/* |
|
139 |
* This function is called whenever a process tries to do an ioctl on our |
|
140 |
* device file. We get two extra parameters (additional to the inode and file |
|
141 |
* structures, which all device functions get): the number of the ioctl called |
|
142 |
* and the parameter given to the ioctl function. |
|
143 |
* |
|
144 |
* If the ioctl is write or read/write (meaning output is returned to the |
|
145 |
* calling process), the ioctl call returns the output of this function. |
|
146 |
* |
|
147 |
*/ |
|
148 |
int device_ioctl(struct inode *inode, |
|
149 |
/* see include/linux/fs.h */ |
|
150 |
struct file *file, |
|
151 |
/* ditto */ |
|
152 |
unsigned int ioctl_num, |
|
153 |
/* number and param for ioctl */ |
|
154 |
unsigned long ioctl_param) |
|
155 |
{ |
|
156 |
int i; |
|
157 |
char *temp; |
|
158 |
char ch; |
|
159 |
/* |
|
160 |
* Switch according to the ioctl called |
|
161 |
*/ |
|
162 |
switch (ioctl_num) { |
|
163 |
case IOCTL_SET_MSG: |
|
164 |
/* |
|
165 |
* Receive a pointer to a message (in user space) and set that |
|
166 |
* to be the device's message. Get the parameter given to |
|
167 |
* ioctl by the process. |
|
168 |
*/ |
|
169 |
temp = (char *)ioctl_param; |
|
170 |
/* |
|
171 |
* Find the length of the message |
|
172 |
*/ |
|
173 |
get_user(ch, temp); |
|
174 |
for (i = 0; ch && i < BUF_LEN; i++, temp++) |
|
175 |
get_user(ch, temp); |
|
176 |
device_write(file, (char *)ioctl_param, i, 0); |
|
177 |
break; |
|
178 |
case IOCTL_GET_MSG: |
|
179 |
/* |
|
180 |
* Give the current message to the calling process − |
|
181 |
* the parameter we got is a pointer, fill it. |
|
182 |
*/ |
|
183 |
i = device_read(file, (char *)ioctl_param, 99, 0); |
|
184 |
/* |
|
185 |
* Put a zero at the end of the buffer, so it will be |
|
186 |
* properly terminated |
|
187 |
*/ |
|
188 |
put_user('\0', (char *)ioctl_param + i); |
|
189 |
break; |
|
190 |
case IOCTL_GET_NTH_BYTE: |
|
191 |
/* |
|
192 |
* This ioctl is both input (ioctl_param) and |
|
193 |
* output (the return value of this function) |
|
194 |
*/ |
|
195 |
return Message[ioctl_param]; |
|
196 |
break; |
|
197 |
} |
|
198 |
return SUCCESS; |
|
199 |
} |
|
200 |
|
|
201 |
/* Module Declarations */ |
|
202 |
/* |
|
203 |
* This structure will hold the functions to be called |
|
204 |
* when a process does something to the device we |
|
205 |
* created. Since a pointer to this structure is kept in |
|
206 |
* the devices table, it can't be local to |
|
207 |
* init_module. NULL is for unimplemented functions. |
|
208 |
*/ |
|
209 |
struct file_operations Fops = { |
|
210 |
.read = device_read, |
|
211 |
.write = device_write, |
|
212 |
.ioctl = device_ioctl, |
|
213 |
.open = device_open, |
|
214 |
.release = device_release, |
|
215 |
/* a.k.a. close */ |
|
216 |
}; |
|
217 |
|
|
218 |
/* |
|
219 |
* Initialize the module − Register the character device |
|
220 |
*/ |
|
221 |
int init_module() |
|
222 |
{ |
|
223 |
int ret_val; |
|
224 |
/* |
|
225 |
* Register the character device (atleast try) |
|
226 |
*/ |
|
227 |
ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops); |
|
228 |
/* |
|
229 |
* Negative values signify an error |
|
230 |
*/ |
|
231 |
if (ret_val < 0) { |
|
232 |
printk(KERN_ALERT "%s failed with %d\n", |
|
233 |
"Sorry, registering the character device ", ret_val); |
|
234 |
return ret_val; |
|
235 |
} |
|
236 |
printk(KERN_INFO "%s The major device number is %d.\n", |
|
237 |
"Registeration is a success", MAJOR_NUM); |
|
238 |
return 0; |
|
239 |
} |
|
240 |
|
|
241 |
/* |
|
242 |
* Cleanup − unregister the appropriate file from /proc |
|
243 |
*/ |
|
244 |
void cleanup_module() |
|
245 |
{ |
|
246 |
//int ret; |
|
247 |
/* |
|
248 |
* Unregister the device |
|
249 |
*/ |
|
250 |
//ret = unregister_chrdev(MAJOR_NUM, DEVICE_NAME); |
|
251 |
printk(KERN_INFO "Unregistering module.\n"); |
|
252 |
unregister_chrdev(MAJOR_NUM, DEVICE_NAME); |
|
253 |
/* |
|
254 |
* If there's an error, report it |
|
255 |
*/ |
|
256 |
/* |
|
257 |
if (ret < 0) |
|
258 |
printk(KERN_ALERT "Error: unregister_chrdev: %d\n", ret); |
|
259 |
/**/ |
|
260 |
} |
|
261 |
|
logic/trunk/driver/dev02/Makefile | ||
---|---|---|
1 |
ifeq ($(KERNELRELEASE),) |
|
2 |
|
|
3 |
KERNELDIR ?= /lib/modules/$(shell uname -r)/build |
|
4 |
PWD := $(shell pwd) |
|
5 |
|
|
6 |
.PHONY: build clean |
|
7 |
|
|
8 |
build: |
|
9 |
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules |
|
10 |
|
|
11 |
clean: |
|
12 |
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c *.symvers *.order |
|
13 |
else |
|
14 |
|
|
15 |
$(info Building with KERNELRELEASE = ${KERNELRELEASE}) |
|
16 |
obj-m := dev_thermometer_02.o |
|
17 |
|
|
18 |
endif |
logic/trunk/driver/dev02/dev_thermometer_02.h | ||
---|---|---|
1 |
/* |
|
2 |
* chardev.h − the header file with the ioctl definitions. |
|
3 |
* The declarations here have to be in a header file, because |
|
4 |
* they need to be known both to the kernel module |
|
5 |
* (in chardev.c) and the process calling ioctl (ioctl.c) |
|
6 |
*/ |
|
7 |
#ifndef CHARDEV_H |
|
8 |
#define CHARDEV_H |
|
9 |
#include <linux/ioctl.h> |
|
10 |
/* |
|
11 |
* The major device number. We can't rely on dynamic |
|
12 |
* registration any more, because ioctls need to know |
|
13 |
* it. |
|
14 |
*/ |
|
15 |
#define MAJOR_NUM 101 |
|
16 |
/* |
|
17 |
* Set the message of the device driver |
|
18 |
*/ |
|
19 |
#define IOCTL_SET_MSG _IOR(MAJOR_NUM, 0, char *) |
|
20 |
/* |
|
21 |
* _IOR means that we're creating an ioctl command |
|
22 |
* number for passing information from a user process |
|
23 |
* to the kernel module. |
|
24 |
* |
|
25 |
* The first arguments, MAJOR_NUM, is the major device |
|
26 |
* number we're using. |
|
27 |
* |
|
28 |
* The second argument is the number of the command |
|
29 |
* (there could be several with different meanings). |
|
30 |
* |
|
31 |
* The third argument is the type we want to get from |
|
32 |
* the process to the kernel. |
|
33 |
*/ |
|
34 |
/* |
|
35 |
* Get the message of the device driver |
|
36 |
*/ |
|
37 |
#define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *) |
|
38 |
/* |
|
39 |
* This IOCTL is used for output, to get the message |
|
40 |
* of the device driver. However, we still need the |
|
41 |
* buffer to place the message in to be input, |
|
42 |
* as it is allocated by the process. |
|
43 |
*/ |
|
44 |
/* |
|
45 |
* Get the n'th byte of the message |
|
46 |
*/ |
|
47 |
#define IOCTL_GET_NTH_BYTE _IOWR(MAJOR_NUM, 2, int) |
|
48 |
/* |
|
49 |
* The IOCTL is used for both input and output. It |
|
50 |
* receives from the user a number, n, and returns |
|
51 |
* Message[n]. |
|
52 |
*/ |
|
53 |
/* |
|
54 |
* The name of the device file |
|
55 |
*/ |
|
56 |
#define DEVICE_FILE_NAME "char_dev" |
|
57 |
#endif |
|
58 |
|
logic/trunk/driver/dev03/Makefile | ||
---|---|---|
1 |
ifeq ($(KERNELRELEASE),) |
|
2 |
|
|
3 |
KERNELDIR ?= /lib/modules/$(shell uname -r)/build |
|
4 |
PWD := $(shell pwd) |
|
5 |
|
|
6 |
.PHONY: build clean |
|
7 |
|
|
8 |
build: |
|
9 |
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules |
|
10 |
|
|
11 |
clean: |
|
12 |
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c *.symvers *.order |
|
13 |
else |
|
14 |
|
|
15 |
$(info Building with KERNELRELEASE = ${KERNELRELEASE}) |
|
16 |
obj-m := dev_barometer_01.o |
|
17 |
|
|
18 |
endif |
logic/trunk/driver/dev03/dev_barometer_01.c | ||
---|---|---|
1 |
/* |
|
2 |
* chardev.c − Create an input/output character device |
|
3 |
*/ |
|
4 |
#include <linux/kernel.h> /* We're doing kernel work */ |
|
5 |
#include <linux/module.h> /* Specifically, a module */ |
|
6 |
#include <linux/fs.h> /* for get_user and put_user */ |
|
7 |
#include <linux/i2c.h> /* for get_user and put_user */ |
|
8 |
#include <linux/hwmon.h> /* for get_user and put_user */ |
|
9 |
#include <linux/err.h> /* for get_user and put_user */ |
|
10 |
#include <asm/uaccess.h> |
|
11 |
#include "dev_barometer_01.h" |
|
12 |
|
|
13 |
#define SUCCESS 0 |
|
14 |
#define DEVICE_NAME "dev_thermometer_01" |
|
15 |
#define BUF_LEN 80 |
|
16 |
/* |
|
17 |
* Is the device open right now? Used to prevent |
|
18 |
* concurent access into the same device |
|
19 |
*/ |
|
20 |
static int Device_Open = 0; |
|
21 |
/* |
|
22 |
* The message the device will give when asked |
|
23 |
*/ |
|
24 |
static char Message[BUF_LEN]; |
|
25 |
/* |
|
26 |
* How far did the process reading the message get? |
|
27 |
* Useful if the message is larger than the size of the |
|
28 |
* buffer we get to fill in device_read. |
|
29 |
*/ |
|
30 |
static char *Message_Ptr; |
|
31 |
/* |
|
32 |
* This is called whenever a process attempts to open the device file |
|
33 |
*/ |
|
34 |
static int device_open(struct inode *inode, struct file *file) |
|
35 |
{ |
|
36 |
#ifdef DEBUG |
|
37 |
printk(KERN_INFO "device_open(%p)\n", file); |
|
38 |
#endif |
|
39 |
/* |
|
40 |
* We don't want to talk to two processes at the same time |
|
41 |
*/ |
|
42 |
if (Device_Open) |
|
43 |
return -EBUSY; |
|
44 |
Device_Open++; |
|
45 |
/* |
|
46 |
* Initialize the message |
|
47 |
*/ |
|
48 |
Message_Ptr = Message; |
|
49 |
try_module_get(THIS_MODULE); |
|
50 |
return SUCCESS; |
|
51 |
} |
|
52 |
|
|
53 |
static int device_release(struct inode *inode, struct file *file) |
|
54 |
{ |
|
55 |
#ifdef DEBUG |
|
56 |
printk(KERN_INFO "device_release(%p,%p)\n", inode, file); |
|
57 |
#endif |
|
58 |
/* |
|
59 |
* We're now ready for our next caller |
|
60 |
*/ |
|
61 |
Device_Open--; |
|
62 |
module_put(THIS_MODULE); |
|
63 |
return SUCCESS; |
|
64 |
} |
|
65 |
|
|
66 |
/* |
|
67 |
* This function is called whenever a process which has already opened the |
|
68 |
* device file attempts to read from it. |
|
69 |
*/ |
|
70 |
static ssize_t device_read(struct file *file, |
|
71 |
/* see include/linux/fs.h*/ |
|
72 |
char __user * buffer, |
|
73 |
/* buffer to be |
|
74 |
* filled with data */ |
|
75 |
size_t length, |
|
76 |
loff_t * offset) |
|
77 |
/* length of the buffer*/ |
|
78 |
{ |
|
79 |
/* |
|
80 |
* Number of bytes actually written to the buffer |
|
81 |
*/ |
|
82 |
int bytes_read = 0; |
|
83 |
#ifdef DEBUG |
|
84 |
printk(KERN_INFO "device_read(%p,%p,%d)\n", file, buffer, length); |
|
85 |
#endif |
|
86 |
/* |
|
87 |
* If we're at the end of the message, return 0 |
|
88 |
* (which signifies end of file) |
|
89 |
*/ |
|
90 |
if (*Message_Ptr == 0) |
|
91 |
return 0; |
|
92 |
/* |
|
93 |
* Actually put the data into the buffer |
|
94 |
*/ |
|
95 |
while (length && *Message_Ptr) { |
|
96 |
/* |
|
97 |
* Because the buffer is in the user data segment, |
|
98 |
* not the kernel data segment, assignment wouldn't |
|
99 |
* work. Instead, we have to use put_user which |
|
100 |
* copies data from the kernel data segment to the |
|
101 |
* user data segment. |
|
102 |
*/ |
|
103 |
put_user(*(Message_Ptr++), buffer++); |
|
104 |
length--; |
|
105 |
bytes_read++; |
|
106 |
} |
|
107 |
#ifdef DEBUG |
|
108 |
printk(KERN_INFO "Read %d bytes, %d left\n", bytes_read, length); |
|
109 |
#endif |
|
110 |
/* |
|
111 |
* Read functions are supposed to return the number |
|
112 |
* of bytes actually inserted into the buffer |
|
113 |
*/ |
|
114 |
return bytes_read; |
|
115 |
} |
|
116 |
|
|
117 |
/* |
|
118 |
* This function is called when somebody tries to |
|
119 |
* write into our device file. |
|
120 |
*/ |
|
121 |
static ssize_t |
|
122 |
device_write(struct file *file, |
|
123 |
const char __user * buffer, size_t length, loff_t * offset) |
|
124 |
{ |
|
125 |
int i; |
|
126 |
#ifdef DEBUG |
|
127 |
printk(KERN_INFO "device_write(%p,%s,%d)", file, buffer, length); |
|
128 |
#endif |
|
129 |
for (i = 0; i < length && i < BUF_LEN; i++) |
|
130 |
get_user(Message[i], buffer + i); |
|
131 |
Message_Ptr = Message; |
|
132 |
/* |
|
133 |
* Again, return the number of input characters used |
|
134 |
*/ |
|
135 |
return i; |
|
136 |
} |
|
137 |
|
|
138 |
/* |
|
139 |
* This function is called whenever a process tries to do an ioctl on our |
|
140 |
* device file. We get two extra parameters (additional to the inode and file |
|
141 |
* structures, which all device functions get): the number of the ioctl called |
|
142 |
* and the parameter given to the ioctl function. |
|
143 |
* |
|
144 |
* If the ioctl is write or read/write (meaning output is returned to the |
|
145 |
* calling process), the ioctl call returns the output of this function. |
|
146 |
* |
|
147 |
*/ |
|
148 |
int device_ioctl(struct inode *inode, |
|
149 |
/* see include/linux/fs.h */ |
|
150 |
struct file *file, |
|
151 |
/* ditto */ |
|
152 |
unsigned int ioctl_num, |
|
153 |
/* number and param for ioctl */ |
|
154 |
unsigned long ioctl_param) |
|
155 |
{ |
|
156 |
int i; |
|
157 |
char *temp; |
|
158 |
char ch; |
|
159 |
/* |
|
160 |
* Switch according to the ioctl called |
|
161 |
*/ |
|
162 |
switch (ioctl_num) { |
|
163 |
case IOCTL_SET_MSG: |
|
164 |
/* |
|
165 |
* Receive a pointer to a message (in user space) and set that |
|
166 |
* to be the device's message. Get the parameter given to |
|
167 |
* ioctl by the process. |
|
168 |
*/ |
|
169 |
temp = (char *)ioctl_param; |
|
170 |
/* |
|
171 |
* Find the length of the message |
|
172 |
*/ |
|
173 |
get_user(ch, temp); |
|
174 |
for (i = 0; ch && i < BUF_LEN; i++, temp++) |
|
175 |
get_user(ch, temp); |
|
176 |
device_write(file, (char *)ioctl_param, i, 0); |
|
177 |
break; |
|
178 |
case IOCTL_GET_MSG: |
|
179 |
/* |
|
180 |
* Give the current message to the calling process − |
|
181 |
* the parameter we got is a pointer, fill it. |
|
182 |
*/ |
|
183 |
i = device_read(file, (char *)ioctl_param, 99, 0); |
|
184 |
/* |
|
185 |
* Put a zero at the end of the buffer, so it will be |
|
186 |
* properly terminated |
|
187 |
*/ |
|
188 |
put_user('\0', (char *)ioctl_param + i); |
|
189 |
break; |
|
190 |
case IOCTL_GET_NTH_BYTE: |
|
191 |
/* |
|
192 |
* This ioctl is both input (ioctl_param) and |
|
193 |
* output (the return value of this function) |
|
194 |
*/ |
|
195 |
return Message[ioctl_param]; |
|
196 |
break; |
|
197 |
} |
|
198 |
return SUCCESS; |
|
199 |
} |
|
200 |
|
|
201 |
/* Module Declarations */ |
|
202 |
/* |
|
203 |
* This structure will hold the functions to be called |
|
204 |
* when a process does something to the device we |
|
205 |
* created. Since a pointer to this structure is kept in |
|
206 |
* the devices table, it can't be local to |
|
207 |
* init_module. NULL is for unimplemented functions. |
|
208 |
*/ |
|
209 |
struct file_operations Fops = { |
|
210 |
.read = device_read, |
|
211 |
.write = device_write, |
|
212 |
.ioctl = device_ioctl, |
|
213 |
.open = device_open, |
|
214 |
.release = device_release, |
|
215 |
/* a.k.a. close */ |
|
216 |
}; |
|
217 |
|
|
218 |
/* |
|
219 |
* Initialize the module − Register the character device |
|
220 |
*/ |
|
221 |
int init_module() |
|
222 |
{ |
|
223 |
int ret_val; |
|
224 |
/* |
|
225 |
* Register the character device (atleast try) |
|
226 |
*/ |
|
227 |
ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops); |
|
228 |
/* |
|
229 |
* Negative values signify an error |
|
230 |
*/ |
|
231 |
if (ret_val < 0) { |
|
232 |
printk(KERN_ALERT "%s failed with %d\n", |
|
233 |
"Sorry, registering the character device ", ret_val); |
|
234 |
return ret_val; |
|
235 |
} |
|
236 |
printk(KERN_INFO "%s The major device number is %d.\n", |
|
237 |
"Registeration is a success", MAJOR_NUM); |
|
238 |
return 0; |
|
239 |
} |
|
240 |
|
|
241 |
/* |
|
242 |
* Cleanup − unregister the appropriate file from /proc |
|
243 |
*/ |
|
244 |
void cleanup_module() |
|
245 |
{ |
|
246 |
//int ret; |
|
247 |
/* |
|
248 |
* Unregister the device |
|
249 |
*/ |
|
250 |
//ret = unregister_chrdev(MAJOR_NUM, DEVICE_NAME); |
|
251 |
printk(KERN_INFO "Unregistering module.\n"); |
|
252 |
unregister_chrdev(MAJOR_NUM, DEVICE_NAME); |
|
253 |
/* |
|
254 |
* If there's an error, report it |
|
255 |
*/ |
|
256 |
/* |
|
257 |
if (ret < 0) |
|
258 |
printk(KERN_ALERT "Error: unregister_chrdev: %d\n", ret); |
|
259 |
/**/ |
|
260 |
} |
|
261 |
|
logic/trunk/driver/dev03/dev_barometer_01.h | ||
---|---|---|
1 |
/* |
|
2 |
* chardev.h − the header file with the ioctl definitions. |
|
3 |
* The declarations here have to be in a header file, because |
|
4 |
* they need to be known both to the kernel module |
|
5 |
* (in chardev.c) and the process calling ioctl (ioctl.c) |
|
6 |
*/ |
|
7 |
#ifndef CHARDEV_H |
|
8 |
#define CHARDEV_H |
|
9 |
#include <linux/ioctl.h> |
|
10 |
/* |
|
11 |
* The major device number. We can't rely on dynamic |
|
12 |
* registration any more, because ioctls need to know |
|
13 |
* it. |
|
14 |
*/ |
|
15 |
#define MAJOR_NUM 102 |
|
16 |
/* |
|
17 |
* Set the message of the device driver |
|
18 |
*/ |
|
19 |
#define IOCTL_SET_MSG _IOR(MAJOR_NUM, 0, char *) |
|
20 |
/* |
|
21 |
* _IOR means that we're creating an ioctl command |
|
22 |
* number for passing information from a user process |
|
23 |
* to the kernel module. |
|
24 |
* |
|
25 |
* The first arguments, MAJOR_NUM, is the major device |
|
26 |
* number we're using. |
|
27 |
* |
|
28 |
* The second argument is the number of the command |
|
29 |
* (there could be several with different meanings). |
|
30 |
* |
|
31 |
* The third argument is the type we want to get from |
|
32 |
* the process to the kernel. |
|
33 |
*/ |
|
34 |
/* |
|
35 |
* Get the message of the device driver |
|
36 |
*/ |
|
37 |
#define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *) |
|
38 |
/* |
|
39 |
* This IOCTL is used for output, to get the message |
|
40 |
* of the device driver. However, we still need the |
|
41 |
* buffer to place the message in to be input, |
|
42 |
* as it is allocated by the process. |
|
43 |
*/ |
|
44 |
/* |
|
45 |
* Get the n'th byte of the message |
|
46 |
*/ |
|
47 |
#define IOCTL_GET_NTH_BYTE _IOWR(MAJOR_NUM, 2, int) |
|
48 |
/* |
|
49 |
* The IOCTL is used for both input and output. It |
|
50 |
* receives from the user a number, n, and returns |
|
51 |
* Message[n]. |
|
52 |
*/ |
|
53 |
/* |
|
54 |
* The name of the device file |
|
55 |
*/ |
|
56 |
#define DEVICE_FILE_NAME "char_dev" |
|
57 |
#endif |
|
58 |
|
logic/trunk/driver/dev04/dev_hygrometer_01.h | ||
---|---|---|
1 |
/* |
|
2 |
* chardev.h − the header file with the ioctl definitions. |
|
3 |
* The declarations here have to be in a header file, because |
|
4 |
* they need to be known both to the kernel module |
|
5 |
* (in chardev.c) and the process calling ioctl (ioctl.c) |
|
6 |
*/ |
|
7 |
#ifndef CHARDEV_H |
|
8 |
#define CHARDEV_H |
|
9 |
#include <linux/ioctl.h> |
|
10 |
/* |
|
11 |
* The major device number. We can't rely on dynamic |
|
12 |
* registration any more, because ioctls need to know |
|
13 |
* it. |
|
14 |
*/ |
|
15 |
#define MAJOR_NUM 103 |
|
16 |
/* |
|
17 |
* Set the message of the device driver |
|
18 |
*/ |
|
19 |
#define IOCTL_SET_MSG _IOR(MAJOR_NUM, 0, char *) |
|
20 |
/* |
|
21 |
* _IOR means that we're creating an ioctl command |
|
22 |
* number for passing information from a user process |
|
23 |
* to the kernel module. |
|
24 |
* |
|
25 |
* The first arguments, MAJOR_NUM, is the major device |
|
26 |
* number we're using. |
|
27 |
* |
|
28 |
* The second argument is the number of the command |
|
29 |
* (there could be several with different meanings). |
|
30 |
* |
|
31 |
* The third argument is the type we want to get from |
|
32 |
* the process to the kernel. |
|
33 |
*/ |
|
34 |
/* |
|
35 |
* Get the message of the device driver |
|
36 |
*/ |
|
37 |
#define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *) |
|
38 |
/* |
|
39 |
* This IOCTL is used for output, to get the message |
|
40 |
* of the device driver. However, we still need the |
|
41 |
* buffer to place the message in to be input, |
|
42 |
* as it is allocated by the process. |
|
43 |
*/ |
|
44 |
/* |
|
45 |
* Get the n'th byte of the message |
|
46 |
*/ |
|
47 |
#define IOCTL_GET_NTH_BYTE _IOWR(MAJOR_NUM, 2, int) |
|
48 |
/* |
|
49 |
* The IOCTL is used for both input and output. It |
|
50 |
* receives from the user a number, n, and returns |
|
51 |
* Message[n]. |
|
52 |
*/ |
|
53 |
/* |
|
54 |
* The name of the device file |
|
55 |
*/ |
|
56 |
#define DEVICE_FILE_NAME "char_dev" |
|
57 |
#endif |
|
58 |
|
logic/trunk/driver/dev04/Makefile | ||
---|---|---|
1 |
ifeq ($(KERNELRELEASE),) |
|
2 |
|
|
3 |
KERNELDIR ?= /lib/modules/$(shell uname -r)/build |
|
4 |
PWD := $(shell pwd) |
|
5 |
|
|
6 |
.PHONY: build clean |
|
7 |
|
|
8 |
build: |
|
9 |
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules |
|
10 |
|
|
11 |
clean: |
|
12 |
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c *.symvers *.order |
|
13 |
else |
|
14 |
|
|
15 |
$(info Building with KERNELRELEASE = ${KERNELRELEASE}) |
|
16 |
obj-m := dev_hygrometer_01.o |
|
17 |
|
|
18 |
endif |
logic/trunk/driver/dev04/dev_hygrometer_01.c | ||
---|---|---|
1 |
/* |
|
2 |
* chardev.c − Create an input/output character device |
|
3 |
*/ |
|
4 |
#include <linux/kernel.h> /* We're doing kernel work */ |
|
5 |
#include <linux/module.h> /* Specifically, a module */ |
|
6 |
#include <linux/fs.h> /* for get_user and put_user */ |
|
7 |
#include <linux/i2c.h> /* for get_user and put_user */ |
|
8 |
#include <linux/hwmon.h> /* for get_user and put_user */ |
|
9 |
#include <linux/err.h> /* for get_user and put_user */ |
|
10 |
#include <asm/uaccess.h> |
|
11 |
#include "dev_hygrometer_01.h" |
|
12 |
|
|
13 |
#define SUCCESS 0 |
|
14 |
#define DEVICE_NAME "dev_thermometer_01" |
|
15 |
#define BUF_LEN 80 |
|
16 |
/* |
|
17 |
* Is the device open right now? Used to prevent |
|
18 |
* concurent access into the same device |
|
19 |
*/ |
|
20 |
static int Device_Open = 0; |
|
21 |
/* |
|
22 |
* The message the device will give when asked |
|
23 |
*/ |
|
24 |
static char Message[BUF_LEN]; |
|
25 |
/* |
|
26 |
* How far did the process reading the message get? |
|
27 |
* Useful if the message is larger than the size of the |
|
28 |
* buffer we get to fill in device_read. |
|
29 |
*/ |
|
30 |
static char *Message_Ptr; |
|
31 |
/* |
|
32 |
* This is called whenever a process attempts to open the device file |
|
33 |
*/ |
|
34 |
static int device_open(struct inode *inode, struct file *file) |
|
35 |
{ |
|
36 |
#ifdef DEBUG |
|
37 |
printk(KERN_INFO "device_open(%p)\n", file); |
|
38 |
#endif |
|
39 |
/* |
|
40 |
* We don't want to talk to two processes at the same time |
|
41 |
*/ |
|
42 |
if (Device_Open) |
|
43 |
return -EBUSY; |
|
44 |
Device_Open++; |
|
45 |
/* |
|
46 |
* Initialize the message |
|
47 |
*/ |
|
48 |
Message_Ptr = Message; |
|
49 |
try_module_get(THIS_MODULE); |
|
50 |
return SUCCESS; |
|
51 |
} |
|
52 |
|
|
53 |
static int device_release(struct inode *inode, struct file *file) |
|
54 |
{ |
|
55 |
#ifdef DEBUG |
|
56 |
printk(KERN_INFO "device_release(%p,%p)\n", inode, file); |
|
57 |
#endif |
|
58 |
/* |
|
59 |
* We're now ready for our next caller |
|
60 |
*/ |
|
61 |
Device_Open--; |
|
62 |
module_put(THIS_MODULE); |
|
63 |
return SUCCESS; |
|
64 |
} |
|
65 |
|
|
66 |
/* |
|
67 |
* This function is called whenever a process which has already opened the |
|
68 |
* device file attempts to read from it. |
|
69 |
*/ |
|
70 |
static ssize_t device_read(struct file *file, |
|
71 |
/* see include/linux/fs.h*/ |
|
72 |
char __user * buffer, |
|
73 |
/* buffer to be |
|
74 |
* filled with data */ |
|
75 |
size_t length, |
|
76 |
loff_t * offset) |
|
77 |
/* length of the buffer*/ |
|
78 |
{ |
|
79 |
/* |
|
80 |
* Number of bytes actually written to the buffer |
|
81 |
*/ |
|
82 |
int bytes_read = 0; |
|
83 |
#ifdef DEBUG |
|
84 |
printk(KERN_INFO "device_read(%p,%p,%d)\n", file, buffer, length); |
|
85 |
#endif |
|
86 |
/* |
|
87 |
* If we're at the end of the message, return 0 |
|
88 |
* (which signifies end of file) |
|
89 |
*/ |
|
90 |
if (*Message_Ptr == 0) |
|
91 |
return 0; |
|
92 |
/* |
|
93 |
* Actually put the data into the buffer |
|
94 |
*/ |
|
95 |
while (length && *Message_Ptr) { |
|
96 |
/* |
|
97 |
* Because the buffer is in the user data segment, |
|
98 |
* not the kernel data segment, assignment wouldn't |
|
99 |
* work. Instead, we have to use put_user which |
|
100 |
* copies data from the kernel data segment to the |
|
101 |
* user data segment. |
|
102 |
*/ |
|
103 |
put_user(*(Message_Ptr++), buffer++); |
|
104 |
length--; |
|
105 |
bytes_read++; |
|
106 |
} |
|
107 |
#ifdef DEBUG |
|
108 |
printk(KERN_INFO "Read %d bytes, %d left\n", bytes_read, length); |
|
109 |
#endif |
|
110 |
/* |
|
111 |
* Read functions are supposed to return the number |
|
112 |
* of bytes actually inserted into the buffer |
|
113 |
*/ |
|
114 |
return bytes_read; |
|
115 |
} |
|
116 |
|
|
117 |
/* |
|
118 |
* This function is called when somebody tries to |
|
119 |
* write into our device file. |
|
120 |
*/ |
|
121 |
static ssize_t |
|
122 |
device_write(struct file *file, |
|
123 |
const char __user * buffer, size_t length, loff_t * offset) |
|
124 |
{ |
|
125 |
int i; |
|
126 |
#ifdef DEBUG |
|
127 |
printk(KERN_INFO "device_write(%p,%s,%d)", file, buffer, length); |
|
128 |
#endif |
|
129 |
for (i = 0; i < length && i < BUF_LEN; i++) |
|
130 |
get_user(Message[i], buffer + i); |
|
131 |
Message_Ptr = Message; |
|
132 |
/* |
|
133 |
* Again, return the number of input characters used |
|
134 |
*/ |
|
135 |
return i; |
|
136 |
} |
|
137 |
|
|
138 |
/* |
|
139 |
* This function is called whenever a process tries to do an ioctl on our |
|
140 |
* device file. We get two extra parameters (additional to the inode and file |
|
141 |
* structures, which all device functions get): the number of the ioctl called |
|
142 |
* and the parameter given to the ioctl function. |
|
143 |
* |
|
144 |
* If the ioctl is write or read/write (meaning output is returned to the |
|
145 |
* calling process), the ioctl call returns the output of this function. |
|
146 |
* |
|
147 |
*/ |
|
148 |
int device_ioctl(struct inode *inode, |
|
149 |
/* see include/linux/fs.h */ |
|
150 |
struct file *file, |
|
151 |
/* ditto */ |
|
152 |
unsigned int ioctl_num, |
|
153 |
/* number and param for ioctl */ |
|
154 |
unsigned long ioctl_param) |
|
155 |
{ |
|
156 |
int i; |
|
157 |
char *temp; |
|
158 |
char ch; |
|
159 |
/* |
|
160 |
* Switch according to the ioctl called |
|
161 |
*/ |
|
162 |
switch (ioctl_num) { |
|
163 |
case IOCTL_SET_MSG: |
|
164 |
/* |
|
165 |
* Receive a pointer to a message (in user space) and set that |
|
166 |
* to be the device's message. Get the parameter given to |
|
167 |
* ioctl by the process. |
|
168 |
*/ |
|
169 |
temp = (char *)ioctl_param; |
|
170 |
/* |
|
171 |
* Find the length of the message |
|
172 |
*/ |
|
173 |
get_user(ch, temp); |
|
174 |
for (i = 0; ch && i < BUF_LEN; i++, temp++) |
|
175 |
get_user(ch, temp); |
|
176 |
device_write(file, (char *)ioctl_param, i, 0); |
|
177 |
break; |
|
178 |
case IOCTL_GET_MSG: |
|
179 |
/* |
|
180 |
* Give the current message to the calling process − |
|
181 |
* the parameter we got is a pointer, fill it. |
|
182 |
*/ |
|
183 |
i = device_read(file, (char *)ioctl_param, 99, 0); |
|
184 |
/* |
|
185 |
* Put a zero at the end of the buffer, so it will be |
|
186 |
* properly terminated |
|
187 |
*/ |
|
188 |
put_user('\0', (char *)ioctl_param + i); |
|
189 |
break; |
|
190 |
case IOCTL_GET_NTH_BYTE: |
|
191 |
/* |
|
192 |
* This ioctl is both input (ioctl_param) and |
|
193 |
* output (the return value of this function) |
|
194 |
*/ |
|
195 |
return Message[ioctl_param]; |
|
196 |
break; |
|
197 |
} |
|
198 |
return SUCCESS; |
|
199 |
} |
|
200 |
|
|
201 |
/* Module Declarations */ |
|
202 |
/* |
|
203 |
* This structure will hold the functions to be called |
|
204 |
* when a process does something to the device we |
|
205 |
* created. Since a pointer to this structure is kept in |
|
206 |
* the devices table, it can't be local to |
|
207 |
* init_module. NULL is for unimplemented functions. |
|
208 |
*/ |
|
209 |
struct file_operations Fops = { |
|
210 |
.read = device_read, |
|
211 |
.write = device_write, |
|
212 |
.ioctl = device_ioctl, |
|
213 |
.open = device_open, |
|
214 |
.release = device_release, |
|
215 |
/* a.k.a. close */ |
|
216 |
}; |
|
217 |
|
|
218 |
/* |
|
219 |
* Initialize the module − Register the character device |
|
220 |
*/ |
|
221 |
int init_module() |
|
222 |
{ |
|
223 |
int ret_val; |
|
224 |
/* |
|
225 |
* Register the character device (atleast try) |
|
226 |
*/ |
|
227 |
ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops); |
|
228 |
/* |
|
229 |
* Negative values signify an error |
|
230 |
*/ |
|
231 |
if (ret_val < 0) { |
|
232 |
printk(KERN_ALERT "%s failed with %d\n", |
|
233 |
"Sorry, registering the character device ", ret_val); |
|
234 |
return ret_val; |
|
235 |
} |
|
236 |
printk(KERN_INFO "%s The major device number is %d.\n", |
|
237 |
"Registeration is a success", MAJOR_NUM); |
|
238 |
return 0; |
|
239 |
} |
|
240 |
|
|
241 |
/* |
|
242 |
* Cleanup − unregister the appropriate file from /proc |
|
243 |
*/ |
|
244 |
void cleanup_module() |
|
245 |
{ |
|
246 |
//int ret; |
|
247 |
/* |
|
248 |
* Unregister the device |
|
249 |
*/ |
|
250 |
//ret = unregister_chrdev(MAJOR_NUM, DEVICE_NAME); |
|
251 |
printk(KERN_INFO "Unregistering module.\n"); |
|
252 |
unregister_chrdev(MAJOR_NUM, DEVICE_NAME); |
|
253 |
/* |
|
254 |
* If there's an error, report it |
|
255 |
*/ |
|
256 |
/* |
|
257 |
if (ret < 0) |
|
258 |
printk(KERN_ALERT "Error: unregister_chrdev: %d\n", ret); |
|
259 |
/**/ |
|
260 |
} |
|
261 |
|
logic/trunk/driver/dev05/dev_light_sensor_01.h | ||
---|---|---|
1 |
/* |
|
2 |
* chardev.h − the header file with the ioctl definitions. |
|
3 |
* The declarations here have to be in a header file, because |
|
4 |
* they need to be known both to the kernel module |
|
5 |
* (in chardev.c) and the process calling ioctl (ioctl.c) |
Also available in: Unified diff