Import changes from 2021-2022
This commit is contained in:
16
.devcontainer/02_01.code-workspace
Normal file
16
.devcontainer/02_01.code-workspace
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": ".."
|
||||
},
|
||||
{
|
||||
"path": "../src/02_modules/exercice01"
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"files.associations": {
|
||||
"moduleparam.h": "c",
|
||||
"ranges": "c"
|
||||
}
|
||||
}
|
||||
}
|
||||
11
.devcontainer/core_dumps.code-workspace
Normal file
11
.devcontainer/core_dumps.code-workspace
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": ".."
|
||||
},
|
||||
{
|
||||
"path": "../src/01_environment/core_dumps"
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ services:
|
||||
-s "rootfs;/rootfs;no;no"
|
||||
-s "workspace;/workspace;no;no"
|
||||
-s "home;/root-home;no;no"
|
||||
-g "unix extensions = yes"
|
||||
-g "vfs objects = catia fruit"
|
||||
ports:
|
||||
- "139:139"
|
||||
|
||||
11
.devcontainer/fibonacci.code-workspace
Normal file
11
.devcontainer/fibonacci.code-workspace
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": ".."
|
||||
},
|
||||
{
|
||||
"path": "../src/01_environment/fibonacci"
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
||||
26
.gitignore
vendored
26
.gitignore
vendored
@@ -2,4 +2,28 @@ images
|
||||
buildroot-images
|
||||
src/*/app
|
||||
.obj
|
||||
.deleted
|
||||
.deleted
|
||||
|
||||
.DS_Store
|
||||
|
||||
src/**/.Module.*
|
||||
src/**/Module.symvers
|
||||
src/**/.mymodule.*
|
||||
src/**/mymodule.*
|
||||
src/**/.modules.*
|
||||
src/**/.*.cmd*
|
||||
src/**/app
|
||||
src/**/core
|
||||
src/**/modules.order
|
||||
src/**/.skeleton.*
|
||||
|
||||
src/**/*.o
|
||||
src/**/*.dtb
|
||||
src/**/*.ovl
|
||||
|
||||
src/02_modules/procstat/procstat
|
||||
src/02_modules/procstat/procstat_s
|
||||
|
||||
src/03_drivers/sample01/main1
|
||||
src/03_drivers/sample01/main2
|
||||
src/03_drivers/sample01/main3
|
||||
|
||||
20
.vscode/c_cpp_properties.json
vendored
Normal file
20
.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"/buildroot/output/build/linux-5.15.21/include",
|
||||
"/buildroot/output/build/linux-5.15.21/arch/arm64/include",
|
||||
"/buildroot/output/build/linux-5.15.21/arch/arm64/include/generated",
|
||||
"/buildroot/output/build/linux-5.15.21/**"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/clang",
|
||||
"cStandard": "c99",
|
||||
"cppStandard": "c++14",
|
||||
"intelliSenseMode": "linux-clang-arm64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
14
src/.clang-format
Normal file
14
src/.clang-format
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
BasedOnStyle: Google
|
||||
IndentWidth: 4
|
||||
---
|
||||
Language: Cpp
|
||||
ColumnLimit: 80
|
||||
BreakBeforeBraces: Custom
|
||||
AlignConsecutiveAssignments: true
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterFunction: true
|
||||
@@ -4,7 +4,6 @@
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"name": "(gdb) Launch",
|
||||
"type": "cppdbg",
|
||||
|
||||
5
src/02_modules/Makefile
Normal file
5
src/02_modules/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
DIRS=$(filter-out Makefile, $(wildcard *))
|
||||
|
||||
all clean install:
|
||||
for dir in $(DIRS); do $(MAKE) $@ -C $$dir; done
|
||||
|
||||
19
src/02_modules/exercice01/.vscode/c_cpp_properties.json
vendored
Normal file
19
src/02_modules/exercice01/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"/buildroot/output/build/linux-5.15.21/include",
|
||||
"/buildroot/output/build/linux-5.15.21/arch/arm64/include",
|
||||
"/buildroot/output/build/linux-5.15.21/arch/arm64/include/generated"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/clang",
|
||||
"cStandard": "c99",
|
||||
"cppStandard": "c++14",
|
||||
"intelliSenseMode": "linux-clang-arm64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
30
src/02_modules/exercice01/Makefile
Normal file
30
src/02_modules/exercice01/Makefile
Normal file
@@ -0,0 +1,30 @@
|
||||
export PATH := /buildroot/output/host/usr/sbin$\
|
||||
:/buildroot/output/host/usr/bin/$\
|
||||
:/buildroot/output/host/sbin$\
|
||||
:/buildroot/output/host/bin/$\
|
||||
:$(PATH)
|
||||
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
CFLAGS_skeleton.o := -DDEBUG
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
echo $(PATH)
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
31
src/02_modules/exercice01/skeleton.c
Normal file
31
src/02_modules/exercice01/skeleton.c
Normal file
@@ -0,0 +1,31 @@
|
||||
// skeleton.c
|
||||
#include <linux/module.h> // needed by all modules
|
||||
#include <linux/init.h> // needed for macros
|
||||
#include <linux/kernel.h> // needed for debugging
|
||||
|
||||
#include <linux/moduleparam.h> // needed for module parameters
|
||||
|
||||
static char* text = "dummy text";
|
||||
module_param(text, charp, 0664);
|
||||
static int elements = 1;
|
||||
module_param(elements, int, 0);
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
pr_info ("Linux module 01 skeleton loaded\n");
|
||||
pr_debug (" text: %s\n elements: %d\n", text, elements);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
pr_info ("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init (skeleton_init);
|
||||
module_exit (skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR ("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION ("Module skeleton");
|
||||
MODULE_LICENSE ("GPL");
|
||||
|
||||
27
src/02_modules/exercice04/Makefile
Normal file
27
src/02_modules/exercice04/Makefile
Normal file
@@ -0,0 +1,27 @@
|
||||
export PATH := /buildroot/output/host/usr/sbin$\
|
||||
:/buildroot/output/host/usr/bin/$\
|
||||
:/buildroot/output/host/sbin$\
|
||||
:/buildroot/output/host/bin/$\
|
||||
:$(PATH)
|
||||
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
16
src/02_modules/exercice04/host.mk
Normal file
16
src/02_modules/exercice04/host.mk
Normal file
@@ -0,0 +1,16 @@
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
else
|
||||
KDIR := /lib/modules/$(shell uname -r)/build
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
endif
|
||||
64
src/02_modules/exercice04/skeleton.c
Normal file
64
src/02_modules/exercice04/skeleton.c
Normal file
@@ -0,0 +1,64 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
|
||||
#include <linux/moduleparam.h> /* needed for module parameters */
|
||||
|
||||
#include <linux/slab.h> /* needed for dynamic memory allocation */
|
||||
#include <linux/list.h> /* needed for linked list processing */
|
||||
#include <linux/string.h> /* needed for string handling */
|
||||
|
||||
static char* text = "dummy text";
|
||||
module_param(text, charp, 0);
|
||||
static int elements = 0;
|
||||
module_param(elements, int, 0);
|
||||
|
||||
struct element {
|
||||
char text[100];
|
||||
int ele_nr;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
static LIST_HEAD (my_list);
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
int i;
|
||||
pr_info ("Linux module 04 skeleton loaded\n");
|
||||
pr_info (" text: %s\n elements: %d\n", text, elements);
|
||||
for (i = 0; i < elements; i++) {
|
||||
struct element* ele = kzalloc (sizeof(*ele), GFP_KERNEL);
|
||||
if (ele != 0) {
|
||||
strncpy (ele->text, text, 99);
|
||||
ele->ele_nr = i;
|
||||
list_add_tail (&ele->node, &my_list);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
struct element* ele;
|
||||
int nb_eles = 0;
|
||||
list_for_each_entry (ele, &my_list, node) {
|
||||
pr_info ("ele [%d/%d/%d] = %s\n", nb_eles, ele->ele_nr, elements, ele->text);
|
||||
nb_eles++;
|
||||
}
|
||||
while (!list_empty (&my_list)) {
|
||||
ele = list_entry (my_list.next, struct element, node);
|
||||
list_del (&ele->node);
|
||||
kfree (ele);
|
||||
}
|
||||
pr_info ("All elements (%d/%d) of the list have been removed and deleted!\n", nb_eles, elements);
|
||||
pr_info ("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init (skeleton_init);
|
||||
module_exit (skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR ("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION ("Module skeleton");
|
||||
MODULE_LICENSE ("GPL");
|
||||
|
||||
22
src/02_modules/exercice05/Makefile
Normal file
22
src/02_modules/exercice05/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
83
src/02_modules/exercice05/skeleton.c
Normal file
83
src/02_modules/exercice05/skeleton.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
|
||||
#include <linux/moduleparam.h> /* needed for module parameters */
|
||||
|
||||
#include <linux/slab.h> /* needed for dynamic memory allocation */
|
||||
#include <linux/list.h> /* needed for linked list processing */
|
||||
#include <linux/string.h> /* needed for string handling */
|
||||
|
||||
#include <linux/ioport.h> /* needed for memory region handling */
|
||||
#include <linux/io.h> /* needed for mmio handling */
|
||||
|
||||
|
||||
static struct resource* res[3]={[0]=0,};
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
unsigned char* regs[3]={[0]=0,};
|
||||
unsigned int chipid[4]={[0]=0,};
|
||||
long temp = 0;
|
||||
unsigned int addr[2] = {[0]=0,};
|
||||
|
||||
pr_info ("Linux module 05 skeleton loaded\n");
|
||||
|
||||
res[0] = request_mem_region (0x01c14000, 0x1000, "allwiner h5 sid");
|
||||
//res[1] = request_mem_region (0x01C25000, 0x1000, "allwiner h5 ths");
|
||||
//res[2] = request_mem_region (0x01C30000, 0x1000, "allwiner h5 emac");
|
||||
if ((res[0] == 0))// || (res[1] == 0) ||(res[2] == 0))
|
||||
pr_info ("Error while reserving memory region... [0]=%d, [1]=%d, [2]=%d\n", res[0]==0, res[1]==0, res[2]==0);
|
||||
|
||||
regs[0] = ioremap (0x01c14000, 0x1000);
|
||||
regs[1] = ioremap (0x01C25000, 0x1000);
|
||||
regs[2] = ioremap (0x01C30000, 0x1000);
|
||||
|
||||
if ((regs[0] == 0) || (regs[1] == 0) ||(regs[2] == 0)) {
|
||||
pr_info ("Error while trying to map processor register...\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
chipid[0] = ioread32 (regs[0]+0x200);
|
||||
chipid[1] = ioread32 (regs[0]+0x204);
|
||||
chipid[2] = ioread32 (regs[0]+0x208);
|
||||
chipid[3] = ioread32 (regs[0]+0x20c);
|
||||
pr_info("chipid=%08x'%08x'%08x'%08x\n",
|
||||
chipid[0], chipid[1], chipid[2], chipid[3]);
|
||||
|
||||
temp = -1191 * (int)ioread32(regs[1]+0x80) / 10 + 223000;
|
||||
pr_info ("temperature=%ld (%d)\n", temp, ioread32(regs[1]+0x80));
|
||||
|
||||
addr[0]=ioread32(regs[2]+0x50);
|
||||
addr[1]=ioread32(regs[2]+0x54);
|
||||
pr_info("mac-addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
(addr[1]>> 0) & 0xff,
|
||||
(addr[1]>> 8) & 0xff,
|
||||
(addr[1]>>16) & 0xff,
|
||||
(addr[1]>>24) & 0xff,
|
||||
(addr[0]>> 0) & 0xff,
|
||||
(addr[0]>> 8) & 0xff
|
||||
);
|
||||
|
||||
iounmap (regs[0]);
|
||||
iounmap (regs[1]);
|
||||
iounmap (regs[2]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
pr_info ("Linux module skeleton unloaded\n");
|
||||
if (res[0] != 0) release_mem_region (0x01c14000, 0x1000);
|
||||
//release_mem_region (0x01C25000, 0x1000);
|
||||
//release_mem_region (0x01C30000, 0x1000);
|
||||
}
|
||||
|
||||
module_init (skeleton_init);
|
||||
module_exit (skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR ("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION ("Module skeleton");
|
||||
MODULE_LICENSE ("GPL");
|
||||
|
||||
22
src/02_modules/exercice06/Makefile
Normal file
22
src/02_modules/exercice06/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
55
src/02_modules/exercice06/skeleton.c
Normal file
55
src/02_modules/exercice06/skeleton.c
Normal file
@@ -0,0 +1,55 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
|
||||
#include <linux/moduleparam.h> /* needed for module parameters */
|
||||
|
||||
#include <linux/slab.h> /* needed for dynamic memory allocation */
|
||||
#include <linux/list.h> /* needed for linked list processing */
|
||||
#include <linux/string.h> /* needed for string handling */
|
||||
|
||||
#include <linux/ioport.h> /* needed for memory region handling */
|
||||
#include <linux/io.h> /* needed for mmio handling */
|
||||
|
||||
#include <linux/kthread.h> /* needed for kernel thread management */
|
||||
#include <linux/delay.h> /* needed for delay fonctions */
|
||||
|
||||
|
||||
static struct task_struct* my_thread;
|
||||
|
||||
|
||||
static int skeleton_thread (void* data)
|
||||
{
|
||||
pr_info ("skeleton thread is now active...\n");
|
||||
while(!kthread_should_stop()) {
|
||||
ssleep (5);
|
||||
pr_info ("skeleton thread is kick every 5 seconds...\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
pr_info ("Linux module 06 skeleton loaded\n");
|
||||
|
||||
my_thread = kthread_run (skeleton_thread, 0, "s/thread");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
kthread_stop (my_thread);
|
||||
|
||||
pr_info ("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init (skeleton_init);
|
||||
module_exit (skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR ("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION ("Module skeleton");
|
||||
MODULE_LICENSE ("GPL");
|
||||
|
||||
22
src/02_modules/exercice07/Makefile
Normal file
22
src/02_modules/exercice07/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
81
src/02_modules/exercice07/skeleton.c
Normal file
81
src/02_modules/exercice07/skeleton.c
Normal file
@@ -0,0 +1,81 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
|
||||
#include <linux/kthread.h> /* needed for kernel thread management */
|
||||
#include <linux/wait.h> /* needed for waitqueues handling */
|
||||
#include <linux/delay.h> /* needed for delay fonctions */
|
||||
|
||||
|
||||
static struct task_struct* my_thread[2];
|
||||
|
||||
DECLARE_WAIT_QUEUE_HEAD (queue_1);
|
||||
static atomic_t is_kicked;
|
||||
|
||||
static int skeleton_thread_1 (void* data)
|
||||
{
|
||||
pr_info ("skeleton thread_1 is now active...\n");
|
||||
while(!kthread_should_stop()) {
|
||||
int status = wait_event_interruptible
|
||||
(queue_1, (atomic_read(&is_kicked) != 0)
|
||||
|| kthread_should_stop());
|
||||
if (status == -ERESTARTSYS) {
|
||||
pr_info ("skeleton thread_1 has been interrupted\n");
|
||||
break;
|
||||
}
|
||||
atomic_dec (&is_kicked);
|
||||
pr_info ("skeleton thread_1 has been kicked\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skeleton_thread_2 (void* data)
|
||||
{
|
||||
wait_queue_head_t queue;
|
||||
pr_info ("skeleton thread_2 is now active...\n");
|
||||
init_waitqueue_head (&queue);
|
||||
while(!kthread_should_stop()) {
|
||||
ssleep(5);
|
||||
/*
|
||||
int status = wait_event_interruptible_timeout
|
||||
(queue, kthread_should_stop(), 5*HZ);
|
||||
if (status == -ERESTARTSYS) {
|
||||
pr_info ("skeleton thread_2 has been interrupted\n");
|
||||
break;
|
||||
}
|
||||
*/
|
||||
pr_info ("skeleton thread_2 timout elapsed...\n");
|
||||
atomic_set (&is_kicked, 1);
|
||||
wake_up_interruptible (&queue_1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
pr_info ("Linux module 07 skeleton loaded\n");
|
||||
|
||||
atomic_set (&is_kicked, 0);
|
||||
my_thread[0] = kthread_run (skeleton_thread_1, 0, "s/thread/%d", 1);
|
||||
my_thread[1] = kthread_run (skeleton_thread_2, 0, "s/thread/2");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
kthread_stop (my_thread[1]);
|
||||
kthread_stop (my_thread[0]);
|
||||
|
||||
pr_info ("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init (skeleton_init);
|
||||
module_exit (skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR ("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION ("Module skeleton");
|
||||
MODULE_LICENSE ("GPL");
|
||||
|
||||
22
src/02_modules/exercice08/Makefile
Normal file
22
src/02_modules/exercice08/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
74
src/02_modules/exercice08/skeleton.c
Normal file
74
src/02_modules/exercice08/skeleton.c
Normal file
@@ -0,0 +1,74 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
|
||||
#include <linux/interrupt.h> /* needed for interrupt handling */
|
||||
#include <linux/gpio.h> /* needed for i/o handling */
|
||||
|
||||
|
||||
#define K1 0
|
||||
#define K2 2
|
||||
#define K3 3
|
||||
|
||||
static char* k1="gpio_a.0-k1";
|
||||
static char* k2="gpio_a.2-k2";
|
||||
static char* k3="gpio_a.3-k3";
|
||||
|
||||
|
||||
irqreturn_t gpio_isr(int irq, void* handle)
|
||||
{
|
||||
pr_info ("interrupt %s raised...\n", (char*)handle);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
// install k1
|
||||
if (status == 0) status = gpio_request (K1, "k1");
|
||||
if (status == 0)
|
||||
status = request_irq(gpio_to_irq(K1), gpio_isr,
|
||||
IRQF_TRIGGER_FALLING | IRQF_SHARED, k1, k1);
|
||||
|
||||
// install k2
|
||||
if (status == 0) status = gpio_request (K2, "k2");
|
||||
if (status == 0)
|
||||
status = request_irq(gpio_to_irq(K2), gpio_isr,
|
||||
IRQF_TRIGGER_FALLING | IRQF_SHARED, k2, k2);
|
||||
|
||||
// install k3
|
||||
if (status == 0) status = gpio_request (K3, "k3");
|
||||
if (status == 0)
|
||||
status = request_irq(gpio_to_irq(K3), gpio_isr,
|
||||
IRQF_TRIGGER_FALLING | IRQF_SHARED, k3, k3);
|
||||
|
||||
pr_info ("Linux module 08 skeleton loaded\n");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
gpio_free(K1);
|
||||
free_irq(gpio_to_irq(K1), k1);
|
||||
|
||||
gpio_free(K2);
|
||||
free_irq(gpio_to_irq(K2), k2);
|
||||
|
||||
gpio_free(K3);
|
||||
free_irq(gpio_to_irq(K3), k3);
|
||||
|
||||
pr_info ("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init (skeleton_init);
|
||||
module_exit (skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR ("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION ("Module skeleton");
|
||||
MODULE_LICENSE ("GPL");
|
||||
|
||||
50
src/02_modules/procstat/Makefile
Normal file
50
src/02_modules/procstat/Makefile
Normal file
@@ -0,0 +1,50 @@
|
||||
EXE=procstat
|
||||
SRCS=$(wildcard *.c)
|
||||
|
||||
ifeq ($(TARGET), host)
|
||||
CC=gcc
|
||||
LD=gcc
|
||||
STRIP=strip
|
||||
CFLAGS=-Wall -Wextra -g -c -O0 -MD -std=c99
|
||||
OBJDIR=.obj/host
|
||||
EXEC=$(EXE)_h
|
||||
|
||||
else
|
||||
TOOLCHAIN_PATH=/buildroot/output/host/usr/bin/
|
||||
TOOLCHAIN=$(TOOLCHAIN_PATH)aarch64-buildroot-linux-gnu-
|
||||
|
||||
CC=$(TOOLCHAIN)gcc
|
||||
LD=$(TOOLCHAIN)gcc
|
||||
STRIP=$(TOOLCHAIN)strip
|
||||
|
||||
CFLAGS+=-pedantic -Wall -Wextra -g -c -mcpu=cortex-a53 -O0 -MD -std=gnu11
|
||||
CPPFLAGS+=-pedantic -Wall -Wextra -g -c -mcpu=cortex-a53 -O0 -MD -std=gnu11
|
||||
|
||||
OBJDIR=.obj/odroid
|
||||
EXEC=$(EXE)
|
||||
endif
|
||||
|
||||
OBJS= $(addprefix $(OBJDIR)/, $(ASRC:.s=.o) $(SRCS:.c=.o))
|
||||
|
||||
all: $(OBJDIR)/ $(EXEC)
|
||||
|
||||
$(EXEC): $(OBJS) $(LINKER_SCRIPT)
|
||||
$(LD) $(OBJS) $(LDFLAGS) -o $@_s
|
||||
$(STRIP) -g -o $@ $@_s
|
||||
|
||||
$(OBJDIR)/%o: %c
|
||||
$(CC) $(CFLAGS) $< -o $@
|
||||
|
||||
$(OBJDIR)/:
|
||||
mkdir -p $(OBJDIR)
|
||||
|
||||
clean:
|
||||
rm -Rf $(OBJDIR) $(EXEC) $(EXEC)_s
|
||||
|
||||
clean_all:
|
||||
rm -Rf .obj $(EXE) $(EXE)_h $(EXE)_s $(EXE)_h_s *~
|
||||
|
||||
|
||||
.PHONY: all clean clean_all
|
||||
|
||||
-include $(OBJS:.o=.d)
|
||||
240
src/02_modules/procstat/procstat.c
Normal file
240
src/02_modules/procstat/procstat.c
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Displays linux /proc/pid/stat in human-readable format
|
||||
*
|
||||
* Build: gcc -o procstat procstat.c
|
||||
* Usage: procstat pid
|
||||
* cat /proc/pid/stat | procstat
|
||||
*
|
||||
* Homepage: http://www.brokestream.com/procstat.html
|
||||
* Version : 2009-03-05
|
||||
*
|
||||
* Ivan Tikhonov, http://www.brokestream.com, kefeer@netangels.ru
|
||||
*
|
||||
* 2007-09-19 changed HZ=100 error to warning
|
||||
*
|
||||
* 2009-03-05 tickspersec are taken from sysconf (Sabuj Pattanayek)
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* Copyright (C) 2009 Ivan Tikhonov
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Ivan Tikhonov, kefeer@brokestream.com
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <linux/limits.h>
|
||||
#include <sys/times.h>
|
||||
|
||||
|
||||
typedef long long int num;
|
||||
|
||||
num pid;
|
||||
char tcomm[PATH_MAX];
|
||||
char state;
|
||||
|
||||
num ppid;
|
||||
num pgid;
|
||||
num sid;
|
||||
num tty_nr;
|
||||
num tty_pgrp;
|
||||
|
||||
num flags;
|
||||
num min_flt;
|
||||
num cmin_flt;
|
||||
num maj_flt;
|
||||
num cmaj_flt;
|
||||
num utime;
|
||||
num stimev;
|
||||
|
||||
num cutime;
|
||||
num cstime;
|
||||
num priority;
|
||||
num nicev;
|
||||
num num_threads;
|
||||
num it_real_value;
|
||||
|
||||
unsigned long long start_time;
|
||||
|
||||
num vsize;
|
||||
num rss;
|
||||
num rsslim;
|
||||
num start_code;
|
||||
num end_code;
|
||||
num start_stack;
|
||||
num esp;
|
||||
num eip;
|
||||
|
||||
num pending;
|
||||
num blocked;
|
||||
num sigign;
|
||||
num sigcatch;
|
||||
num wchan;
|
||||
num zero1;
|
||||
num zero2;
|
||||
num exit_signal;
|
||||
num cpu;
|
||||
num rt_priority;
|
||||
num policy;
|
||||
|
||||
long tickspersec;
|
||||
|
||||
FILE *input;
|
||||
|
||||
void readone(num *x) { fscanf(input, "%lld ", x); }
|
||||
void readunsigned(unsigned long long *x) { fscanf(input, "%llu ", x); }
|
||||
void readstr(char *x) { fscanf(input, "%s ", x);}
|
||||
void readchar(char *x) { fscanf(input, "%c ", x);}
|
||||
|
||||
void printone(char *name, num x) { printf("%20s: %lld\n", name, x);}
|
||||
void printonex(char *name, num x) { printf("%20s: %016llx\n", name, x);}
|
||||
void printunsigned(char *name, unsigned long long x) { printf("%20s: %llu\n", name, x);}
|
||||
void printchar(char *name, char x) { printf("%20s: %c\n", name, x);}
|
||||
void printstr(char *name, char *x) { printf("%20s: %s\n", name, x);}
|
||||
void printtime(char *name, num x) { printf("%20s: %f\n", name, (((double)x) / tickspersec));}
|
||||
|
||||
int gettimesinceboot() {
|
||||
FILE *procuptime;
|
||||
int sec, ssec;
|
||||
|
||||
procuptime = fopen("/proc/uptime", "r");
|
||||
fscanf(procuptime, "%d.%ds", &sec, &ssec);
|
||||
fclose(procuptime);
|
||||
return (sec*tickspersec)+ssec;
|
||||
}
|
||||
|
||||
void printtimediff(char *name, num x) {
|
||||
int sinceboot = gettimesinceboot();
|
||||
int running = sinceboot - x;
|
||||
time_t rt = time(NULL) - (running / tickspersec);
|
||||
char buf[1024];
|
||||
|
||||
strftime(buf, sizeof(buf), "%m.%d %H:%M", localtime(&rt));
|
||||
printf("%20s: %s (%lu.%lus)\n", name, buf, running / tickspersec, running % tickspersec);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
tickspersec = sysconf(_SC_CLK_TCK);
|
||||
input = NULL;
|
||||
|
||||
if(argc > 1) {
|
||||
chdir("/proc");
|
||||
if(chdir(argv[1]) == 0) { input = fopen("stat", "r"); }
|
||||
if(!input) {
|
||||
perror("open");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
input = stdin;
|
||||
}
|
||||
|
||||
|
||||
readone(&pid);
|
||||
readstr(tcomm);
|
||||
readchar(&state);
|
||||
readone(&ppid);
|
||||
readone(&pgid);
|
||||
readone(&sid);
|
||||
readone(&tty_nr);
|
||||
readone(&tty_pgrp);
|
||||
readone(&flags);
|
||||
readone(&min_flt);
|
||||
readone(&cmin_flt);
|
||||
readone(&maj_flt);
|
||||
readone(&cmaj_flt);
|
||||
readone(&utime);
|
||||
readone(&stimev);
|
||||
readone(&cutime);
|
||||
readone(&cstime);
|
||||
readone(&priority);
|
||||
readone(&nicev);
|
||||
readone(&num_threads);
|
||||
readone(&it_real_value);
|
||||
readunsigned(&start_time);
|
||||
readone(&vsize);
|
||||
readone(&rss);
|
||||
readone(&rsslim);
|
||||
readone(&start_code);
|
||||
readone(&end_code);
|
||||
readone(&start_stack);
|
||||
readone(&esp);
|
||||
readone(&eip);
|
||||
readone(&pending);
|
||||
readone(&blocked);
|
||||
readone(&sigign);
|
||||
readone(&sigcatch);
|
||||
readone(&wchan);
|
||||
readone(&zero1);
|
||||
readone(&zero2);
|
||||
readone(&exit_signal);
|
||||
readone(&cpu);
|
||||
readone(&rt_priority);
|
||||
readone(&policy);
|
||||
|
||||
{
|
||||
|
||||
printone("pid", pid);
|
||||
printstr("tcomm", tcomm);
|
||||
printchar("state", state);
|
||||
printone("ppid", ppid);
|
||||
printone("pgid", pgid);
|
||||
printone("sid", sid);
|
||||
printone("tty_nr", tty_nr);
|
||||
printone("tty_pgrp", tty_pgrp);
|
||||
printone("flags", flags);
|
||||
printone("min_flt", min_flt);
|
||||
printone("cmin_flt", cmin_flt);
|
||||
printone("maj_flt", maj_flt);
|
||||
printone("cmaj_flt", cmaj_flt);
|
||||
printtime("utime", utime);
|
||||
printtime("stime", stimev);
|
||||
printtime("cutime", cutime);
|
||||
printtime("cstime", cstime);
|
||||
printone("priority", priority);
|
||||
printone("nice", nicev);
|
||||
printone("num_threads", num_threads);
|
||||
printtime("it_real_value", it_real_value);
|
||||
printtimediff("start_time", start_time);
|
||||
printone("vsize", vsize);
|
||||
printone("rss", rss);
|
||||
printone("rsslim", rsslim);
|
||||
printone("start_code", start_code);
|
||||
printone("end_code", end_code);
|
||||
printone("start_stack", start_stack);
|
||||
printone("esp", esp);
|
||||
printone("eip", eip);
|
||||
printonex("pending", pending);
|
||||
printonex("blocked", blocked);
|
||||
printonex("sigign", sigign);
|
||||
printonex("sigcatch", sigcatch);
|
||||
printone("wchan", wchan);
|
||||
printone("zero1", zero1);
|
||||
printone("zero2", zero2);
|
||||
printonex("exit_signal", exit_signal);
|
||||
printone("cpu", cpu);
|
||||
printone("rt_priority", rt_priority);
|
||||
printone("policy", policy);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
5
src/03_drivers/Makefile
Normal file
5
src/03_drivers/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
DIRS=$(filter-out Makefile, $(wildcard *))
|
||||
|
||||
all clean install:
|
||||
for dir in $(DIRS); do $(MAKE) $@ -C $$dir; done
|
||||
|
||||
37
src/03_drivers/dts/Makefile
Normal file
37
src/03_drivers/dts/Makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
ccflags-y += -Wno-declaration-after-statement -std=gnu11
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
INCL+=-I. -I$(KDIR)/include -I$(KDIR)/arch/arm64/boot/dts
|
||||
DTB = mydt.dtb
|
||||
DTS = $(DTB:.dtb=.dts)
|
||||
|
||||
all: dtb boot
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
dtb: $(DTB)
|
||||
$(DTB) : $(DTS)
|
||||
ln -s $(KDIR)/arch/arm/boot/dts arm
|
||||
-cpp $(INCL) -E -P -x assembler-with-cpp $(DTS) | dtc -I dts -O dtb -o $(DTB) -
|
||||
rm arm
|
||||
|
||||
boot:
|
||||
mkimage -T script -A arm -C none -d boot.cmd boot.ovl
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
rm -f *.dtb *.ovl
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
10
src/03_drivers/dts/boot.cmd
Normal file
10
src/03_drivers/dts/boot.cmd
Normal file
@@ -0,0 +1,10 @@
|
||||
setenv bootargs console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait
|
||||
|
||||
fatload mmc 0 $kernel_addr_r Image
|
||||
#fatload mmc 0 $fdt_addr_r nanopi-neo-plus2.dtb
|
||||
fatload mmc 0 $fdt_addr_r mydt.dtb
|
||||
|
||||
fdt addr $fdt_addr_r
|
||||
fdt resize
|
||||
|
||||
booti $kernel_addr_r - $fdt_addr_r
|
||||
12
src/03_drivers/dts/mydt.dts
Normal file
12
src/03_drivers/dts/mydt.dts
Normal file
@@ -0,0 +1,12 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include "allwinner/sun50i-h5-nanopi-neo-plus2.dts"
|
||||
|
||||
/ {
|
||||
/delete-node/ leds;
|
||||
|
||||
mydevice {
|
||||
compatible = "mydevice";
|
||||
attribute = "text";
|
||||
};
|
||||
};
|
||||
135
src/03_drivers/dts/skeleton.c
Normal file
135
src/03_drivers/dts/skeleton.c
Normal file
@@ -0,0 +1,135 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
|
||||
#include <linux/cdev.h> /* needed for char device driver */
|
||||
#include <linux/fs.h> /* needed for device drivers */
|
||||
#include <linux/uaccess.h> /* needed to copy data to/from user */
|
||||
|
||||
#include <linux/device.h> /* needed for sysfs handling */
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h> /* needed for sysfs handling */
|
||||
|
||||
static int skeleton_open(struct inode* i, struct file* f)
|
||||
{
|
||||
pr_info("skeleton : open operation... major:%d, minor:%d\n",
|
||||
imajor(i),
|
||||
iminor(i));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skeleton_release(struct inode* i, struct file* f)
|
||||
{
|
||||
pr_info("skeleton: release operation...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_read(struct file* f,
|
||||
char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
pr_info("skeleton: read operation... read=%ld\n", count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_write(struct file* f,
|
||||
const char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
pr_info("skeleton: write operation... written=%ld\n", count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct file_operations fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = skeleton_open,
|
||||
.read = skeleton_read,
|
||||
.write = skeleton_write,
|
||||
.release = skeleton_release,
|
||||
};
|
||||
|
||||
struct miscdevice misc_device = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.fops = &fops,
|
||||
.name = "mydevice",
|
||||
.mode = 0777,
|
||||
};
|
||||
|
||||
int skeleton_probe(struct platform_device* pdev)
|
||||
{
|
||||
pr_info("skeleton - driver probe %llx (%s)- M.m=%d.%d\n",
|
||||
(unsigned long long)pdev,
|
||||
pdev->name,
|
||||
MAJOR(pdev->dev.devt),
|
||||
MINOR(pdev->dev.devt));
|
||||
|
||||
// register misc device ...
|
||||
int ret = misc_register(&misc_device);
|
||||
|
||||
// read device tree attribute
|
||||
struct device_node* dt_node = pdev->dev.of_node;
|
||||
const char* prop = 0;
|
||||
if (dt_node)
|
||||
ret = of_property_read_string(dt_node, "attribute", &prop);
|
||||
else
|
||||
pr_info("mymodule not found!\n");
|
||||
if ((prop != 0) && (ret == 0))
|
||||
pr_info("attribute=%s (ret=%d)\n", prop, ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
int skeleton_remove(struct platform_device* pdev)
|
||||
{
|
||||
pr_info("skeleton - sysfs driver remove %llx\n", (unsigned long long)pdev);
|
||||
misc_deregister(&misc_device);
|
||||
return 0;
|
||||
}
|
||||
void skeleton_shutdown(struct platform_device* pdev)
|
||||
{
|
||||
pr_info("skeleton - sysfs driver shutdown %s\n", pdev->name);
|
||||
}
|
||||
|
||||
struct of_device_id of_skeleton[] = {
|
||||
{
|
||||
.compatible = "mydevice",
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_skeleton);
|
||||
|
||||
static struct platform_driver sysfs_driver = {
|
||||
.probe = skeleton_probe,
|
||||
.remove = skeleton_remove,
|
||||
.shutdown = skeleton_shutdown,
|
||||
.driver =
|
||||
{
|
||||
.name = "mydriver",
|
||||
.of_match_table = of_match_ptr(of_skeleton),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
pr_info("Linux module skeleton loading...\n");
|
||||
int status = platform_driver_register(&sysfs_driver);
|
||||
pr_info("Linux module skeleton loaded\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
pr_info("Linux module skeleton exiting...\n");
|
||||
platform_driver_unregister(&sysfs_driver);
|
||||
pr_info("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init(skeleton_init);
|
||||
module_exit(skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION("Module skeleton");
|
||||
MODULE_LICENSE("GPL");
|
||||
44
src/03_drivers/exercice01/Makefile
Normal file
44
src/03_drivers/exercice01/Makefile
Normal file
@@ -0,0 +1,44 @@
|
||||
EXE=app
|
||||
SRCS=$(wildcard *.c)
|
||||
|
||||
ifeq ($(target),)
|
||||
target=nano
|
||||
endif
|
||||
|
||||
CFLAGS=-Wall -Wextra -g -c -O0 -MD -std=gnu11
|
||||
|
||||
TOOLCHAIN_PATH=/buildroot/output/host/usr/bin/
|
||||
TOOLCHAIN=$(TOOLCHAIN_PATH)aarch64-linux-
|
||||
CFLAGS+=-mcpu=cortex-a53 -funwind-tables
|
||||
##CFLAGS+=-O2 -fno-omit-frame-pointer
|
||||
OBJDIR=.obj/nano
|
||||
EXEC=$(EXE)
|
||||
|
||||
CC=$(TOOLCHAIN)gcc
|
||||
LD=$(TOOLCHAIN)gcc
|
||||
AR=$(TOOLCHAIN)ar
|
||||
STRIP=$(TOOLCHAIN)strip
|
||||
|
||||
OBJDIR=.obj/$(target)
|
||||
OBJS= $(addprefix $(OBJDIR)/, $(SRCS:.c=.o))
|
||||
|
||||
$(OBJDIR)/%o: %c
|
||||
$(CC) $(CFLAGS) $< -o $@
|
||||
|
||||
all: $(OBJDIR)/ $(EXEC)
|
||||
|
||||
$(EXEC): $(OBJS) $(LINKER_SCRIPT)
|
||||
$(LD) $(OBJS) $(LDFLAGS) -o $@
|
||||
|
||||
$(OBJDIR)/:
|
||||
mkdir -p $(OBJDIR)
|
||||
|
||||
clean:
|
||||
rm -Rf $(OBJDIR) $(EXEC) $(EXEC)_s *~
|
||||
|
||||
clean_all: clean
|
||||
rm -Rf .obj $(EXE) $(EXE)_s $(EXE)_a $(EXE)_a_s $(EXE)_h $(EXE)_h_s
|
||||
|
||||
-include $(OBJS:.o=.d)
|
||||
|
||||
.PHONY: all clean clean_all
|
||||
53
src/03_drivers/exercice01/main.c
Normal file
53
src/03_drivers/exercice01/main.c
Normal file
@@ -0,0 +1,53 @@
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
/* open memory file descriptor */
|
||||
int fd = open("/dev/mem", O_RDWR);
|
||||
if (fd < 0) {
|
||||
printf("Could not open /dev/mem: error=%i\n", fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t psz = getpagesize();
|
||||
off_t dev_addr = 0x01c14200;
|
||||
off_t ofs = dev_addr % psz;
|
||||
off_t offset = dev_addr - ofs;
|
||||
printf(
|
||||
"psz=%lx, addr=%lx, offset=%lx, ofs=%lx\n", psz, dev_addr, offset, ofs);
|
||||
|
||||
/* map to user space nanopi internal registers */
|
||||
volatile uint32_t* regs =
|
||||
mmap(0, psz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
|
||||
|
||||
if (regs == MAP_FAILED) // (void *)-1
|
||||
{
|
||||
printf("mmap failed, error: %i:%s \n", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t chipid[4] = {
|
||||
[0] = *(regs + (ofs + 0x00) / sizeof(uint32_t)),
|
||||
[1] = *(regs + (ofs + 0x04) / sizeof(uint32_t)),
|
||||
[2] = *(regs + (ofs + 0x08) / sizeof(uint32_t)),
|
||||
[3] = *(regs + (ofs + 0x0c) / sizeof(uint32_t)),
|
||||
};
|
||||
|
||||
printf("NanoPi NEO Plus2 chipid=%08x'%08x'%08x'%08x\n",
|
||||
chipid[0],
|
||||
chipid[1],
|
||||
chipid[2],
|
||||
chipid[3]);
|
||||
|
||||
munmap((void*)regs, psz);
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/03_drivers/exercice02/Makefile
Normal file
23
src/03_drivers/exercice02/Makefile
Normal file
@@ -0,0 +1,23 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../buildroot_path
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
123
src/03_drivers/exercice02/skeleton.c
Normal file
123
src/03_drivers/exercice02/skeleton.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/cdev.h> /* needed for char device driver */
|
||||
#include <linux/fs.h> /* needed for device drivers */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
#include <linux/moduleparam.h> /* needed for module parameters */
|
||||
#include <linux/uaccess.h> /* needed to copy data to/from user */
|
||||
|
||||
#define BUFFER_SZ 10000
|
||||
|
||||
static char s_buffer[BUFFER_SZ];
|
||||
static dev_t skeleton_dev;
|
||||
static struct cdev skeleton_cdev;
|
||||
|
||||
static int skeleton_open(struct inode* i, struct file* f)
|
||||
{
|
||||
pr_info("skeleton : open operation... major:%d, minor:%d\n",
|
||||
imajor(i),
|
||||
iminor(i));
|
||||
|
||||
if ((f->f_flags & (O_APPEND)) != 0) {
|
||||
pr_info("skeleton : opened for appending...\n");
|
||||
}
|
||||
|
||||
if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) != 0) {
|
||||
pr_info("skeleton : opened for reading & writing...\n");
|
||||
} else if ((f->f_mode & FMODE_READ) != 0) {
|
||||
pr_info("skeleton : opened for reading...\n");
|
||||
} else if ((f->f_mode & FMODE_WRITE) != 0) {
|
||||
pr_info("skeleton : opened for writing...\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skeleton_release(struct inode* i, struct file* f)
|
||||
{
|
||||
pr_info("skeleton: release operation...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_read(struct file* f,
|
||||
char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
// compute remaining bytes to copy, update count and pointers
|
||||
ssize_t remaining = BUFFER_SZ - (ssize_t)(*off);
|
||||
char* ptr = s_buffer + *off;
|
||||
if (count > remaining) count = remaining;
|
||||
*off += count;
|
||||
|
||||
// copy required number of bytes
|
||||
if (copy_to_user(buf, ptr, count) != 0) count = -EFAULT;
|
||||
|
||||
pr_info("skeleton: read operation... read=%ld\n", count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_write(struct file* f,
|
||||
const char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
// compute remaining space in buffer and update pointers
|
||||
ssize_t remaining = BUFFER_SZ - (ssize_t)(*off);
|
||||
|
||||
pr_info("skeleton: at%ld\n", (unsigned long)(*off));
|
||||
|
||||
// check if still remaining space to store additional bytes
|
||||
if (count >= remaining) count = -EIO;
|
||||
|
||||
// store additional bytes into internal buffer
|
||||
if (count > 0) {
|
||||
char* ptr = s_buffer + *off;
|
||||
*off += count;
|
||||
ptr[count] = 0; // make sure string is null terminated
|
||||
if (copy_from_user(ptr, buf, count)) count = -EFAULT;
|
||||
}
|
||||
|
||||
pr_info("skeleton: write operation... written=%ld\n", count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct file_operations skeleton_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = skeleton_open,
|
||||
.read = skeleton_read,
|
||||
.write = skeleton_write,
|
||||
.release = skeleton_release,
|
||||
};
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
int status = alloc_chrdev_region(&skeleton_dev, 0, 1, "mymodule");
|
||||
if (status == 0) {
|
||||
cdev_init(&skeleton_cdev, &skeleton_fops);
|
||||
skeleton_cdev.owner = THIS_MODULE;
|
||||
status = cdev_add(&skeleton_cdev, skeleton_dev, 1);
|
||||
}
|
||||
|
||||
pr_info("Linux module skeleton loaded\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
cdev_del(&skeleton_cdev);
|
||||
unregister_chrdev_region(skeleton_dev, 1);
|
||||
|
||||
pr_info("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init(skeleton_init);
|
||||
module_exit(skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION("Module skeleton");
|
||||
MODULE_LICENSE("GPL");
|
||||
23
src/03_drivers/exercice03/Makefile
Normal file
23
src/03_drivers/exercice03/Makefile
Normal file
@@ -0,0 +1,23 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../buildroot_path
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
147
src/03_drivers/exercice03/skeleton.c
Normal file
147
src/03_drivers/exercice03/skeleton.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/cdev.h> /* needed for char device driver */
|
||||
#include <linux/fs.h> /* needed for device drivers */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
#include <linux/moduleparam.h> /* needed for module parameters */
|
||||
#include <linux/slab.h> /* needed for dynamic memory management */
|
||||
#include <linux/uaccess.h> /* needed to copy data to/from user */
|
||||
|
||||
static int instances = 3;
|
||||
module_param(instances, int, 0);
|
||||
|
||||
#define BUFFER_SZ 10000
|
||||
static char** buffers = 0;
|
||||
|
||||
static int skeleton_open(struct inode* i, struct file* f)
|
||||
{
|
||||
pr_info("skeleton : open operation... major:%d, minor:%d\n",
|
||||
imajor(i),
|
||||
iminor(i));
|
||||
|
||||
if (iminor(i) >= instances) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) != 0) {
|
||||
pr_info("skeleton : opened for reading & writing...\n");
|
||||
} else if ((f->f_mode & FMODE_READ) != 0) {
|
||||
pr_info("skeleton : opened for reading...\n");
|
||||
} else if ((f->f_mode & FMODE_WRITE) != 0) {
|
||||
pr_info("skeleton : opened for writing...\n");
|
||||
}
|
||||
|
||||
f->private_data = buffers[iminor(i)];
|
||||
pr_info("skeleton: private_data=%p\n", f->private_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skeleton_release(struct inode* i, struct file* f)
|
||||
{
|
||||
pr_info("skeleton: release operation...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_read(struct file* f,
|
||||
char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
// compute remaining bytes to copy, update count and pointers
|
||||
ssize_t remaining = BUFFER_SZ - (ssize_t)(*off);
|
||||
char* ptr = (char*)f->private_data + *off;
|
||||
if (count > remaining) count = remaining;
|
||||
*off += count;
|
||||
|
||||
// copy required number of bytes
|
||||
if (copy_to_user(buf, ptr, count) != 0) count = -EFAULT;
|
||||
|
||||
pr_info("skeleton: read operation... read=%ld\n", count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_write(struct file* f,
|
||||
const char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
// compute remaining space in buffer and update pointers
|
||||
ssize_t remaining = BUFFER_SZ - (ssize_t)(*off);
|
||||
|
||||
// check if still remaining space to store additional bytes
|
||||
if (count >= remaining) count = -EIO;
|
||||
|
||||
// store additional bytes into internal buffer
|
||||
if (count > 0) {
|
||||
char* ptr = f->private_data + *off;
|
||||
*off += count;
|
||||
ptr[count] = 0; // make sure string is null terminated
|
||||
if (copy_from_user(ptr, buf, count)) count = -EFAULT;
|
||||
}
|
||||
|
||||
pr_info("skeleton: write operation... private_data=%p, written=%ld\n",
|
||||
f->private_data,
|
||||
count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct file_operations skeleton_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = skeleton_open,
|
||||
.read = skeleton_read,
|
||||
.write = skeleton_write,
|
||||
.release = skeleton_release,
|
||||
};
|
||||
|
||||
static dev_t skeleton_dev;
|
||||
static struct cdev skeleton_cdev;
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
int i;
|
||||
int status = -EFAULT;
|
||||
|
||||
if (instances <= 0) return -EFAULT;
|
||||
|
||||
status = alloc_chrdev_region(&skeleton_dev, 0, instances, "mymodule");
|
||||
if (status == 0) {
|
||||
cdev_init(&skeleton_cdev, &skeleton_fops);
|
||||
skeleton_cdev.owner = THIS_MODULE;
|
||||
status = cdev_add(&skeleton_cdev, skeleton_dev, instances);
|
||||
}
|
||||
|
||||
if (status == 0) {
|
||||
buffers = kzalloc(sizeof(char*) * instances, GFP_KERNEL);
|
||||
for (i = 0; i < instances; i++)
|
||||
buffers[i] = kzalloc(BUFFER_SZ, GFP_KERNEL);
|
||||
}
|
||||
|
||||
pr_info("Linux module skeleton loaded\n");
|
||||
pr_info("The number of instances: %d\n", instances);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
cdev_del(&skeleton_cdev);
|
||||
unregister_chrdev_region(skeleton_dev, instances);
|
||||
|
||||
for (i = 0; i < instances; i++) kfree(buffers[i]);
|
||||
kfree(buffers);
|
||||
|
||||
pr_info("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init(skeleton_init);
|
||||
module_exit(skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION("Module skeleton");
|
||||
MODULE_LICENSE("GPL");
|
||||
37
src/03_drivers/exercice04/Makefile
Normal file
37
src/03_drivers/exercice04/Makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
EXEC=app
|
||||
SRCS=$(wildcard *.c)
|
||||
|
||||
TOOLCHAIN_PATH=/buildroot/output/host/usr/bin/
|
||||
TOOLCHAIN=$(TOOLCHAIN_PATH)aarch64-linux-
|
||||
CFLAGS+=-Wall -Wextra -g -c -O0 -MD -std=gnu11
|
||||
CFLAGS+=-mcpu=cortex-a53 -funwind-tables
|
||||
|
||||
OBJDIR=.obj
|
||||
|
||||
CC=$(TOOLCHAIN)gcc
|
||||
LD=$(TOOLCHAIN)gcc
|
||||
AR=$(TOOLCHAIN)ar
|
||||
STRIP=$(TOOLCHAIN)strip
|
||||
OBJS+=$(addprefix $(OBJDIR)/, $(SRCS:.c=.o))
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
$(OBJDIR)/%o: %c
|
||||
$(CC) $(CFLAGS) $< -o $@
|
||||
|
||||
|
||||
all: $(OBJDIR)/ $(EXEC)
|
||||
|
||||
clean: $(EXTRA_CLEAN)
|
||||
rm -Rf .obj
|
||||
rm -Rf $(EXEC) *.map *~
|
||||
|
||||
$(EXEC): $(OBJS) $(LINKER_SCRIPT)
|
||||
$(LD) $(OBJS) $(LDFLAGS) -o $@
|
||||
|
||||
$(OBJDIR)/:
|
||||
mkdir -p $(OBJDIR)
|
||||
|
||||
-include $(OBJS:.o=.d)
|
||||
|
||||
|
||||
47
src/03_drivers/exercice04/main.c
Normal file
47
src/03_drivers/exercice04/main.c
Normal file
@@ -0,0 +1,47 @@
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const char* text =
|
||||
"\n"
|
||||
"bonjour le monde\n"
|
||||
"ce mois d'octobre est plutot humide...\n"
|
||||
"ce n'est qu'un petit texte de test...\n";
|
||||
|
||||
static const char* text2 =
|
||||
"\n"
|
||||
"et voici un complement au premier text..\n"
|
||||
"ce n'est qu'un deuxieme petit texte de test...\n";
|
||||
|
||||
static const char* blabla =
|
||||
"blabla blabla blabla blabla blabla blabla blabla\n";
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc <= 1) return 0;
|
||||
|
||||
int fdw = open(argv[1], O_RDWR);
|
||||
write(fdw, argv[1], strlen(argv[1]));
|
||||
write(fdw, text, strlen(text));
|
||||
write(fdw, text2, strlen(text2));
|
||||
|
||||
int s;
|
||||
do {
|
||||
s = write(fdw, blabla, strlen(blabla));
|
||||
} while (s >= 0);
|
||||
close(fdw);
|
||||
|
||||
int fdr = open(argv[1], O_RDONLY);
|
||||
while (1) {
|
||||
char buff[100];
|
||||
ssize_t sz = read(fdr, buff, sizeof(buff) - 1);
|
||||
if (sz <= 0) break;
|
||||
buff[sizeof(buff) - 1] = 0;
|
||||
printf("%s", buff);
|
||||
}
|
||||
close(fdr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
22
src/03_drivers/exercice05.1/Makefile
Normal file
22
src/03_drivers/exercice05.1/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
249
src/03_drivers/exercice05.1/skeleton.c
Normal file
249
src/03_drivers/exercice05.1/skeleton.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
|
||||
#include <linux/cdev.h> /* needed for char device driver */
|
||||
#include <linux/fs.h> /* needed for device drivers */
|
||||
#include <linux/uaccess.h> /* needed to copy data to/from user */
|
||||
|
||||
#include <linux/device.h> /* needed for sysfs handling */
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/platform_device.h> /* needed for sysfs handling */
|
||||
|
||||
//#define MISC
|
||||
//#define PLATFORM
|
||||
#define CLASS
|
||||
|
||||
struct skeleton_config {
|
||||
int id;
|
||||
long ref;
|
||||
char name[30];
|
||||
char descr[30];
|
||||
};
|
||||
|
||||
static struct skeleton_config config;
|
||||
static int val;
|
||||
|
||||
ssize_t sysfs_show_val(struct device* dev,
|
||||
struct device_attribute* attr,
|
||||
char* buf)
|
||||
{
|
||||
sprintf(buf, "%d\n", val);
|
||||
return strlen(buf);
|
||||
}
|
||||
ssize_t sysfs_store_val(struct device* dev,
|
||||
struct device_attribute* attr,
|
||||
const char* buf,
|
||||
size_t count)
|
||||
{
|
||||
val = simple_strtol(buf, 0, 10);
|
||||
return count;
|
||||
}
|
||||
DEVICE_ATTR(val, 0664, sysfs_show_val, sysfs_store_val);
|
||||
|
||||
ssize_t sysfs_show_cfg(struct device* dev,
|
||||
struct device_attribute* attr,
|
||||
char* buf)
|
||||
{
|
||||
sprintf(buf,
|
||||
"%d %ld %s %s\n",
|
||||
config.id,
|
||||
config.ref,
|
||||
config.name,
|
||||
config.descr);
|
||||
return strlen(buf);
|
||||
}
|
||||
ssize_t sysfs_store_cfg(struct device* dev,
|
||||
struct device_attribute* attr,
|
||||
const char* buf,
|
||||
size_t count)
|
||||
{
|
||||
sscanf(buf,
|
||||
"%d %ld %s %s",
|
||||
&config.id,
|
||||
&config.ref,
|
||||
config.name,
|
||||
config.descr);
|
||||
return count;
|
||||
}
|
||||
DEVICE_ATTR(cfg, 0664, sysfs_show_cfg, sysfs_store_cfg);
|
||||
|
||||
#define BUFFER_SZ 10000
|
||||
|
||||
static char s_buffer[BUFFER_SZ];
|
||||
static dev_t skeleton_dev;
|
||||
static struct cdev skeleton_cdev;
|
||||
|
||||
static int skeleton_open(struct inode* i, struct file* f)
|
||||
{
|
||||
pr_info("skeleton : open operation... major:%d, minor:%d\n",
|
||||
imajor(i),
|
||||
iminor(i));
|
||||
|
||||
if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) != 0) {
|
||||
pr_info("skeleton : opened for reading & writing...\n");
|
||||
} else if ((f->f_mode & FMODE_READ) != 0) {
|
||||
pr_info("skeleton : opened for reading...\n");
|
||||
} else if ((f->f_mode & FMODE_WRITE) != 0) {
|
||||
pr_info("skeleton : opened for writing...\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skeleton_release(struct inode* i, struct file* f)
|
||||
{
|
||||
pr_info("skeleton: release operation...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_read(struct file* f,
|
||||
char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
// compute remaining bytes to copy, update count and pointers
|
||||
ssize_t remaining = BUFFER_SZ - (ssize_t)(*off);
|
||||
char* ptr = s_buffer + *off;
|
||||
if (count > remaining) count = remaining;
|
||||
*off += count;
|
||||
|
||||
// copy required number of bytes
|
||||
if (copy_to_user(buf, ptr, count) != 0) count = -EFAULT;
|
||||
|
||||
pr_info("skeleton: read operation... read=%ld\n", count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_write(struct file* f,
|
||||
const char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
// compute remaining space in buffer and update pointers
|
||||
ssize_t remaining = BUFFER_SZ - (ssize_t)(*off);
|
||||
|
||||
// check if still remaining space to store additional bytes
|
||||
if (count >= remaining) count = -EIO;
|
||||
|
||||
// store additional bytes into internal buffer
|
||||
if (count > 0) {
|
||||
char* ptr = s_buffer + *off;
|
||||
*off += count;
|
||||
ptr[count] = 0; // make sure string is null terminated
|
||||
if (copy_from_user(ptr, buf, count)) count = -EFAULT;
|
||||
}
|
||||
|
||||
pr_info("skeleton: write operation... written=%ld\n", count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct file_operations skeleton_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = skeleton_open,
|
||||
.read = skeleton_read,
|
||||
.write = skeleton_write,
|
||||
.release = skeleton_release,
|
||||
};
|
||||
|
||||
#ifdef MISC
|
||||
static struct miscdevice misc_device = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.fops = &fops
|
||||
.name = "my_misc_module",
|
||||
.mode = 0,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM
|
||||
static void sysfs_dev_release (struct device *dev)
|
||||
{
|
||||
pr_info ("skeleton - sysfs dev release\n");
|
||||
}
|
||||
|
||||
static struct platform_device platform_device = {
|
||||
.name = "my_platform_module",
|
||||
.id = -1,
|
||||
.dev.release = sysfs_dev_release
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CLASS
|
||||
static struct class* sysfs_class;
|
||||
static struct device* sysfs_device;
|
||||
#endif
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
#ifndef MISC
|
||||
status = alloc_chrdev_region(&skeleton_dev, 0, 1, "mymodule");
|
||||
if (status == 0) {
|
||||
cdev_init(&skeleton_cdev, &skeleton_fops);
|
||||
skeleton_cdev.owner = THIS_MODULE;
|
||||
status = cdev_add(&skeleton_cdev, skeleton_dev, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MISC
|
||||
if (status == 0) status = misc_register(&misc_device);
|
||||
if (status == 0) status = device_create_file(misc_device.this_device, &dev_attr_val);
|
||||
if (status == 0) status = device_create_file(misc_device.this_device, &dev_attr_cfg);
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM
|
||||
platform_device.dev.devt = skeleton_dev;
|
||||
if (status == 0) status = platform_device_register (&platform_device);
|
||||
if (status == 0) status = device_create_file (&platform_device.dev, &dev_attr_val);
|
||||
if (status == 0) status = device_create_file (&platform_device.dev, &dev_attr_cfg);
|
||||
#endif
|
||||
|
||||
#ifdef CLASS
|
||||
sysfs_class = class_create(THIS_MODULE, "my_sysfs_class");
|
||||
sysfs_device = device_create(sysfs_class, NULL, skeleton_dev, NULL, "my_sysfs_device");
|
||||
if (status == 0) status = device_create_file(sysfs_device, &dev_attr_val);
|
||||
if (status == 0) status = device_create_file(sysfs_device, &dev_attr_cfg);
|
||||
#endif
|
||||
|
||||
pr_info("Linux module skeleton loaded\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
#ifdef MISC
|
||||
misc_deregister(&misc_device);
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM
|
||||
device_remove_file (&platform_device.dev, &dev_attr_cfg);
|
||||
device_remove_file (&platform_device.dev, &dev_attr_val);
|
||||
platform_device_unregister (&platform_device);
|
||||
#endif
|
||||
|
||||
#ifdef CLASS
|
||||
device_remove_file(sysfs_device, &dev_attr_val);
|
||||
device_remove_file(sysfs_device, &dev_attr_cfg);
|
||||
device_destroy(sysfs_class, 0);
|
||||
class_destroy(sysfs_class);
|
||||
#endif
|
||||
|
||||
#ifndef MISC
|
||||
cdev_del(&skeleton_cdev);
|
||||
unregister_chrdev_region(skeleton_dev, 1);
|
||||
#endif
|
||||
|
||||
pr_info("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init(skeleton_init);
|
||||
module_exit(skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION("Module skeleton");
|
||||
MODULE_LICENSE("GPL");
|
||||
23
src/03_drivers/exercice05/Makefile
Normal file
23
src/03_drivers/exercice05/Makefile
Normal file
@@ -0,0 +1,23 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../buildroot_path
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
153
src/03_drivers/exercice05/skeleton.c
Normal file
153
src/03_drivers/exercice05/skeleton.c
Normal file
@@ -0,0 +1,153 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
|
||||
#include <linux/cdev.h> /* needed for char device driver */
|
||||
#include <linux/fs.h> /* needed for device drivers */
|
||||
#include <linux/uaccess.h> /* needed to copy data to/from user */
|
||||
|
||||
#include <linux/device.h> /* needed for sysfs handling */
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/platform_device.h> /* needed for sysfs handling */
|
||||
|
||||
//#define MISC
|
||||
//#define PLATFORM
|
||||
#define CLASS
|
||||
|
||||
struct skeleton_config {
|
||||
int id;
|
||||
long ref;
|
||||
char name[30];
|
||||
char descr[30];
|
||||
};
|
||||
|
||||
static struct skeleton_config config;
|
||||
static int val;
|
||||
|
||||
ssize_t sysfs_show_val(struct device* dev,
|
||||
struct device_attribute* attr,
|
||||
char* buf)
|
||||
{
|
||||
sprintf(buf, "%d\n", val);
|
||||
return strlen(buf);
|
||||
}
|
||||
ssize_t sysfs_store_val(struct device* dev,
|
||||
struct device_attribute* attr,
|
||||
const char* buf,
|
||||
size_t count)
|
||||
{
|
||||
val = simple_strtol(buf, 0, 10);
|
||||
return count;
|
||||
}
|
||||
DEVICE_ATTR(val, 0664, sysfs_show_val, sysfs_store_val);
|
||||
|
||||
ssize_t sysfs_show_cfg(struct device* dev,
|
||||
struct device_attribute* attr,
|
||||
char* buf)
|
||||
{
|
||||
sprintf(buf,
|
||||
"%d %ld %s %s\n",
|
||||
config.id,
|
||||
config.ref,
|
||||
config.name,
|
||||
config.descr);
|
||||
return strlen(buf);
|
||||
}
|
||||
ssize_t sysfs_store_cfg(struct device* dev,
|
||||
struct device_attribute* attr,
|
||||
const char* buf,
|
||||
size_t count)
|
||||
{
|
||||
sscanf(buf,
|
||||
"%d %ld %s %s",
|
||||
&config.id,
|
||||
&config.ref,
|
||||
config.name,
|
||||
config.descr);
|
||||
return count;
|
||||
}
|
||||
DEVICE_ATTR(cfg, 0664, sysfs_show_cfg, sysfs_store_cfg);
|
||||
|
||||
|
||||
#ifdef MISC
|
||||
static struct miscdevice misc_device = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = "mymodule",
|
||||
.mode = 0,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM
|
||||
static void sysfs_dev_release (struct device *dev)
|
||||
{
|
||||
pr_info ("skeleton - sysfs dev release\n");
|
||||
}
|
||||
|
||||
static struct platform_device platform_device = {
|
||||
.name = "mymodule",
|
||||
.id = -1,
|
||||
.dev.release = sysfs_dev_release
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CLASS
|
||||
static struct class* sysfs_class;
|
||||
static struct device* sysfs_device;
|
||||
#endif
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
#ifdef MISC
|
||||
if (status == 0) status = misc_register(&misc_device);
|
||||
if (status == 0) status = device_create_file(misc_device.this_device, &dev_attr_val);
|
||||
if (status == 0) status = device_create_file(misc_device.this_device, &dev_attr_cfg);
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM
|
||||
if (status == 0) status = platform_device_register (&platform_device);
|
||||
if (status == 0) status = device_create_file (&platform_device.dev, &dev_attr_val);
|
||||
if (status == 0) status = device_create_file (&platform_device.dev, &dev_attr_cfg);
|
||||
#endif
|
||||
|
||||
#ifdef CLASS
|
||||
sysfs_class = class_create(THIS_MODULE, "my_sysfs_class");
|
||||
sysfs_device = device_create(sysfs_class, NULL, 0, NULL, "my_sysfs_device");
|
||||
if (status == 0) status = device_create_file(sysfs_device, &dev_attr_val);
|
||||
if (status == 0) status = device_create_file(sysfs_device, &dev_attr_cfg);
|
||||
#endif
|
||||
|
||||
pr_info("Linux module skeleton loaded\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
#ifdef MISC
|
||||
misc_deregister(&misc_device);
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM
|
||||
device_remove_file (&platform_device.dev, &dev_attr_cfg);
|
||||
device_remove_file (&platform_device.dev, &dev_attr_val);
|
||||
platform_device_unregister (&platform_device);
|
||||
#endif
|
||||
|
||||
#ifdef CLASS
|
||||
device_remove_file(sysfs_device, &dev_attr_val);
|
||||
device_remove_file(sysfs_device, &dev_attr_cfg);
|
||||
device_destroy(sysfs_class, 0);
|
||||
class_destroy(sysfs_class);
|
||||
#endif
|
||||
|
||||
pr_info("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init(skeleton_init);
|
||||
module_exit(skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION("Module skeleton");
|
||||
MODULE_LICENSE("GPL");
|
||||
36
src/03_drivers/exercice06.1/Makefile
Normal file
36
src/03_drivers/exercice06.1/Makefile
Normal file
@@ -0,0 +1,36 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
INCL+=-I. -I$(KDIR)/include -I$(KDIR)/arch/arm64/boot/dts
|
||||
DTB = mydt.dtb
|
||||
DTS = $(DTB:.dtb=.dts)
|
||||
|
||||
all: dtb boot
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
dtb: $(DTB)
|
||||
$(DTB) : $(DTS)
|
||||
ln -s $(KDIR)/arch/arm/boot/dts arm
|
||||
-cpp $(INCL) -E -P -x assembler-with-cpp $(DTS) | dtc -I dts -O dtb -o $(DTB) -
|
||||
rm arm
|
||||
|
||||
boot:
|
||||
mkimage -T script -A arm -C none -d boot.cmd boot.ovl
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
rm -f *.dtb *.ovl
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
13
src/03_drivers/exercice06.1/boot.cmd
Normal file
13
src/03_drivers/exercice06.1/boot.cmd
Normal file
@@ -0,0 +1,13 @@
|
||||
setenv bootargs console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait
|
||||
|
||||
fatload mmc 0 $kernel_addr_r Image
|
||||
#fatload mmc 0 $fdt_addr_r sun50i-h5-nanopi-neo-plus2.dtb
|
||||
fatload mmc 0 $fdt_addr_r mydt.dtb
|
||||
|
||||
fdt addr $fdt_addr_r
|
||||
fdt resize
|
||||
#fdt mknode / mymodule2
|
||||
#fdt set /mymodule2 compatible mymodule2
|
||||
|
||||
|
||||
booti $kernel_addr_r - $fdt_addr_r
|
||||
34
src/03_drivers/exercice06.1/mydt.dts
Normal file
34
src/03_drivers/exercice06.1/mydt.dts
Normal file
@@ -0,0 +1,34 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include "allwinner/sun50i-h5-nanopi-neo-plus2.dts"
|
||||
|
||||
/ {
|
||||
/delete-node/ leds;
|
||||
|
||||
mydevice {
|
||||
compatible = "mydevice";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
attribute = "idle";
|
||||
|
||||
mydevice@0 {
|
||||
reg = <0x0>;
|
||||
attribute = "on";
|
||||
};
|
||||
|
||||
mydevice@1 {
|
||||
reg = <0x1>;
|
||||
attribute = "off";
|
||||
};
|
||||
|
||||
mydevice@2 {
|
||||
reg = <0x2>;
|
||||
attribute = "off";
|
||||
};
|
||||
|
||||
mydevice@3 {
|
||||
reg = <0x3>;
|
||||
attribute = "off";
|
||||
};
|
||||
};
|
||||
};
|
||||
253
src/03_drivers/exercice06.1/skeleton.c
Normal file
253
src/03_drivers/exercice06.1/skeleton.c
Normal file
@@ -0,0 +1,253 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
|
||||
#include <linux/cdev.h> /* needed for char device driver */
|
||||
#include <linux/fs.h> /* needed for device drivers */
|
||||
#include <linux/uaccess.h> /* needed to copy data to/from user */
|
||||
|
||||
#include <linux/list.h> /* needed for linked list processing */
|
||||
#include <linux/device.h> /* needed for sysfs handling */
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h> /* needed for sysfs handling */
|
||||
|
||||
#define BUFFER_SZ 10000
|
||||
struct mydata {
|
||||
char buffer[BUFFER_SZ];
|
||||
struct miscdevice misc;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
static int skeleton_open(struct inode* i, struct file* f)
|
||||
{
|
||||
pr_info("skeleton : open operation... major:%d, minor:%d, p_data=%llx\n",
|
||||
imajor(i),
|
||||
iminor(i),
|
||||
(long long)f->private_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skeleton_release(struct inode* i, struct file* f)
|
||||
{
|
||||
pr_info("skeleton: release operation...p_data=%llx\n",
|
||||
(long long)f->private_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_read(struct file* f,
|
||||
char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
struct mydata* mydata = container_of(f->private_data, struct mydata, misc);
|
||||
|
||||
// compute remaining bytes to copy, update count and pointers
|
||||
ssize_t remaining = strlen(mydata->buffer) - (ssize_t)(*off);
|
||||
char* ptr = mydata->buffer + *off;
|
||||
if (count > remaining) count = remaining;
|
||||
*off += count;
|
||||
|
||||
// copy required number of bytes
|
||||
if (copy_to_user(buf, ptr, count) != 0) count = -EFAULT;
|
||||
|
||||
pr_info("skeleton: read operation...p_data=%llx read=%ld\n",
|
||||
(long long)f->private_data,
|
||||
count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_write(struct file* f,
|
||||
const char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
struct mydata* mydata = container_of(f->private_data, struct mydata, misc);
|
||||
|
||||
// compute remaining space in buffer and update pointers
|
||||
ssize_t remaining = sizeof(mydata->buffer) - (ssize_t)(*off);
|
||||
char* ptr = mydata->buffer + *off;
|
||||
*off += count;
|
||||
|
||||
// check if still remaining space to store additional bytes
|
||||
if (count >= remaining) count = -EIO;
|
||||
|
||||
// store additional bytes into internal buffer
|
||||
if (count > 0) {
|
||||
ptr[count] = 0; // make sure string is null terminated
|
||||
if (copy_from_user(ptr, buf, count)) count = -EFAULT;
|
||||
}
|
||||
|
||||
pr_info("skeleton: write operation... written=%ld\n", count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct file_operations fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = skeleton_open,
|
||||
.read = skeleton_read,
|
||||
.write = skeleton_write,
|
||||
.release = skeleton_release,
|
||||
};
|
||||
|
||||
int drv_probe(struct platform_device* pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct device_node* dt_node = pdev->dev.of_node;
|
||||
struct mydata* mydata = 0;
|
||||
const char* prop_str = 0;
|
||||
|
||||
pr_info("skeleton - driver probe %llx (%s)- M.m=%d.%d, dtnode=%p\n",
|
||||
(unsigned long long)pdev,
|
||||
pdev->name,
|
||||
MAJOR(pdev->dev.devt),
|
||||
MINOR(pdev->dev.devt),
|
||||
dt_node);
|
||||
|
||||
ret = of_property_read_string(dt_node, "attribute", &prop_str);
|
||||
if (prop_str && ret == 0) pr_info("attribute=%s (ret=%d)\n", prop_str, ret);
|
||||
|
||||
if (pdev->num_resources) {
|
||||
pr_info("resources: name=%s, start=%lld, end=%lld\n",
|
||||
pdev->resource[0].name,
|
||||
pdev->resource[0].start,
|
||||
pdev->resource[0].end);
|
||||
}
|
||||
|
||||
if (dt_node) {
|
||||
int ret = 0;
|
||||
const char* prop_str = 0;
|
||||
const unsigned int* prop_reg = 0;
|
||||
struct device_node* child = 0;
|
||||
struct list_head* list = devm_kzalloc(&pdev->dev, sizeof(struct list_head), GFP_KERNEL);
|
||||
if (list == 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to allocate resource for miscdev\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
INIT_LIST_HEAD(list);
|
||||
platform_set_drvdata(pdev, list);
|
||||
|
||||
for_each_available_child_of_node(dt_node, child)
|
||||
{
|
||||
mydata = devm_kzalloc(&pdev->dev, sizeof(*mydata), GFP_KERNEL);
|
||||
pr_info("miscdev=%llx\n", (long long)mydata);
|
||||
if (mydata == 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to allocate resource for miscdev\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
list_add_tail (&(mydata->node), list);
|
||||
|
||||
pr_info("child found: name=%s, fullname=%s\n",
|
||||
child->name,
|
||||
child->full_name);
|
||||
prop_reg = of_get_property(child, "reg", NULL);
|
||||
if (prop_reg != 0) {
|
||||
unsigned long reg = of_read_ulong(prop_reg, 1);
|
||||
pr_info("reg:%lu\n", reg);
|
||||
}
|
||||
|
||||
ret = of_property_read_string(child, "attribute", &prop_str);
|
||||
if (prop_str && ret == 0)
|
||||
pr_info("attribute=%s (ret=%d)\n", prop_str, ret);
|
||||
|
||||
/* register misc device ... */
|
||||
mydata->misc.minor = MISC_DYNAMIC_MINOR;
|
||||
mydata->misc.fops = &fops;
|
||||
mydata->misc.name = child->full_name;
|
||||
mydata->misc.mode = 0664;
|
||||
ret = misc_register(&(mydata->misc));
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to register miscdev\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int drv_remove(struct platform_device* pdev)
|
||||
{
|
||||
struct mydata* mydata;
|
||||
struct list_head* list = platform_get_drvdata(pdev);
|
||||
pr_info("skeleton - sysfs driver remove %s\n", pdev->name);
|
||||
list_for_each_entry (mydata, list, node) {
|
||||
misc_deregister(&(mydata->misc));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void drv_shutdown(struct platform_device* pdev)
|
||||
{
|
||||
pr_info("skeleton - sysfs driver shutdown %s\n", pdev->name);
|
||||
}
|
||||
int drv_suspend(struct platform_device* pdev, pm_message_t state)
|
||||
{
|
||||
pr_info("skeleton - sysfs driver suspend %s (state=%d)\n",
|
||||
pdev->name,
|
||||
state.event);
|
||||
return 0;
|
||||
}
|
||||
int drv_resume(struct platform_device* pdev)
|
||||
{
|
||||
pr_info("skeleton - sysfs driver resume %s\n", pdev->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct of_device_id of_drv[] = {
|
||||
{
|
||||
.compatible = "mydevice",
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_drv);
|
||||
|
||||
static struct platform_driver sysfs_driver = {
|
||||
.probe = drv_probe,
|
||||
.remove = drv_remove,
|
||||
.shutdown = drv_shutdown,
|
||||
.suspend = drv_suspend,
|
||||
.resume = drv_resume,
|
||||
.driver =
|
||||
{
|
||||
.name = "mydriver",
|
||||
.of_match_table = of_match_ptr(of_drv),
|
||||
},
|
||||
};
|
||||
#if 1
|
||||
static int __init sysfs_driver_init(void)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
pr_info("Linux module skeleton loading...\n");
|
||||
|
||||
/* install sysfs */
|
||||
if (status == 0) status = platform_driver_register(&sysfs_driver);
|
||||
|
||||
pr_info("Linux module skeleton loaded\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit sysfs_driver_exit(void)
|
||||
{
|
||||
pr_info("Linux module skeleton exiting...\n");
|
||||
|
||||
/* uninstall sysfs */
|
||||
platform_driver_unregister(&sysfs_driver);
|
||||
|
||||
pr_info("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init(sysfs_driver_init);
|
||||
module_exit(sysfs_driver_exit);
|
||||
|
||||
#else
|
||||
module_platform_driver(sysfs_driver);
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION("Module skeleton");
|
||||
MODULE_LICENSE("GPL");
|
||||
40
src/03_drivers/exercice06/Makefile
Normal file
40
src/03_drivers/exercice06/Makefile
Normal file
@@ -0,0 +1,40 @@
|
||||
export PATH := /buildroot/output/host/usr/sbin$\
|
||||
:/buildroot/output/host/usr/bin/$\
|
||||
:/buildroot/output/host/sbin$\
|
||||
:/buildroot/output/host/bin/$\
|
||||
:$(PATH)
|
||||
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all: dtb
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
|
||||
DTB = mydt.dtb
|
||||
DTS = mydt.dts
|
||||
INCL+=-I. -I$(KDIR)/include -I$(KDIR)/arch/arm64/boot/dts
|
||||
|
||||
dtb: $(DTB)
|
||||
$(DTB) : $(DTS)
|
||||
ln -s $(KDIR)/arch/arm/boot/dts arm
|
||||
-cpp $(INCL) -E -P -x assembler-with-cpp $(DTS) | dtc -I dts -O dtb -o $(DTB) -
|
||||
rm arm
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
rm -f *.dtb
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
13
src/03_drivers/exercice06/mydt.dts
Normal file
13
src/03_drivers/exercice06/mydt.dts
Normal file
@@ -0,0 +1,13 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include "allwinner/sun50i-h5-nanopi-neo-plus2.dts"
|
||||
|
||||
/ {
|
||||
/delete-node/ leds;
|
||||
|
||||
mydevice {
|
||||
compatible = "mydevice";
|
||||
attribute = "on";
|
||||
};
|
||||
|
||||
};
|
||||
255
src/03_drivers/exercice06/skeleton.c
Normal file
255
src/03_drivers/exercice06/skeleton.c
Normal file
@@ -0,0 +1,255 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
|
||||
#include <linux/cdev.h> /* needed for char device driver */
|
||||
#include <linux/fs.h> /* needed for device drivers */
|
||||
#include <linux/uaccess.h> /* needed to copy data to/from user */
|
||||
|
||||
#include <linux/device.h> /* needed for sysfs handling */
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h> /* needed for sysfs handling */
|
||||
|
||||
#define BUFFER_SZ 10000
|
||||
struct mydata {
|
||||
char buffer[BUFFER_SZ];
|
||||
struct miscdevice misc;
|
||||
};
|
||||
|
||||
static int skeleton_open(struct inode* i, struct file* f)
|
||||
{
|
||||
pr_info("skeleton : open operation... major:%d, minor:%d, p_data=%llx\n",
|
||||
imajor(i),
|
||||
iminor(i),
|
||||
(long long)f->private_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skeleton_release(struct inode* i, struct file* f)
|
||||
{
|
||||
pr_info("skeleton: release operation...p_data=%llx\n",
|
||||
(long long)f->private_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_read(struct file* f,
|
||||
char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
struct mydata* mydata = container_of(f->private_data, struct mydata, misc);
|
||||
|
||||
// compute remaining bytes to copy, update count and pointers
|
||||
ssize_t remaining = strlen(mydata->buffer) - (ssize_t)(*off);
|
||||
char* ptr = mydata->buffer + *off;
|
||||
if (count > remaining) count = remaining;
|
||||
*off += count;
|
||||
|
||||
// copy required number of bytes
|
||||
if (copy_to_user(buf, ptr, count) != 0) count = -EFAULT;
|
||||
|
||||
pr_info("skeleton: read operation...p_data=%llx read=%ld\n",
|
||||
(long long)f->private_data,
|
||||
count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_write(struct file* f,
|
||||
const char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
struct mydata* mydata = container_of(f->private_data, struct mydata, misc);
|
||||
|
||||
// compute remaining space in buffer and update pointers
|
||||
ssize_t remaining = sizeof(mydata->buffer) - (ssize_t)(*off);
|
||||
char* ptr = mydata->buffer + *off;
|
||||
*off += count;
|
||||
|
||||
// check if still remaining space to store additional bytes
|
||||
if (count >= remaining) count = -EIO;
|
||||
|
||||
// store additional bytes into internal buffer
|
||||
if (count > 0) {
|
||||
ptr[count] = 0; // make sure string is null terminated
|
||||
if (copy_from_user(ptr, buf, count)) count = -EFAULT;
|
||||
}
|
||||
|
||||
pr_info("skeleton: write operation... written=%ld\n", count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct file_operations fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = skeleton_open,
|
||||
.read = skeleton_read,
|
||||
.write = skeleton_write,
|
||||
.release = skeleton_release,
|
||||
};
|
||||
|
||||
int drv_probe(struct platform_device* pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct device_node* dt_node = pdev->dev.of_node;
|
||||
struct mydata* mydata = 0;
|
||||
|
||||
pr_info("skeleton - driver probe %llx (%s)- M.m=%d.%d\n",
|
||||
(unsigned long long)pdev,
|
||||
pdev->name,
|
||||
MAJOR(pdev->dev.devt),
|
||||
MINOR(pdev->dev.devt));
|
||||
|
||||
mydata = devm_kzalloc(&pdev->dev, sizeof(*mydata), GFP_KERNEL);
|
||||
pr_info("miscdev=%llx\n", (long long)mydata);
|
||||
if (mydata == 0) {
|
||||
dev_err(&pdev->dev, "Failed to allocate resource for miscdev\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (pdev->num_resources) {
|
||||
pr_info("resources: name=%s, start=%lld, end=%lld\n",
|
||||
pdev->resource[0].name,
|
||||
pdev->resource[0].start,
|
||||
pdev->resource[0].end);
|
||||
}
|
||||
|
||||
if (dt_node) {
|
||||
int ret = 0;
|
||||
const char* prop_str = 0;
|
||||
const unsigned int* prop_reg = 0;
|
||||
|
||||
prop_reg = of_get_property(dt_node, "reg", NULL);
|
||||
if (prop_reg != 0) {
|
||||
unsigned long reg = of_read_ulong(prop_reg, 1);
|
||||
pr_info("reg:%lu\n", reg);
|
||||
}
|
||||
|
||||
ret = of_property_read_string(dt_node, "attribute", &prop_str);
|
||||
if (prop_str && ret == 0)
|
||||
pr_info("attribute=%s (ret=%d)\n", prop_str, ret);
|
||||
}
|
||||
|
||||
/* register misc device ... */
|
||||
platform_set_drvdata(pdev, mydata);
|
||||
mydata->misc.minor = MISC_DYNAMIC_MINOR;
|
||||
mydata->misc.fops = &fops;
|
||||
mydata->misc.name = pdev->name;
|
||||
mydata->misc.mode = 0664;
|
||||
ret = misc_register(&(mydata->misc));
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to register miscdev\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int drv_remove(struct platform_device* pdev)
|
||||
{
|
||||
struct mydata* mydata = platform_get_drvdata(pdev);
|
||||
pr_info("skeleton - sysfs driver remove %s\n", pdev->name);
|
||||
misc_deregister(&(mydata->misc));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void drv_shutdown(struct platform_device* pdev)
|
||||
{
|
||||
pr_info("skeleton - sysfs driver shutdown %s\n", pdev->name);
|
||||
}
|
||||
int drv_suspend(struct platform_device* pdev, pm_message_t state)
|
||||
{
|
||||
pr_info("skeleton - sysfs driver suspend %s (state=%d)\n",
|
||||
pdev->name,
|
||||
state.event);
|
||||
return 0;
|
||||
}
|
||||
int drv_resume(struct platform_device* pdev)
|
||||
{
|
||||
pr_info("skeleton - sysfs driver resume %s\n", pdev->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct of_device_id of_drv[] = {
|
||||
{
|
||||
.compatible = "mydevice",
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_drv);
|
||||
|
||||
static struct platform_driver sysfs_driver = {
|
||||
.probe = drv_probe,
|
||||
.remove = drv_remove,
|
||||
.shutdown = drv_shutdown,
|
||||
.suspend = drv_suspend,
|
||||
.resume = drv_resume,
|
||||
.driver =
|
||||
{
|
||||
.name = "mydriver",
|
||||
.of_match_table = of_match_ptr(of_drv),
|
||||
},
|
||||
};
|
||||
|
||||
//#define INIT
|
||||
//#define MACRO
|
||||
#define BOTH
|
||||
|
||||
#ifdef INIT
|
||||
static int __init sysfs_driver_init(void)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
pr_info("Linux module skeleton loading...\n");
|
||||
|
||||
/* install sysfs */
|
||||
if (status == 0) status = platform_driver_register(&sysfs_driver);
|
||||
|
||||
pr_info("Linux module skeleton loaded\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit sysfs_driver_exit(void)
|
||||
{
|
||||
pr_info("Linux module skeleton exiting...\n");
|
||||
|
||||
/* uninstall sysfs */
|
||||
platform_driver_unregister(&sysfs_driver);
|
||||
|
||||
pr_info("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init(sysfs_driver_init);
|
||||
module_exit(sysfs_driver_exit);
|
||||
#endif
|
||||
|
||||
#ifdef MACRO
|
||||
module_platform_driver(sysfs_driver);
|
||||
#endif
|
||||
|
||||
#ifdef BOTH
|
||||
static int __init sysfs_driver_init(void)
|
||||
{
|
||||
pr_info("Linux module skeleton loading...\n");
|
||||
|
||||
pr_info("Linux module skeleton loaded\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit sysfs_driver_exit(void)
|
||||
{
|
||||
pr_info("Linux module skeleton exiting...\n");
|
||||
|
||||
pr_info("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init(sysfs_driver_init);
|
||||
module_exit(sysfs_driver_exit);
|
||||
module_platform_driver(sysfs_driver);
|
||||
#endif
|
||||
|
||||
|
||||
MODULE_AUTHOR("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION("Module skeleton");
|
||||
MODULE_LICENSE("GPL");
|
||||
5
src/03_drivers/exercice07/Makefile
Normal file
5
src/03_drivers/exercice07/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
DIRS=$(filter-out Makefile, $(wildcard *))
|
||||
|
||||
all clean install:
|
||||
for dir in $(DIRS); do $(MAKE) $@ -C $$dir; done
|
||||
|
||||
22
src/03_drivers/exercice07/drv/Makefile
Normal file
22
src/03_drivers/exercice07/drv/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
126
src/03_drivers/exercice07/drv/skeleton.c
Normal file
126
src/03_drivers/exercice07/drv/skeleton.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
|
||||
#include <linux/cdev.h> /* needed for char device driver */
|
||||
#include <linux/fs.h> /* needed for device drivers */
|
||||
#include <linux/uaccess.h> /* needed to copy data to/from user */
|
||||
|
||||
#include <linux/poll.h> /* needed for polling handling */
|
||||
#include <linux/sched.h> /* needed for scheduling constants */
|
||||
#include <linux/wait.h> /* needed for wating */
|
||||
|
||||
#include <linux/gpio.h> /* needed for i/o handling */
|
||||
#include <linux/interrupt.h> /* needed for interrupt handling */
|
||||
#include <linux/io.h> /* needed for mmio handling */
|
||||
#include <linux/ioport.h> /* needed for memory region handling */
|
||||
#include <linux/miscdevice.h>
|
||||
|
||||
#define K1 0
|
||||
#define K2 2
|
||||
#define K3 3
|
||||
|
||||
static char* k1 = "gpio_a.0-k1";
|
||||
static char* k2 = "gpio_a.2-k2";
|
||||
static char* k3 = "gpio_a.3-k3";
|
||||
|
||||
static atomic_t nb_of_interrupts;
|
||||
DECLARE_WAIT_QUEUE_HEAD(queue);
|
||||
|
||||
irqreturn_t gpio_isr(int irq, void* handle)
|
||||
{
|
||||
atomic_inc(&nb_of_interrupts);
|
||||
wake_up_interruptible(&queue);
|
||||
|
||||
pr_info("interrupt %s raised...\n", (char*)handle);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_read(struct file* f,
|
||||
char __user* buf,
|
||||
size_t sz,
|
||||
loff_t* off)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int skeleton_poll(struct file* f, poll_table* wait)
|
||||
{
|
||||
unsigned mask = 0;
|
||||
poll_wait(f, &queue, wait);
|
||||
if (atomic_read(&nb_of_interrupts) != 0) {
|
||||
mask |= POLLIN | POLLRDNORM; /* read operation */
|
||||
/* mask |= POLLOUT | POLLWRNORM; write operation */
|
||||
atomic_dec(&nb_of_interrupts);
|
||||
pr_info("polling thread waked-up...\n");
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
static struct file_operations skeleton_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = skeleton_read,
|
||||
.poll = skeleton_poll,
|
||||
};
|
||||
|
||||
struct miscdevice misc_device = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.fops = &skeleton_fops,
|
||||
.name = "mymodule",
|
||||
.mode = 0777,
|
||||
};
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
atomic_set(&nb_of_interrupts, 0);
|
||||
|
||||
status = misc_register(&misc_device);
|
||||
|
||||
// install k1
|
||||
if (status == 0)
|
||||
status = devm_request_irq(misc_device.this_device,
|
||||
gpio_to_irq(K1),
|
||||
gpio_isr,
|
||||
IRQF_TRIGGER_FALLING | IRQF_SHARED,
|
||||
k1,
|
||||
k1);
|
||||
|
||||
// install k2
|
||||
if (status == 0)
|
||||
status = devm_request_irq(misc_device.this_device,
|
||||
gpio_to_irq(K2),
|
||||
gpio_isr,
|
||||
IRQF_TRIGGER_RISING | IRQF_SHARED,
|
||||
k2,
|
||||
k2);
|
||||
|
||||
// install k3
|
||||
if (status == 0)
|
||||
status = devm_request_irq(
|
||||
misc_device.this_device,
|
||||
gpio_to_irq(K3),
|
||||
gpio_isr,
|
||||
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_SHARED,
|
||||
k3,
|
||||
k3);
|
||||
|
||||
pr_info("Linux module skeleton loaded(status=%d)\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
misc_deregister(&misc_device);
|
||||
pr_info("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init(skeleton_init);
|
||||
module_exit(skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION("Module skeleton");
|
||||
MODULE_LICENSE("GPL");
|
||||
5
src/03_drivers/exercice08/Makefile
Normal file
5
src/03_drivers/exercice08/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
DIRS=$(filter-out Makefile, $(wildcard *))
|
||||
|
||||
all clean install:
|
||||
for dir in $(DIRS); do $(MAKE) $@ -C $$dir; done
|
||||
|
||||
22
src/03_drivers/exercice08/drv/Makefile
Normal file
22
src/03_drivers/exercice08/drv/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
85
src/03_drivers/exercice08/drv/skeleton.c
Normal file
85
src/03_drivers/exercice08/drv/skeleton.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
|
||||
#include <linux/cdev.h> /* needed for char device driver */
|
||||
#include <linux/fs.h> /* needed for device drivers */
|
||||
#include <linux/uaccess.h> /* needed to copy data to/from user */
|
||||
|
||||
#include <linux/mm.h> /* needed for mmap handling */
|
||||
|
||||
#include <linux/device.h> /* needed for sysfs handling */
|
||||
#include <linux/platform_device.h> /* needed for sysfs handling */
|
||||
|
||||
static int skeleton_mmap(struct file* f, struct vm_area_struct* vma)
|
||||
{
|
||||
int status = 0;
|
||||
unsigned long size = vma->vm_end - vma->vm_start;
|
||||
|
||||
if (size > PAGE_SIZE) status = -EINVAL;
|
||||
|
||||
vma->vm_pgoff = 0x01c14000 >> PAGE_SHIFT;
|
||||
|
||||
if (status == 0)
|
||||
status = remap_pfn_range(
|
||||
vma, vma->vm_start, vma->vm_pgoff, size, vma->vm_page_prot);
|
||||
if (status != 0) status = -EAGAIN;
|
||||
|
||||
pr_info("skeleton: mmap (size=%lu, shift=%d) status=%d\n",
|
||||
size,
|
||||
PAGE_SHIFT,
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct file_operations skeleton_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.mmap = skeleton_mmap,
|
||||
};
|
||||
|
||||
static dev_t skeleton_dev;
|
||||
static struct cdev skeleton_cdev;
|
||||
|
||||
static void sysfs_dev_release(struct device* dev)
|
||||
{
|
||||
pr_info("skeleton - sysfs dev release\n");
|
||||
}
|
||||
static struct platform_device sysfs_device;
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = alloc_chrdev_region(&skeleton_dev, 0, 1, "mymodule");
|
||||
if (status == 0) {
|
||||
cdev_init(&skeleton_cdev, &skeleton_fops);
|
||||
skeleton_cdev.owner = THIS_MODULE;
|
||||
status = cdev_add(&skeleton_cdev, skeleton_dev, 1);
|
||||
}
|
||||
|
||||
sysfs_device.name = "mymodule";
|
||||
sysfs_device.id = -1;
|
||||
sysfs_device.dev.release = sysfs_dev_release;
|
||||
sysfs_device.dev.devt = skeleton_dev;
|
||||
if (status == 0) status = platform_device_register(&sysfs_device);
|
||||
|
||||
pr_info("Linux module skeleton loaded\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
platform_device_unregister(&sysfs_device);
|
||||
cdev_del(&skeleton_cdev);
|
||||
unregister_chrdev_region(skeleton_dev, 1);
|
||||
|
||||
pr_info("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init(skeleton_init);
|
||||
module_exit(skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION("Module skeleton");
|
||||
MODULE_LICENSE("GPL");
|
||||
5
src/03_drivers/exercice09/Makefile
Normal file
5
src/03_drivers/exercice09/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
DIRS=$(filter-out Makefile, $(wildcard *))
|
||||
|
||||
all clean install:
|
||||
for dir in $(DIRS); do $(MAKE) $@ -C $$dir; done
|
||||
|
||||
22
src/03_drivers/exercice09/drv/Makefile
Normal file
22
src/03_drivers/exercice09/drv/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
99
src/03_drivers/exercice09/drv/skeleton.c
Normal file
99
src/03_drivers/exercice09/drv/skeleton.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
|
||||
#include <linux/cdev.h> /* needed for char device driver */
|
||||
#include <linux/fs.h> /* needed for device drivers */
|
||||
#include <linux/uaccess.h> /* needed to copy data to/from user */
|
||||
|
||||
#include <linux/ioctl.h> /* needed for ioctl handling */
|
||||
#include "skeleton.h"
|
||||
|
||||
static struct skeleton_config config;
|
||||
static int val;
|
||||
|
||||
static long skeleton_ioctl(struct file* f, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int status = 0;
|
||||
switch (cmd) {
|
||||
case SKELETON_IO_RESET:
|
||||
val = 0;
|
||||
memset(&config, 0, sizeof(config));
|
||||
pr_info("skeleton-ioctl: reset command\n");
|
||||
break;
|
||||
|
||||
case SKELETON_IO_WR_REF:
|
||||
if (_IOC_SIZE(cmd) == sizeof(config))
|
||||
status =
|
||||
copy_from_user(&config, (char __user*)arg, _IOC_SIZE(cmd));
|
||||
else
|
||||
status = -EFAULT;
|
||||
pr_info("skeleton-ioctl: write config\n");
|
||||
break;
|
||||
|
||||
case SKELETON_IO_RD_REF:
|
||||
if (_IOC_SIZE(cmd) == sizeof(config))
|
||||
status =
|
||||
copy_to_user((char __user*)arg, &config, _IOC_SIZE(cmd));
|
||||
else
|
||||
status = -EFAULT;
|
||||
pr_info("skeleton-ioctl: read config\n");
|
||||
break;
|
||||
|
||||
case SKELETON_IO_WR_VAL:
|
||||
val = arg;
|
||||
pr_info("skeleton-ioctl: write value=%d\n", val);
|
||||
break;
|
||||
|
||||
case SKELETON_IO_RD_VAL:
|
||||
status = val;
|
||||
pr_info("skeleton-ioctl: read value=%d\n", status);
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_info("skeleton-ioctl: unknown command (cmd=%d)\n", cmd);
|
||||
status = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct file_operations skeleton_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = skeleton_ioctl,
|
||||
};
|
||||
|
||||
static dev_t skeleton_dev;
|
||||
static struct cdev skeleton_cdev;
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = alloc_chrdev_region(&skeleton_dev, 0, 1, "mymodule");
|
||||
if (status == 0) {
|
||||
cdev_init(&skeleton_cdev, &skeleton_fops);
|
||||
skeleton_cdev.owner = THIS_MODULE;
|
||||
status = cdev_add(&skeleton_cdev, skeleton_dev, 1);
|
||||
}
|
||||
|
||||
pr_info("Linux module skeleton loaded\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
cdev_del(&skeleton_cdev);
|
||||
unregister_chrdev_region(skeleton_dev, 1);
|
||||
|
||||
pr_info("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init(skeleton_init);
|
||||
module_exit(skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION("Module skeleton");
|
||||
MODULE_LICENSE("GPL");
|
||||
20
src/03_drivers/exercice09/drv/skeleton.h
Normal file
20
src/03_drivers/exercice09/drv/skeleton.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef SKELETON_H
|
||||
#define SKELETON_H
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
struct skeleton_config {
|
||||
int id;
|
||||
long ref;
|
||||
char name[30];
|
||||
char descr[30];
|
||||
};
|
||||
|
||||
#define SKELETON_IOMAGIC 'g'
|
||||
#define SKELETON_IO_RESET _IO(SKELETON_IOMAGIC, 0)
|
||||
#define SKELETON_IO_WR_REF _IOW(SKELETON_IOMAGIC, 1, struct skeleton_config)
|
||||
#define SKELETON_IO_RD_REF _IOR(SKELETON_IOMAGIC, 2, struct skeleton_config)
|
||||
#define SKELETON_IO_WR_VAL _IOW(SKELETON_IOMAGIC, 3, int)
|
||||
#define SKELETON_IO_RD_VAL _IOR(SKELETON_IOMAGIC, 4, int)
|
||||
|
||||
#endif
|
||||
22
src/03_drivers/exercice10/Makefile
Normal file
22
src/03_drivers/exercice10/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
120
src/03_drivers/exercice10/skeleton.c
Normal file
120
src/03_drivers/exercice10/skeleton.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
|
||||
#include <linux/cdev.h> /* needed for char device driver */
|
||||
#include <linux/fs.h> /* needed for device drivers */
|
||||
#include <linux/uaccess.h> /* needed to copy data to/from user */
|
||||
|
||||
#include <linux/proc_fs.h> /* needed for procfs handling */
|
||||
|
||||
struct skeleton_config {
|
||||
int id;
|
||||
long ref;
|
||||
char name[50];
|
||||
char descr[50];
|
||||
};
|
||||
|
||||
static struct skeleton_config config = {.id = 11,
|
||||
.ref = 33,
|
||||
.name = "config structure",
|
||||
.descr = "procfs test driver"};
|
||||
static int val = 55;
|
||||
|
||||
static ssize_t skeleton_read_config(struct file* f,
|
||||
char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
char temp[200];
|
||||
int len = snprintf(temp,
|
||||
sizeof(temp),
|
||||
"id=%d\nref=%ld\nname=%s\ndescr=%s\n",
|
||||
config.id,
|
||||
config.ref,
|
||||
config.name,
|
||||
config.descr);
|
||||
|
||||
len -= (ssize_t)(*off);
|
||||
if (count > len) count = len;
|
||||
*off += count;
|
||||
|
||||
if (copy_to_user(buf, temp, count) != 0) count = -EFAULT;
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct proc_ops fops_config = {
|
||||
.proc_read = skeleton_read_config,
|
||||
};
|
||||
|
||||
static ssize_t skeleton_read_val(struct file* f,
|
||||
char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
char temp[20];
|
||||
int len = snprintf(temp, sizeof(temp), "%d\n", val);
|
||||
|
||||
len -= (ssize_t)(*off);
|
||||
if (count > len) count = len;
|
||||
*off += count;
|
||||
|
||||
if (copy_to_user(buf, temp, count) != 0) count = -EFAULT;
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_write_val(struct file* f,
|
||||
const char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
char temp[20];
|
||||
|
||||
if (count > sizeof(temp)) return -EIO;
|
||||
if (copy_from_user(temp, buf, count)) return -EFAULT;
|
||||
|
||||
val = simple_strtol(temp, 0, 10);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct proc_ops fops_val = {
|
||||
.proc_read = skeleton_read_val,
|
||||
.proc_write = skeleton_write_val,
|
||||
};
|
||||
|
||||
static struct proc_dir_entry* procfs_dir = 0;
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
/* create procfs node and attributes */
|
||||
procfs_dir = proc_mkdir("mymodule", NULL);
|
||||
proc_create("config", 0, procfs_dir, &fops_config);
|
||||
proc_create("val", 0, procfs_dir, &fops_val);
|
||||
|
||||
if (procfs_dir == 0) status = -EFAULT;
|
||||
|
||||
pr_info("Linux module skeleton loaded (status=%d)\n", status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
/* remove procfs attributes and node */
|
||||
remove_proc_entry("val", procfs_dir);
|
||||
remove_proc_entry("config", procfs_dir);
|
||||
remove_proc_entry("mymodule", NULL);
|
||||
|
||||
pr_info("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init(skeleton_init);
|
||||
module_exit(skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION("Module skeleton");
|
||||
MODULE_LICENSE("GPL");
|
||||
19
src/03_drivers/sample01/Makefile
Normal file
19
src/03_drivers/sample01/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
objects = main1 main2 main3
|
||||
|
||||
TOOLCHAIN_PATH=/buildroot/output/host/usr/bin/
|
||||
TOOLCHAIN=$(TOOLCHAIN_PATH)aarch64-linux-
|
||||
CFLAGS+=-Wall -Wextra -g -O0 -std=gnu11
|
||||
CFLAGS+=-mcpu=cortex-a53 -funwind-tables
|
||||
|
||||
CC=$(TOOLCHAIN)gcc
|
||||
|
||||
|
||||
all: $(objects)
|
||||
|
||||
$(objects): %: %.c
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.txt
|
||||
rm -f *~
|
||||
rm $(objects)
|
||||
14
src/03_drivers/sample01/main1.c
Normal file
14
src/03_drivers/sample01/main1.c
Normal file
@@ -0,0 +1,14 @@
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const char* msg1 = "1234567890abcdefghijklmnopqrstuvwxyz\n";
|
||||
|
||||
int main()
|
||||
{
|
||||
int fd = open("test1.txt", O_RDWR | O_CREAT | O_TRUNC, 0664);
|
||||
for (int i = 0; i < 10000; i++) write(fd, msg1, strlen(msg1));
|
||||
close(fd);
|
||||
}
|
||||
28
src/03_drivers/sample01/main2.c
Normal file
28
src/03_drivers/sample01/main2.c
Normal file
@@ -0,0 +1,28 @@
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define FILE_SZ (10 * 1024 * 1024)
|
||||
|
||||
static const char* msg2 = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
|
||||
|
||||
int main()
|
||||
{
|
||||
// open again 1st file generated by the main1 application
|
||||
int fd = open("test1.txt", O_RDWR, 0664);
|
||||
char* file = mmap(0, FILE_SZ, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
printf("the file after mapping...\n");
|
||||
|
||||
// modify every 10th lines
|
||||
for (int i = 0; i < 10000; i += 10)
|
||||
memcpy(file + i * strlen(msg2), msg2, strlen(msg2));
|
||||
|
||||
printf("the file after filling...\n");
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
28
src/03_drivers/sample01/main3.c
Normal file
28
src/03_drivers/sample01/main3.c
Normal file
@@ -0,0 +1,28 @@
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define FILE_SZ (5 * 1024 * 1024)
|
||||
|
||||
static const char* msg1 = "1234567890abcdefghijklmnopqrstuvwxyz\n";
|
||||
|
||||
int main()
|
||||
{
|
||||
int fd = open("test3.txt", O_RDWR | O_CREAT | O_TRUNC, 0664);
|
||||
char* file = mmap(0, FILE_SZ, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
lseek(fd, FILE_SZ, SEEK_SET);
|
||||
write(fd, "", 1);
|
||||
printf("the file after mapping...\n");
|
||||
|
||||
for (int i = 0; i < 10000; i += 1)
|
||||
memcpy(file + i * strlen(msg1), msg1, strlen(msg1));
|
||||
|
||||
printf("the file after filling...\n");
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
10000
src/03_drivers/sample01/test1.txt
Normal file
10000
src/03_drivers/sample01/test1.txt
Normal file
File diff suppressed because it is too large
Load Diff
22
src/03_drivers/sample05.1/Makefile
Normal file
22
src/03_drivers/sample05.1/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
101
src/03_drivers/sample05.1/skeleton.c
Normal file
101
src/03_drivers/sample05.1/skeleton.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
|
||||
#include <linux/cdev.h> /* needed for char device driver */
|
||||
#include <linux/fs.h> /* needed for device drivers */
|
||||
#include <linux/uaccess.h> /* needed to copy data to/from user */
|
||||
|
||||
#include <linux/device.h> /* needed for sysfs handling */
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h> /* needed for sysfs handling */
|
||||
|
||||
#define BUFFER_SZ 10000
|
||||
|
||||
static struct mydata {
|
||||
struct device* device;
|
||||
|
||||
struct skeleton_attr {
|
||||
char buffer[BUFFER_SZ];
|
||||
struct device_attribute dev_attr;
|
||||
} attr;
|
||||
|
||||
} mydevices[5];
|
||||
|
||||
#define ATTR_INSTANCE(a) \
|
||||
{ \
|
||||
a.attr.buffer[0] = 0; \
|
||||
a.attr.dev_attr.attr.name = "val"; \
|
||||
a.attr.dev_attr.attr.mode = 0664; \
|
||||
a.attr.dev_attr.show = sysfs_show_attr; \
|
||||
a.attr.dev_attr.store = sysfs_store_attr; \
|
||||
}
|
||||
|
||||
// --- sysfs file opers ------------------------------------------------------
|
||||
|
||||
ssize_t sysfs_show_attr(struct device* dev,
|
||||
struct device_attribute* attr,
|
||||
char* buf)
|
||||
{
|
||||
struct mydata* mydata = container_of(attr, struct mydata, attr.dev_attr);
|
||||
|
||||
strcpy(buf, mydata->attr.buffer);
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
ssize_t sysfs_store_attr(struct device* dev,
|
||||
struct device_attribute* attr,
|
||||
const char* buf,
|
||||
size_t count)
|
||||
{
|
||||
struct mydata* mydata = container_of(attr, struct mydata, attr.dev_attr);
|
||||
|
||||
int len = sizeof(mydata->attr.buffer) - 1;
|
||||
if (len > count) len = count;
|
||||
strncpy(mydata->attr.buffer, buf, len);
|
||||
mydata->attr.buffer[len] = 0;
|
||||
return len;
|
||||
}
|
||||
static struct class* sysfs_class;
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
int status = 0;
|
||||
int i =0;
|
||||
|
||||
sysfs_class = class_create(THIS_MODULE, "myclass");
|
||||
|
||||
for (i=0; i<ARRAY_SIZE(mydevices); i++) {
|
||||
struct mydata* mydev = &mydevices[i];
|
||||
|
||||
mydev->device = device_create(sysfs_class, NULL, i, NULL, "mydevice.%d", i);
|
||||
|
||||
ATTR_INSTANCE((*mydev));
|
||||
status = device_create_file(mydev->device, &(mydev->attr.dev_attr));
|
||||
}
|
||||
|
||||
pr_info("Linux module skeleton loaded\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
int i = 0;
|
||||
for (i=0; i<ARRAY_SIZE(mydevices); i++) {
|
||||
struct mydata* mydev = &mydevices[i];
|
||||
device_remove_file(mydev->device, &(mydev->attr.dev_attr));
|
||||
device_destroy(sysfs_class, i);
|
||||
}
|
||||
class_destroy(sysfs_class);
|
||||
|
||||
pr_info("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init(skeleton_init);
|
||||
module_exit(skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION("Module skeleton");
|
||||
MODULE_LICENSE("GPL");
|
||||
22
src/03_drivers/sample05/Makefile
Normal file
22
src/03_drivers/sample05/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
59
src/03_drivers/sample05/skeleton.c
Normal file
59
src/03_drivers/sample05/skeleton.c
Normal file
@@ -0,0 +1,59 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
#include <linux/device.h> /* needed for sysfs handling */
|
||||
|
||||
static char sysfs_buf[1000];
|
||||
|
||||
ssize_t sysfs_show_attr(struct device* dev,
|
||||
struct device_attribute* attr,
|
||||
char* buf)
|
||||
{
|
||||
strcpy(buf, sysfs_buf);
|
||||
return strlen(buf);
|
||||
}
|
||||
ssize_t sysfs_store_attr(struct device* dev,
|
||||
struct device_attribute* attr,
|
||||
const char* buf,
|
||||
size_t count)
|
||||
{
|
||||
int len = sizeof(sysfs_buf) - 1;
|
||||
if (len > count) len = count;
|
||||
strncpy(sysfs_buf, buf, len);
|
||||
sysfs_buf[len] = 0;
|
||||
return len;
|
||||
}
|
||||
DEVICE_ATTR(attr, 0664, sysfs_show_attr, sysfs_store_attr);
|
||||
|
||||
static struct class* sysfs_class;
|
||||
static struct device* sysfs_device;
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
sysfs_class = class_create(THIS_MODULE, "myclass");
|
||||
sysfs_device = device_create(sysfs_class, NULL, 0, NULL, "mydevice");
|
||||
status = device_create_file(sysfs_device, &dev_attr_attr);
|
||||
|
||||
pr_info("Linux module skeleton loaded\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
/* uninstall sysfs */
|
||||
device_remove_file(sysfs_device, &dev_attr_attr);
|
||||
device_destroy(sysfs_class, 0);
|
||||
class_destroy(sysfs_class);
|
||||
|
||||
pr_info("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init(skeleton_init);
|
||||
module_exit(skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION("Module skeleton");
|
||||
MODULE_LICENSE("GPL");
|
||||
22
src/03_drivers/sample06.2/Makefile
Normal file
22
src/03_drivers/sample06.2/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
217
src/03_drivers/sample06.2/skeleton.c
Normal file
217
src/03_drivers/sample06.2/skeleton.c
Normal file
@@ -0,0 +1,217 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
|
||||
#include <linux/moduleparam.h> /* needed for module parameters */
|
||||
#include <linux/slab.h> /* needed for dynamic memory management */
|
||||
|
||||
#include <linux/fs.h> /* needed for device drivers */
|
||||
#include <linux/uaccess.h> /* needed to copy data to/from user */
|
||||
#include <linux/cdev.h> /* needed for char device driver */
|
||||
|
||||
#include <linux/device.h> /* needed for sysfs handling */
|
||||
#include <linux/platform_device.h> /* needed for sysfs handling */
|
||||
|
||||
#define INSTANCES 3
|
||||
|
||||
// --- sysfs operations --------------------------------------------------------
|
||||
|
||||
struct skeleton_attr {
|
||||
long val;
|
||||
int id;
|
||||
struct device_attribute dev_attr;
|
||||
};
|
||||
|
||||
#define ATTR_INSTANCE(i,v)\
|
||||
{\
|
||||
.val = v,\
|
||||
.id = i,\
|
||||
.dev_attr = {\
|
||||
.attr = {.name = "val", .mode=0664, },\
|
||||
.show = sysfs_show_val,\
|
||||
.store = sysfs_store_val,\
|
||||
},\
|
||||
}
|
||||
|
||||
static ssize_t sysfs_show_val(
|
||||
struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct skeleton_attr* s_attr =
|
||||
container_of(attr, struct skeleton_attr, dev_attr);
|
||||
|
||||
sprintf (buf, "%ld\n", s_attr->val);
|
||||
|
||||
pr_info ("skeleton-sysfs_show: val[%d]=%ld\n", s_attr->id, s_attr->val);
|
||||
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
static ssize_t sysfs_store_val(
|
||||
struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct skeleton_attr* s_attr =
|
||||
container_of(attr, struct skeleton_attr, dev_attr);
|
||||
|
||||
int err = kstrtol (buf, 10, &s_attr->val);
|
||||
|
||||
//pr_info ("skeleton-sysfs_store: val[%d]=%ld\n", s_attr->id, s_attr->val);
|
||||
return err == 0 ? count : err;
|
||||
}
|
||||
|
||||
static struct skeleton_attr skeleton_attr[INSTANCES] = {
|
||||
[0] = ATTR_INSTANCE(0,10),
|
||||
[1] = ATTR_INSTANCE(1,11),
|
||||
[2] = ATTR_INSTANCE(2,12),
|
||||
};
|
||||
|
||||
|
||||
static void sysfs_dev_release (struct device *dev)
|
||||
{
|
||||
pr_info ("skeleton-sysfs_dev_release\n");
|
||||
}
|
||||
static struct platform_device sysfs_device[INSTANCES];
|
||||
|
||||
// --- fops operations ---------------------------------------------------------
|
||||
|
||||
#define BUFFER_SZ 10000
|
||||
static char buffers[INSTANCES][BUFFER_SZ];
|
||||
|
||||
static int skeleton_open (struct inode *i, struct file *f)
|
||||
{
|
||||
pr_info ("skeleton-open operation... major:%d, minor:%d\n",
|
||||
imajor (i), iminor(i));
|
||||
|
||||
if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) != 0) {
|
||||
pr_info (" o--> opened for reading & writing...\n");
|
||||
} else if (iminor(i) >= INSTANCES) return -EFAULT;
|
||||
|
||||
if ((f->f_mode & FMODE_READ) != 0) {
|
||||
pr_info (" o--> opened for reading...\n");
|
||||
|
||||
} else if ((f->f_mode & FMODE_WRITE) != 0) {
|
||||
pr_info (" o--> opened for writing...\n");
|
||||
}
|
||||
|
||||
f->private_data = buffers[iminor(i)];
|
||||
pr_info (" o--> private_data address = %p\n", f->private_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skeleton_release (struct inode *i, struct file *f)
|
||||
{
|
||||
pr_info ("skeleton-release operation...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_read (struct file *f, char __user *buf,
|
||||
size_t count, loff_t *off)
|
||||
{
|
||||
// compute remaining bytes to copy, update count and pointers
|
||||
ssize_t remaining = strlen(f->private_data) - (ssize_t)(*off);
|
||||
char* ptr = (char*)f->private_data + *off;
|
||||
if (count > remaining) count = remaining;
|
||||
*off += count;
|
||||
|
||||
// copy required number of bytes
|
||||
if (copy_to_user (buf, ptr, count) != 0) count = -EFAULT;
|
||||
|
||||
pr_info("skeleton-read: buf=%p, read=%ld\n", f->private_data, count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_write (struct file *f, const char __user *buf,
|
||||
size_t count, loff_t *off)
|
||||
{
|
||||
// compute remaining space in buffer and update pointers
|
||||
ssize_t remaining = BUFFER_SZ - (ssize_t)(*off);
|
||||
char* ptr = (char*)f->private_data + *off;
|
||||
*off += count;
|
||||
|
||||
// check if still remaining space to store additional bytes
|
||||
if (count >= remaining) count = -EIO;
|
||||
|
||||
// store additional bytes into internal buffer
|
||||
if (count > 0) {
|
||||
ptr[count] = 0; // make sure string is null terminated
|
||||
if (copy_from_user (ptr, buf, count)) count = -EFAULT;
|
||||
}
|
||||
|
||||
pr_info ("skeleton-write: buf=%p, written=%ld\n", f->private_data, count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct file_operations skeleton_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = skeleton_open,
|
||||
.read = skeleton_read,
|
||||
.write = skeleton_write,
|
||||
.release = skeleton_release,
|
||||
};
|
||||
|
||||
static dev_t skeleton_dev;
|
||||
static struct cdev skeleton_cdev;
|
||||
|
||||
static int __init skeleton_init(void)
|
||||
{
|
||||
int i;
|
||||
int status = -EFAULT;
|
||||
|
||||
status = alloc_chrdev_region (&skeleton_dev, 0, INSTANCES, "mymodule");
|
||||
if (status == 0) {
|
||||
cdev_init (&skeleton_cdev, &skeleton_fops);
|
||||
skeleton_cdev.owner = THIS_MODULE;
|
||||
status = cdev_add (&skeleton_cdev, skeleton_dev, INSTANCES);
|
||||
}
|
||||
|
||||
/* install sysfs */
|
||||
for (i = 0; i < INSTANCES; i++) {
|
||||
sysfs_device[i].name = "mymodule";
|
||||
sysfs_device[i].id = i;
|
||||
sysfs_device[i].dev.release = sysfs_dev_release;
|
||||
sysfs_device[i].dev.devt = MKDEV (MAJOR(skeleton_dev), i);
|
||||
if (status == 0)
|
||||
status = platform_device_register (&sysfs_device[i]);
|
||||
if (status == 0)
|
||||
status = device_create_file (
|
||||
&sysfs_device[i].dev,
|
||||
&skeleton_attr[i].dev_attr);
|
||||
}
|
||||
|
||||
pr_info ("Linux module skeleton loaded\n");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void __exit skeleton_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < INSTANCES; i++) {
|
||||
device_remove_file (
|
||||
&sysfs_device[i].dev,
|
||||
&skeleton_attr[i].dev_attr);
|
||||
platform_device_unregister (&sysfs_device[i]);
|
||||
}
|
||||
|
||||
cdev_del (&skeleton_cdev);
|
||||
unregister_chrdev_region (skeleton_dev, INSTANCES);
|
||||
|
||||
pr_info ("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init (skeleton_init);
|
||||
module_exit (skeleton_exit);
|
||||
|
||||
MODULE_AUTHOR ("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION ("Module skeleton");
|
||||
MODULE_LICENSE ("GPL");
|
||||
|
||||
42
src/03_drivers/sample06.3/Makefile
Normal file
42
src/03_drivers/sample06.3/Makefile
Normal file
@@ -0,0 +1,42 @@
|
||||
export PATH := /buildroot/output/host/usr/sbin$\
|
||||
:/buildroot/output/host/usr/bin/$\
|
||||
:/buildroot/output/host/sbin$\
|
||||
:/buildroot/output/host/bin/$\
|
||||
:$(PATH)
|
||||
|
||||
# Part executed when called from kernel build system:
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += mymodule.o ## name of the generated module
|
||||
|
||||
mymodule-objs := skeleton.o ## list of objects needed for that module
|
||||
|
||||
# Part executed when called from standard make in module source directory:
|
||||
else
|
||||
include ../../kernel_settings
|
||||
PWD := $(shell pwd)
|
||||
|
||||
INCL+=-I. -I$(KDIR)/include -I$(KDIR)/arch/arm64/boot/dts
|
||||
DTB = mydt.dtb
|
||||
DTS = $(DTB:.dtb=.dts)
|
||||
|
||||
all: dtb boot
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(CPU) CROSS_COMPILE=$(TOOLS) modules
|
||||
|
||||
dtb: $(DTB)
|
||||
$(DTB) : $(DTS)
|
||||
ln -s $(KDIR)/arch/arm/boot/dts arm
|
||||
-cpp $(INCL) -E -P -x assembler-with-cpp $(DTS) | dtc -I dts -O dtb -o $(DTB) -
|
||||
rm arm
|
||||
|
||||
boot:
|
||||
mkimage -T script -A arm -C none -d boot.cmd boot.ovl
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) clean
|
||||
rm -f *.dtb *.ovl
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) INSTALL_MOD_PATH=$(MODPATH) modules_install
|
||||
|
||||
endif
|
||||
|
||||
13
src/03_drivers/sample06.3/boot.cmd
Normal file
13
src/03_drivers/sample06.3/boot.cmd
Normal file
@@ -0,0 +1,13 @@
|
||||
setenv bootargs console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait
|
||||
|
||||
fatload mmc 0 $kernel_addr_r Image
|
||||
#fatload mmc 0 $fdt_addr_r sun50i-h5-nanopi-neo-plus2.dtb
|
||||
fatload mmc 0 $fdt_addr_r mydt.dtb
|
||||
|
||||
fdt addr $fdt_addr_r
|
||||
fdt resize
|
||||
#fdt mknode / mymodule2
|
||||
#fdt set /mymodule2 compatible mymodule2
|
||||
|
||||
|
||||
booti $kernel_addr_r - $fdt_addr_r
|
||||
29
src/03_drivers/sample06.3/mydt.dts
Normal file
29
src/03_drivers/sample06.3/mydt.dts
Normal file
@@ -0,0 +1,29 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include "allwinner/sun50i-h5-nanopi-neo-plus2.dts"
|
||||
|
||||
/ {
|
||||
/delete-node/ leds;
|
||||
|
||||
mydevice {
|
||||
compatible = "mydevice";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
attribute = "idle";
|
||||
|
||||
mydevice@0 {
|
||||
reg = <0x0>;
|
||||
attribute = "on";
|
||||
};
|
||||
|
||||
mydevice@1 {
|
||||
reg = <0x1>;
|
||||
attribute = "off";
|
||||
};
|
||||
|
||||
mydevice@2 {
|
||||
reg = <0x2>;
|
||||
attribute = "off";
|
||||
};
|
||||
};
|
||||
};
|
||||
304
src/03_drivers/sample06.3/skeleton.c
Normal file
304
src/03_drivers/sample06.3/skeleton.c
Normal file
@@ -0,0 +1,304 @@
|
||||
/* skeleton.c */
|
||||
#include <linux/init.h> /* needed for macros */
|
||||
#include <linux/kernel.h> /* needed for debugging */
|
||||
#include <linux/module.h> /* needed by all modules */
|
||||
|
||||
#include <linux/cdev.h> /* needed for char device driver */
|
||||
#include <linux/fs.h> /* needed for device drivers */
|
||||
#include <linux/uaccess.h> /* needed to copy data to/from user */
|
||||
|
||||
#include <linux/device.h> /* needed for sysfs handling */
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h> /* needed for sysfs handling */
|
||||
|
||||
#define BUFFER_SZ 10000
|
||||
|
||||
struct mydata {
|
||||
char buffer[BUFFER_SZ];
|
||||
|
||||
struct class* sysfs_class;
|
||||
struct device* sysfs_device;
|
||||
struct miscdevice misc;
|
||||
struct skeleton_attr {
|
||||
long val;
|
||||
int id;
|
||||
struct device_attribute dev_attr;
|
||||
} attr;
|
||||
};
|
||||
|
||||
#define ATTR_INSTANCE(a, i, v) \
|
||||
{ \
|
||||
a.attr.val = v; \
|
||||
a.attr.id = i; \
|
||||
a.attr.dev_attr.attr.name = "val"; \
|
||||
a.attr.dev_attr.attr.mode = 0664; \
|
||||
a.attr.dev_attr.show = sysfs_show_val; \
|
||||
a.attr.dev_attr.store = sysfs_store_val; \
|
||||
}
|
||||
|
||||
// --- sysfs file opers ------------------------------------------------------
|
||||
|
||||
static ssize_t sysfs_show_val(struct device* dev,
|
||||
struct device_attribute* attr,
|
||||
char* buf)
|
||||
{
|
||||
struct mydata* mydata = container_of(attr, struct mydata, attr.dev_attr);
|
||||
|
||||
sprintf(buf, "%ld\n", mydata->attr.val);
|
||||
|
||||
pr_info("skeleton-sysfs_show: val[%d]=%ld\n",
|
||||
mydata->attr.id,
|
||||
mydata->attr.val);
|
||||
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
static ssize_t sysfs_store_val(struct device* dev,
|
||||
struct device_attribute* attr,
|
||||
const char* buf,
|
||||
size_t count)
|
||||
{
|
||||
struct mydata* mydata = container_of(attr, struct mydata, attr.dev_attr);
|
||||
|
||||
int err = kstrtol(buf, 10, &mydata->attr.val);
|
||||
|
||||
pr_info("skeleton-sysfs_store: val[%d]=%ld\n",
|
||||
mydata->attr.id,
|
||||
mydata->attr.val);
|
||||
|
||||
return err == 0 ? count : err;
|
||||
}
|
||||
|
||||
// --- file opers ------------------------------------------------------------
|
||||
|
||||
static int skeleton_open(struct inode* i, struct file* f)
|
||||
{
|
||||
pr_info("skeleton : open operation... major:%d, minor:%d, p_data=%llx\n",
|
||||
imajor(i),
|
||||
iminor(i),
|
||||
(long long)f->private_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skeleton_release(struct inode* i, struct file* f)
|
||||
{
|
||||
pr_info("skeleton: release operation...p_data=%llx\n",
|
||||
(long long)f->private_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_read(struct file* f,
|
||||
char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
struct mydata* mydata = container_of(f->private_data, struct mydata, misc);
|
||||
|
||||
// compute remaining bytes to copy, update count and pointers
|
||||
ssize_t remaining = strlen(mydata->buffer) - (ssize_t)(*off);
|
||||
char* ptr = mydata->buffer + *off;
|
||||
if (count > remaining) count = remaining;
|
||||
*off += count;
|
||||
|
||||
// copy required number of bytes
|
||||
if (copy_to_user(buf, ptr, count) != 0) count = -EFAULT;
|
||||
|
||||
pr_info("skeleton: read operation...p_data=%llx read=%ld\n",
|
||||
(long long)f->private_data,
|
||||
count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t skeleton_write(struct file* f,
|
||||
const char __user* buf,
|
||||
size_t count,
|
||||
loff_t* off)
|
||||
{
|
||||
struct mydata* mydata = container_of(f->private_data, struct mydata, misc);
|
||||
|
||||
// compute remaining space in buffer and update pointers
|
||||
ssize_t remaining = sizeof(mydata->buffer) - (ssize_t)(*off);
|
||||
char* ptr = mydata->buffer + *off;
|
||||
*off += count;
|
||||
|
||||
// check if still remaining space to store additional bytes
|
||||
if (count >= remaining) count = -EIO;
|
||||
|
||||
// store additional bytes into internal buffer
|
||||
if (count > 0) {
|
||||
ptr[count] = 0; // make sure string is null terminated
|
||||
if (copy_from_user(ptr, buf, count)) count = -EFAULT;
|
||||
}
|
||||
|
||||
pr_info("skeleton: write operation... written=%ld\n", count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct file_operations fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = skeleton_open,
|
||||
.read = skeleton_read,
|
||||
.write = skeleton_write,
|
||||
.release = skeleton_release,
|
||||
};
|
||||
|
||||
int drv_probe(struct platform_device* pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct device_node* dt_node = pdev->dev.of_node;
|
||||
struct mydata* mydata = 0;
|
||||
const char* prop_str = 0;
|
||||
|
||||
pr_info("skeleton - driver probe %llx (%s)- M.m=%d.%d\n",
|
||||
(unsigned long long)pdev,
|
||||
pdev->name,
|
||||
MAJOR(pdev->dev.devt),
|
||||
MINOR(pdev->dev.devt));
|
||||
|
||||
ret = of_property_read_string(dt_node, "attribute", &prop_str);
|
||||
if (prop_str && ret == 0) pr_info("attribute=%s (ret=%d)\n", prop_str, ret);
|
||||
|
||||
if (pdev->num_resources) {
|
||||
pr_info("resources: name=%s, start=%lld, end=%lld\n",
|
||||
pdev->resource[0].name,
|
||||
pdev->resource[0].start,
|
||||
pdev->resource[0].end);
|
||||
}
|
||||
|
||||
if (dt_node) {
|
||||
int ret = 0;
|
||||
const char* prop_str = 0;
|
||||
const unsigned int* prop_reg = 0;
|
||||
unsigned long reg = 0;
|
||||
|
||||
struct device_node* child;
|
||||
for_each_available_child_of_node(dt_node, child)
|
||||
{
|
||||
mydata = devm_kzalloc(&pdev->dev, sizeof(*mydata), GFP_KERNEL);
|
||||
pr_info("miscdev=%llx\n", (long long)mydata);
|
||||
if (mydata == 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to allocate resource for miscdev\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pr_info("child found: name=%s, fullname=%s\n",
|
||||
child->name,
|
||||
child->full_name);
|
||||
prop_reg = of_get_property(child, "reg", NULL);
|
||||
if (prop_reg != 0) {
|
||||
reg = of_read_ulong(prop_reg, 1);
|
||||
pr_info("reg:%lu\n", reg);
|
||||
}
|
||||
|
||||
ret = of_property_read_string(child, "attribute", &prop_str);
|
||||
if (prop_str && ret == 0)
|
||||
pr_info("attribute=%s (ret=%d)\n", prop_str, ret);
|
||||
|
||||
// register misc device ...
|
||||
platform_set_drvdata(pdev, mydata);
|
||||
mydata->misc.minor = MISC_DYNAMIC_MINOR;
|
||||
mydata->misc.fops = &fops;
|
||||
mydata->misc.name = child->full_name;
|
||||
mydata->misc.mode = 0664;
|
||||
ret = misc_register(&(mydata->misc));
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to register miscdev\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
// register misc device sysfs attribute...
|
||||
ATTR_INSTANCE((*mydata), reg, reg);
|
||||
ret = device_create_file(mydata->misc.this_device,
|
||||
&mydata->attr.dev_attr);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to register miscdev sysfs attribute\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int drv_remove(struct platform_device* pdev)
|
||||
{
|
||||
struct mydata* mydata = platform_get_drvdata(pdev);
|
||||
pr_info("skeleton - sysfs driver remove %s\n", pdev->name);
|
||||
misc_deregister(&(mydata->misc));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void drv_shutdown(struct platform_device* pdev)
|
||||
{
|
||||
pr_info("skeleton - sysfs driver shutdown %s\n", pdev->name);
|
||||
}
|
||||
int drv_suspend(struct platform_device* pdev, pm_message_t state)
|
||||
{
|
||||
pr_info("skeleton - sysfs driver suspend %s (state=%d)\n",
|
||||
pdev->name,
|
||||
state.event);
|
||||
return 0;
|
||||
}
|
||||
int drv_resume(struct platform_device* pdev)
|
||||
{
|
||||
pr_info("skeleton - sysfs driver resume %s\n", pdev->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct of_device_id of_drv[] = {
|
||||
{
|
||||
.compatible = "mydevice",
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_drv);
|
||||
|
||||
static struct platform_driver sysfs_driver = {
|
||||
.probe = drv_probe,
|
||||
.remove = drv_remove,
|
||||
.shutdown = drv_shutdown,
|
||||
.suspend = drv_suspend,
|
||||
.resume = drv_resume,
|
||||
.driver =
|
||||
{
|
||||
.name = "mydriver",
|
||||
.of_match_table = of_match_ptr(of_drv),
|
||||
},
|
||||
};
|
||||
#if 1
|
||||
static int __init sysfs_driver_init(void)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
pr_info("Linux module skeleton loading...\n");
|
||||
|
||||
/* install sysfs */
|
||||
if (status == 0) status = platform_driver_register(&sysfs_driver);
|
||||
|
||||
pr_info("Linux module skeleton loaded\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit sysfs_driver_exit(void)
|
||||
{
|
||||
pr_info("Linux module skeleton exiting...\n");
|
||||
|
||||
/* uninstall sysfs */
|
||||
platform_driver_unregister(&sysfs_driver);
|
||||
|
||||
pr_info("Linux module skeleton unloaded\n");
|
||||
}
|
||||
|
||||
module_init(sysfs_driver_init);
|
||||
module_exit(sysfs_driver_exit);
|
||||
|
||||
#else
|
||||
module_platform_driver(sysfs_driver);
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Daniel Gachet <daniel.gachet@hefr.ch>");
|
||||
MODULE_DESCRIPTION("Module skeleton");
|
||||
MODULE_LICENSE("GPL");
|
||||
5
src/buildroot_path
Normal file
5
src/buildroot_path
Normal file
@@ -0,0 +1,5 @@
|
||||
export PATH := /buildroot/output/host/usr/sbin$\
|
||||
:/buildroot/output/host/usr/bin/$\
|
||||
:/buildroot/output/host/sbin$\
|
||||
:/buildroot/output/host/bin/$\
|
||||
:$(PATH)
|
||||
8
src/kernel_settings
Normal file
8
src/kernel_settings
Normal file
@@ -0,0 +1,8 @@
|
||||
CVER := aarch64-buildroot-linux-gnu-
|
||||
KVER := 5.15.21
|
||||
CPU := arm64
|
||||
|
||||
KDIR := /buildroot/output/build/linux-$(KVER)/
|
||||
TOOLS := /buildroot/output/host/usr/bin/$(CVER)
|
||||
MODPATH := /rootfs
|
||||
#MODPATH := /buildroot/output/target
|
||||
Reference in New Issue
Block a user