Initial commit

This commit is contained in:
Jacques Supcik committed 2026-02-18 13:34:35 +01:00
commit 3967e73347
196 files changed
+17768

No files matched your search

+14
View 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
View File
@@ -0,0 +1,4 @@
DIRS=$(filter-out Makefile appl.mk dot-vscode, $(wildcard *))
all clean clean_all:
for dir in $(DIRS); do $(MAKE) $@ -C $$dir; done
+45
View File
@@ -0,0 +1,45 @@
CFLAGS=-Wall -Wextra -g -c -O0 -MD -std=gnu11
CFLAGS+=$(EXTRA_CFLAGS)
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)
ifeq ($(target),host)
EXEC=$(EXE)_h
endif
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
+21
View File
@@ -0,0 +1,21 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/app",
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerServerAddress": "192.168.0.14:1234",
"miDebuggerPath": "/buildroot/output/host/bin/aarch64-linux-gdb"
}
]
}
+14
View File
@@ -0,0 +1,14 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "gdbserver",
"type": "shell",
"command": [
"ssh -t root@192.168.0.14 '/usr/bin/gdbserver :1234",
"${workspaceFolder}/app'"]
}
]
}
@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.28)
project(backtrace)
include(../../nanopi.cmake)
add_executable(backtrace main.c)
+5
View File
@@ -0,0 +1,5 @@
EXE=app
SRCS=$(wildcard *.c)
# Include the standard application Makefile for the CSEL1 labs
include ../appl.mk
+5
View File
@@ -0,0 +1,5 @@
build:
cmake -S . -B build && cmake --build build
clean:
rm -rf build
+63
View File
@@ -0,0 +1,63 @@
/**
* Copyright 2015 University of Applied Sciences Western Switzerland / Fribourg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Module: MA-CSEL1 - Building Embedded Systems under Linux
*
* Abstract: Introduction to the Embedded Linux Development Environment
*
* Purpose: Backtracing demo program.
*
* Autĥor: Daniel Gachet
* Date: 28.08.2015
*/
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <unistd.h>
#include <signal.h>
#define SIZE 1000
void signal_handler(int __attribute__((unused)) sig)
{
void* buffer[SIZE];
int nptrs = backtrace(buffer, SIZE);
printf("backtrace() returned %d addresses\n", nptrs);
backtrace_symbols_fd (buffer, nptrs, STDOUT_FILENO);
exit(EXIT_FAILURE);
}
void access_data()
{
int* p=0;
*p=10;
}
void call (int n)
{
if (n>0) call (n-1);
access_data();
}
int main ()
{
signal(SIGSEGV, signal_handler); // Invalid memory segment access
call(10);
return 0;
}
+32
View File
@@ -0,0 +1,32 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/app",
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerServerAddress": "192.168.0.14:1234",
"miDebuggerPath": "/buildroot/output/host/bin/aarch64-linux-gdb"
},
{
"name": "(gdb) debug Core Dumped",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/app",
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "/buildroot/output/host/bin/aarch64-linux-gdb",
"coreDumpPath": "${workspaceFolder}/core"
}
]
}
+14
View File
@@ -0,0 +1,14 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "gdbserver",
"type": "shell",
"command": [
"ssh -t root@192.168.0.14 '/usr/bin/gdbserver :1234",
"${workspaceFolder}/app'"]
}
]
}
@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.28)
project(core-dumps)
include(../../nanopi.cmake)
add_executable(core-dumps core_dumps.c)
+5
View File
@@ -0,0 +1,5 @@
EXE=app
SRCS=$(wildcard *.c)
# Include the standard application Makefile for the CSEL1 labs
include ../appl.mk
@@ -0,0 +1,45 @@
/**
* Copyright 2015 University of Applied Sciences Western Switzerland / Fribourg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Module: MA-CSEL1 - Building Embedded Systems under Linux
*
* Abstract: Introduction to the Embedded Linux Development Environment
*
* Purpose: Core dump demo program.
* Before to call this demo program don't forget set
* $ ulimit -c 10000
*
* Autĥor: Daniel Gachet
* Date: 28.08.2015
*/
void access_data()
{
int* p=0;
*p=10;
}
void call (int n)
{
if (n>0) call (n-1);
access_data();
}
int main ()
{
call(10);
return 0;
}
+5
View File
@@ -0,0 +1,5 @@
build:
cmake -S . -B build && cmake --build build
clean:
rm -rf build
+21
View File
@@ -0,0 +1,21 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/app",
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerServerAddress": "192.168.0.14:1234",
"miDebuggerPath": "/buildroot/output/host/bin/aarch64-linux-gdb"
}
]
}
+14
View File
@@ -0,0 +1,14 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "gdbserver",
"type": "shell",
"command": [
"ssh -t root@192.168.0.14 '/usr/bin/gdbserver :1234",
"${workspaceFolder}/app'"]
}
]
}
+5
View File
@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.28)
project(daemon)
include(../../nanopi.cmake)
add_executable(daemon daemon.c)
+5
View File
@@ -0,0 +1,5 @@
EXE=app
SRCS=$(wildcard *.c)
# Include the standard application Makefile for the CSEL1 labs
include ../appl.mk
+24
View File
@@ -0,0 +1,24 @@
#!/bin/sh
#
# Daemon application
#
case "$1" in
start)
/usr/local/app_a
;;
stop)
killall app_a
;;
restart|reload)
killall app_a
/usr/local/app_a
;;
*)
echo $"Usage: $0 {start|stop|restart}"
exit 1
esac
echo "Daemon application launched"
exit $?
+152
View File
@@ -0,0 +1,152 @@
/**
* Copyright 2015 University of Applied Sciences Western Switzerland / Fribourg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Module: MA-CSEL1 - Building Embedded Systems under Linux
*
* Abstract: Introduction to the Embedded Linux Development Environment
*
* Purpose: This module implements a simple daemon to be launched
* from a /etc/init.d/S??_* script
*
* Autĥor: Daniel Gachet
* Date: 28.08.2015
*/
#define _XOPEN_SOURCE 600
#define _DEFAULT_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>
#include <signal.h>
#include <syslog.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define UNUSED(x) (void)(x)
static int signal_catched = 0;
static void catch_signal (int signal)
{
syslog (LOG_INFO, "signal=%d catched\n", signal);
signal_catched++;
}
static void fork_process()
{
pid_t pid = fork();
switch (pid) {
case 0: break; // child process has been created
case -1: syslog (LOG_ERR, "ERROR while forking"); exit (1); break;
default: exit(0); // exit parent process with success
}
}
int main(int argc, char* argv[])
{
UNUSED(argc); UNUSED(argv);
// 1. fork off the parent process
fork_process();
// 2. create new session
if (setsid() == -1) {
syslog (LOG_ERR, "ERROR while creating new session");
exit (1);
}
// 3. fork again to get rid of session leading process
fork_process();
// 4. capture all required signals
struct sigaction act = {.sa_handler = catch_signal,};
sigaction (SIGHUP, &act, NULL); // 1 - hangup
sigaction (SIGINT, &act, NULL); // 2 - terminal interrupt
sigaction (SIGQUIT, &act, NULL); // 3 - terminal quit
sigaction (SIGABRT, &act, NULL); // 6 - abort
sigaction (SIGTERM, &act, NULL); // 15 - termination
sigaction (SIGTSTP, &act, NULL); // 19 - terminal stop signal
// 5. update file mode creation mask
umask(0027);
// 6. change working directory to appropriate place
if (chdir ("/") == -1) {
syslog (LOG_ERR, "ERROR while changing to working directory");
exit (1);
}
// 7. close all open file descriptors
for (int fd = sysconf(_SC_OPEN_MAX); fd >= 0; fd--) {
close (fd);
}
// 8. redirect stdin, stdout and stderr to /dev/null
if (open ("/dev/null", O_RDWR) != STDIN_FILENO) {
syslog (LOG_ERR, "ERROR while opening '/dev/null' for stdin");
exit (1);
}
if (dup2 (STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO) {
syslog (LOG_ERR, "ERROR while opening '/dev/null' for stdout");
exit (1);
}
if (dup2 (STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) {
syslog (LOG_ERR, "ERROR while opening '/dev/null' for stderr");
exit (1);
}
// 9. option: open syslog for message logging
openlog (NULL, LOG_NDELAY | LOG_PID, LOG_DAEMON);
syslog (LOG_INFO, "Daemon has started...");
// 10. option: get effective user and group id for appropriate's one
struct passwd* pwd = getpwnam ("daemon");
if (pwd == 0) {
syslog (LOG_ERR, "ERROR while reading daemon password file entry");
exit (1);
}
// 11. option: change root directory
if (chroot (".") == -1) {
syslog (LOG_ERR, "ERROR while changing to new root directory");
exit (1);
}
// 12. option: change effective user and group id for appropriate's one
if (setegid (pwd->pw_gid) == -1) {
syslog (LOG_ERR, "ERROR while setting new effective group id");
exit (1);
}
if (seteuid (pwd->pw_uid) == -1) {
syslog (LOG_ERR, "ERROR while setting new effective user id");
exit (1);
}
// 13. implement daemon body...
int t = 30;
do {
t = sleep(t);
} while (t > 0);
syslog (LOG_INFO, "daemon stopped. Number of signals catched=%d\n", signal_catched);
closelog();
return 0;
}
+5
View File
@@ -0,0 +1,5 @@
build:
cmake -S . -B build && cmake --build build
clean:
rm -rf build
+24
View File
@@ -0,0 +1,24 @@
set -o errexit
set -o pipefail
set -o nounset
# set -o xtrace
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
__root="$(cd "$(dirname "${__dir}")" && pwd)"
targets="""
backtrace
core_dumps
daemon
fibonacci
memory_leaks
process
system_calls
tracing
"""
for i in $targets; do
mkdir -p $__root/$i/.vscode
cp $__dir/launch.json $__root/$i/.vscode
cp $__dir/tasks.json $__root/$i/.vscode
done
+21
View File
@@ -0,0 +1,21 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/app",
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerServerAddress": "192.168.0.14:1234",
"miDebuggerPath": "/buildroot/output/host/bin/aarch64-linux-gdb"
}
]
}
@@ -0,0 +1,43 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "app",
"args": [
"2"
],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
// "miDebuggerServerAddress": "192.168.0.14:1234",
// "miDebuggerPath": "/buildroot/output/host/bin/aarch64-linux-gdb",
"pipeTransport": {
// "pipeCwd": "/usr/bin",
"pipeProgram": "/usr/bin/ssh",
"pipeArgs": [
"root@192.168.0.14"
],
"debuggerPath": "/usr/bin/gdb"
// "debuggerPath": "stdbuf -i0 -o0 -e0 /usr/bin/gdb"
},
// "logging": {
// "engineLogging": true,
// },
}
]
}
+14
View File
@@ -0,0 +1,14 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "gdbserver",
"type": "shell",
"command": [
"ssh -t root@192.168.0.14 '/usr/bin/gdbserver :1234",
"${workspaceFolder}/app'"]
}
]
}
+1
View File
@@ -0,0 +1 @@
fibonacci
+21
View File
@@ -0,0 +1,21 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/app",
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerServerAddress": "192.168.0.14:1234",
"miDebuggerPath": "/buildroot/output/host/bin/aarch64-linux-gdb"
}
]
}
+14
View File
@@ -0,0 +1,14 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "gdbserver",
"type": "shell",
"command": [
"ssh -t root@192.168.0.14 '/usr/bin/gdbserver :1234",
"${workspaceFolder}/app 2'"]
}
]
}
@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.28)
project(fibonacci)
include(../../nanopi.cmake)
add_executable(fibonacci fibonacci.c)
+5
View File
@@ -0,0 +1,5 @@
EXE=app
SRCS=$(wildcard *.c)
# Include the standard application Makefile for the CSEL1 labs
include ../appl.mk
+88
View File
@@ -0,0 +1,88 @@
/**
* Copyright 2015 University of Applied Sciences Western Switzerland / Fribourg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Module: MA-CSEL1 - Building Embedded Systems under Linux
*
* Abstract: Introduction to the Embedded Linux Development Environment
*
* Purpose: Fibonacci numbers: a simple demo program to exercice debugging
* facilities on embedded Linux system.
*
* -->> tracing with printf
*
* Autĥor: Daniel Gachet
* Date: 28.08.2015
*/
#include <stdio.h>
#include <stdlib.h>
/**
* The Fibonacci numbers form a sequence of integers, mathematically defined by
* F(0)=0; F(1)=1; F(n) = F(n - 1) + F(n - 2) for n > 1.
*
* This results in the following sequence of numbers: 0, 1, 1, 2, 3, 5, 8, 13,
* 21, 34, 55, 89, 144, 233, 377, 610, 987, ...
* so that each new number is the sum of the previous two, after seeding the
* sequence with the starting pair 0, 1.
*
* @param n value for which the Fibonacci number should be computed
* @return Fibonacci number
*/
long fibonacci_r(long n)
{
if (n <= 1)
return n;
return fibonacci_r(n - 1) + fibonacci_r(n - 2);
}
long fibonacci_i(long n)
{
long f0 = 0;
long f1 = 1;
while (n > 0)
{
f1 = f1 + f0;
f0 = f1 - f0; // WAT !!!
n--;
}
return f0;
}
/**
* Main program computing the Fibonacci numbers for a given sequence starting
* from 0 to a number specified at the command line.
*/
int main(int argc, char **argv)
{
long n = 0;
long i = 0;
if (argc == 2)
{
n = atol(argv[1]);
}
printf("%s, %d, %s, %s\n", __FILE__, __LINE__, __DATE__, __TIME__);
printf("The first %ld Fibonacci numbers are:\n", n);
for (i = 0; i < n; i++)
{
printf("%ld%s", fibonacci_i(i), i < n-1 ? ", " : "");
}
printf("\n");
return 0;
}
+5
View File
@@ -0,0 +1,5 @@
build:
cmake -S . -B build && cmake --build build
clean:
rm -rf build
+9
View File
@@ -0,0 +1,9 @@
build-all:
#!/bin/bash
for i in $(dirname */CMAkeLists.txt); do
cd $i && just build && cd ..
done
clean-all:
rm -Rf */build
+21
View File
@@ -0,0 +1,21 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/app",
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerServerAddress": "192.168.0.14:1234",
"miDebuggerPath": "/buildroot/output/host/bin/aarch64-linux-gdb"
}
]
}
+14
View File
@@ -0,0 +1,14 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "gdbserver",
"type": "shell",
"command": [
"ssh -t root@192.168.0.14 '/usr/bin/gdbserver :1234",
"${workspaceFolder}/app'"]
}
]
}
@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.28)
project(memory-leaks)
include(../../nanopi.cmake)
add_executable(memory-leaks mem_leaks.c)
+5
View File
@@ -0,0 +1,5 @@
EXE=app
SRCS=$(wildcard *.c)
# Include the standard application Makefile for the CSEL1 labs
include ../appl.mk
+5
View File
@@ -0,0 +1,5 @@
build:
cmake -S . -B build && cmake --build build
clean:
rm -rf build
+113
View File
@@ -0,0 +1,113 @@
/**
* Copyright 2015 University of Applied Sciences Western Switzerland / Fribourg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Module: MA-CSEL1 - Building Embedded Systems under Linux
*
* Abstract: Introduction to the Embedded Linux Development Environment
*
* Purpose: Memory leak demo program
* call this demo program with
* $ valgrind --leak-check=full ./app_a
*
* Autĥor: Daniel Gachet
* Date: 28.08.2015
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#ifdef DEBUG
#define TRACE(x) printf x
#else
#define TRACE(x)
#endif
struct alpha
{
int attr;
struct alpha* next;
};
void alloc1 (struct alpha** root)
{
static int cnt=0;
struct alpha* ele = malloc (sizeof(*ele));
ele->next = 0;
ele->attr = cnt++;
if (*root == 0) {
*root = ele;
} else {
struct alpha* n = *root;
while (n->next != 0) n = n->next;
n->next = ele;
}
}
void alloc2(struct alpha** root)
{
static int cnt=0;
struct alpha* ele = malloc (sizeof(*ele));
ele->next = 0;
ele->attr = cnt++;
if (*root == 0) {
*root = ele;
} else {
struct alpha* n = *root;
while (n->next != 0) n = n->next;
n->next = ele;
}
}
void alloc(struct alpha** root)
{
static int x=0;
if (x == 0) alloc1(root);
else alloc2 (root);
x = (x + 1) % 2;
}
void dealloc(struct alpha** root)
{
struct alpha* ele = *root;
if (*root != 0) *root = ele->next;
free (ele);
}
int main ()
{
struct alpha* root = 0;
for (int i=0; i<4000; i++) alloc (&root);
struct alpha* p = root;
int i = 0;
while (p != 0) {
TRACE (("ele %2d, attr=%2d, ptr=%p\n", i, p->attr, p));
p = p->next;
i++;
}
for (int i=0; i<15; i++) dealloc (&root);
return 0;
}
+21
View File
@@ -0,0 +1,21 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/app",
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerServerAddress": "192.168.0.14:1234",
"miDebuggerPath": "/buildroot/output/host/bin/aarch64-linux-gdb"
}
]
}
+14
View File
@@ -0,0 +1,14 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "gdbserver",
"type": "shell",
"command": [
"ssh -t root@192.168.0.14 '/usr/bin/gdbserver :1234",
"${workspaceFolder}/app'"]
}
]
}
@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.28)
project(process)
include(../../nanopi.cmake)
add_executable(process process.c)
+5
View File
@@ -0,0 +1,5 @@
EXE=app
SRCS=$(wildcard *.c)
# Include the standard application Makefile for the CSEL1 labs
include ../appl.mk
+5
View File
@@ -0,0 +1,5 @@
build:
cmake -S . -B build && cmake --build build
clean:
rm -rf build
+133
View File
@@ -0,0 +1,133 @@
/**
* Copyright 2015 University of Applied Sciences Western Switzerland / Fribourg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Module: MA-CSEL1 - Building Embedded Systems under Linux
*
* Abstract: Introduction to the Embedded Linux Development Environment
*
* Purpose: This module implements a simple application to be launched from
* /etc/inttab.
* -->> tracing with syslog
*
* Autĥor: Daniel Gachet
* Date: 28.08.2015
*/
#define _XOPEN_SOURCE 600
#define _DEFAULT_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>
#include <signal.h>
#include <syslog.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define UNUSED(x) (void)(x)
static int signal_catched = 0;
static void catch_signal (int signal)
{
syslog (LOG_INFO, "signal=%d catched\n", signal);
signal_catched++;
}
int main(int argc, char* argv[])
{
UNUSED(argc); UNUSED(argv);
// daemon's steps 1 to 3 skipt
// 4. capture all required signals
struct sigaction act = {.sa_handler = catch_signal,};
sigaction (SIGHUP, &act, NULL); // 1 - hangup
sigaction (SIGINT, &act, NULL); // 2 - terminal interrupt
sigaction (SIGQUIT, &act, NULL); // 3 - terminal quit
sigaction (SIGABRT, &act, NULL); // 6 - abort
sigaction (SIGTERM, &act, NULL); // 15 - termination
sigaction (SIGTSTP, &act, NULL); // 19 - terminal stop signal
// 5. update file mode creation mask
umask(0027);
// 6. change working directory to appropriate place
if (chdir ("/") == -1) {
syslog (LOG_ERR, "ERROR while changing to working directory");
exit (1);
}
// 7. close all open file descriptors
for (int fd = sysconf(_SC_OPEN_MAX); fd >= 0; fd--) {
close (fd);
}
// 8. redirect stdin, stdout and stderr to /dev/null
if (open ("/dev/null", O_RDWR) != STDIN_FILENO) {
syslog (LOG_ERR, "ERROR while opening '/dev/null' for stdin");
exit (1);
}
if (dup2 (STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO) {
syslog (LOG_ERR, "ERROR while opening '/dev/null' for stdout");
exit (1);
}
if (dup2 (STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) {
syslog (LOG_ERR, "ERROR while opening '/dev/null' for stderr");
exit (1);
}
// 9. option: open syslog for message logging
openlog (NULL, LOG_NDELAY | LOG_PID, LOG_DAEMON);
syslog (LOG_INFO, "Daemon has started...");
// 10. option: get effective user and group id for appropriate's one
struct passwd* pwd = getpwnam ("daemon");
if (pwd == 0) {
syslog (LOG_ERR, "ERROR while reading daemon password file entry");
exit (1);
}
// 11. option: change root directory
if (chroot (".") == -1) {
syslog (LOG_ERR, "ERROR while changing to new root directory");
exit (1);
}
// 12. option: change effective user and group id for appropriate's one
if (setegid (pwd->pw_gid) == -1) {
syslog (LOG_ERR, "ERROR while setting new effective group id");
exit (1);
}
if (seteuid (pwd->pw_uid) == -1) {
syslog (LOG_ERR, "ERROR while setting new effective user id");
exit (1);
}
// 13. implement daemon body...
int t = 30;
do {
t = sleep(t);
} while (t > 0);
syslog (LOG_INFO, "daemon stopped. Number of signals catched=%d\n", signal_catched);
closelog();
return 0;
}
+21
View File
@@ -0,0 +1,21 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/app",
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerServerAddress": "192.168.0.14:1234",
"miDebuggerPath": "/buildroot/output/host/bin/aarch64-linux-gdb"
}
]
}
+14
View File
@@ -0,0 +1,14 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "gdbserver",
"type": "shell",
"command": [
"ssh -t root@192.168.0.14 '/usr/bin/gdbserver :1234",
"${workspaceFolder}/app'"]
}
]
}
@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.28)
project("system-calls")
include(../../nanopi.cmake)
add_executable("system-calls" syscall.c)
+5
View File
@@ -0,0 +1,5 @@
EXE=app
SRCS=$(wildcard *.c)
# Include the standard application Makefile for the CSEL1 labs
include ../appl.mk
+5
View File
@@ -0,0 +1,5 @@
build:
cmake -S . -B build && cmake --build build
clean:
rm -rf build
+58
View File
@@ -0,0 +1,58 @@
/**
* Copyright 2015 University of Applied Sciences Western Switzerland / Fribourg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Module: MA-CSEL1 - Building Embedded Systems under Linux
*
* Abstract: Introduction to the Embedded Linux Development Environment
*
* Purpose: System call demo program
* call this demo program with
* # strace ./app_a
*
* Autĥor: Daniel Gachet
* Date: 28.08.2015
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <libgen.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int temp = 99000;
int f = open("/sys/class/thermal/thermal_zone0/temp", O_RDONLY);
if (f >= 0) {
char val[50] = "";
ssize_t r = read (f, val, sizeof(val));
close (f);
if (r > 0) {
temp = atoi(val);
}
}
printf ("current temperature: %d.%02d degree Celcius\n",
temp/1000, (temp/10)%100);
return 0;
}
+21
View File
@@ -0,0 +1,21 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/app",
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerServerAddress": "192.168.0.14:1234",
"miDebuggerPath": "/buildroot/output/host/bin/aarch64-linux-gdb"
}
]
}
+14
View File
@@ -0,0 +1,14 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "gdbserver",
"type": "shell",
"command": [
"ssh -t root@192.168.0.14 '/usr/bin/gdbserver :1234",
"${workspaceFolder}/app'"]
}
]
}
@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.28)
project(tracing)
include(../../nanopi.cmake)
add_executable(fibonacci fibonacci.c)
add_executable(fibonacci-debug fibonacci.c)
target_compile_definitions(fibonacci-debug PRIVATE DEBUG)
+9
View File
@@ -0,0 +1,9 @@
EXE=app
SRCS=$(wildcard *.c)
ifneq ($(DEBUG),)
EXTRA_CFLAGS+=-DDEBUG
endif
# Include the standard application Makefile for the CSEL1 labs
include ../appl.mk
+79
View File
@@ -0,0 +1,79 @@
/**
* Copyright 2015 University of Applied Sciences Western Switzerland / Fribourg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Module: MA-CSEL1 - Building Embedded Systems under Linux
*
* Abstract: Introduction to the Embedded Linux Development Environment
*
* Purpose: Fibonacci numbers: a simple demo program to exercice debugging
* facilities on embedded Linux system.
*
* -->> tracing with conditional printf
*
* Autĥor: Daniel Gachet
* Date: 28.08.2015
*/
#include <stdio.h>
#include <stdlib.h>
#ifdef DEBUG
#define TRACE(x) printf x
#else
#define TRACE(X)
#endif
/**
* The Fibonacci numbers form a sequence of integers, mathematically defined by
* F(0)=0; F(1)=1; F(n) = F(n - 1) + F(n - 2) for n > 1.
*
* This results in the following sequence of numbers: 0, 1, 1, 2, 3, 5, 8, 13,
* 21, 34, 55, 89, 144, 233, 377, 610, 987, ...
* so that each new number is the sum of the previous two, after seeding the
* sequence with the starting pair 0, 1.
*
* @param n value for which the Fibonacci number should be computed
* @return Fibonacci number
*/
long fibonacci(long n)
{
if (n <= 1) return n;
return fibonacci(n-1)+fibonacci(n-2);
}
/**
* Main program computing the Fibonacci numbers for a given sequence starting
* from 0 to a number specified at the command line.
*/
int main (int argc, char** argv)
{
long n = 0;
long i = 0;
if (argc == 2) {
n = atol(argv[1]);
}
TRACE(("%s, %d, %s, %s\n", __FILE__, __LINE__, __DATE__, __TIME__));
printf("The first %ld Fibonacci numbers are:\n", n);
for (i=0; i<=n; i++) {
printf("%ld, ", fibonacci(i));
}
printf("\n");
return 0;
}
+5
View File
@@ -0,0 +1,5 @@
build:
cmake -S . -B build && cmake --build build
clean:
rm -rf build
+5
View File
@@ -0,0 +1,5 @@
DIRS=$(filter-out Makefile, $(wildcard *))
all clean install:
for dir in $(DIRS); do $(MAKE) $@ -C $$dir; done
+19
View File
@@ -0,0 +1,19 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"/buildroot/output/build/linux-5.15.148/include",
"/buildroot/output/build/linux-5.15.148/arch/arm64/include",
"/buildroot/output/build/linux-5.15.148/arch/arm64/include/generated"
],
"defines": [],
"compilerPath": "/usr/bin/clang",
"cStandard": "c99",
"cppStandard": "c++14",
"intelliSenseMode": "linux-clang-arm64"
}
],
"version": 4
}
+30
View 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
View 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");
+22
View 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 ../../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
+16
View 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
View 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");
+23
View 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
+83
View 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");
+24
View File
@@ -0,0 +1,24 @@
# 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
include ../../set_host_path
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
View 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");
+23
View 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
+81
View 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");
+23
View 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
+74
View 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
View 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
View 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
View File
@@ -0,0 +1,5 @@
DIRS=$(filter-out Makefile, $(wildcard *))
all clean install:
for dir in $(DIRS); do $(MAKE) $@ -C $$dir; done
+37
View 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
View 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
View File
@@ -0,0 +1,12 @@
/dts-v1/;
#include "allwinner/sun50i-h5-nanopi-neo-plus2.dts"
/ {
/delete-node/ leds;
mydevice {
compatible = "mydevice";
attribute = "text";
};
};
+135
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File
@@ -0,0 +1,13 @@
/dts-v1/;
#include "allwinner/sun50i-h5-nanopi-neo-plus2.dts"
/ {
/delete-node/ leds;
mydevice {
compatible = "mydevice";
attribute = "on";
};
};
+255
View 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
View File
@@ -0,0 +1,5 @@
DIRS=$(filter-out Makefile, $(wildcard *))
all clean install:
for dir in $(DIRS); do $(MAKE) $@ -C $$dir; done
Loaded 100 of 196 files, more files were not shown because too many files have changed in this diff. Show more