디바이스 드라이버에 대한 간단한 이론 지식은 아랫글의 중후반부에 있음
ubuntu@ubuntu8:~/pi_bsp/drivers/p106$ vi hello.c
/*모듈 소스 2.6(/base/test.c)*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int hello_init(void)
{
printk("Hello, world \n");
return 0;
}
static void hello_exit(void)
{
printk("GoodBye, world \n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("Dual BSD/GPL");
Makefile
MOD := hello
obj-m := $(MOD).o
CROSS = ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
#KDIR := /lib/modules/$(shell uname -r)/build
KDIR := /home/ubuntu/pi_bsp/kernel/linux
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules $(CROSS)
cp $(MOD).ko /srv/nfs
clean:
rm -rf *.ko
rm -rf *.mod.*
rm -rf .*.cmd
rm -rf *.o
rm -rf modules.order
rm -rf Module.symvers
rm -rf $(MOD).mod
rm -rf .tmp_versions
KDIR이 커널 디렉터리
ubuntu@ubuntu8:~/pi_bsp/drivers/p106$ make
파이로 복사해주고
ubuntu@ubuntu8:~/pi_bsp/drivers/p106$ cp hello.ko /srv/nfs/
파이로 넘어와서
pi@pi08:/mnt/ubuntu_nfs $ ls -l hello.ko
-rw-rw-r-- 1 pi pi 4364 Feb 21 15:07 hello.ko
pi@pi08:/mnt/ubuntu_nfs $ file hello.ko
hello.ko: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), BuildID[sha1]=2d1e26330e265b4647a778ed176d4cdbd4cccb77, not stripped
실행파일이 아니므로 relocatable로 나옴 커널에 적재되어 호출된 후 메모리에 재배치후 실행되는 파일.
pi@pi08:/mnt/ubuntu_nfs $ lsmod | wc -l
84
84가 아니라면 다시해..난 62야..
pi@pi08:/mnt/ubuntu_nfs $ sudo insmod hello.ko
모듈을 동적으로 커널에 적재하겠다는 뜻이고
pi@pi08:/mnt/ubuntu_nfs $ lsmod | wc -l
63
최상단에 hello 올라가있음.
pi@pi08:/mnt/ubuntu_nfs $ lsmod |more
Module Size Used by
hello 16384 0
dmesg하면 커널 메시지 나오는데 Hello, World 찍혀있죠?
pi@pi08:/mnt/ubuntu_nfs $ dmesg
[15293.495454] Hello, world
커널에서 동적으로 내릴 때는 .ko 생략가능함.
pi@pi08:/mnt/ubuntu_nfs $ sudo rmmod hello
[15463.941997] GoodBye, world
pi@pi08:/mnt/ubuntu_nfs $ dmesg
다 됬쥬~?
그럼 응용 실습해봅싀다~
ubuntu@ubuntu8:~/pi_bsp/drivers/p106$ make clean
ubuntu@ubuntu8:~/pi_bsp/drivers/p106$ ls
Makefile hello.c
해서 make로 생성된 파일들 지워주고
그대로 복사해서 다른 폴더로 복사해주겠으
led 버튼 제어하는 이전에 사용한 코드
#include <linux/kernel.h>
#include <linux/gpio.h>
#define OFF 0
#define ON 1
#define GPIOLEDCNT 8
#define GPIOKEYCNT 8
int gpioLed[GPIOLEDCNT] = {6,7,8,9,10,11,12,13};
int gpioKey[GPIOKEYCNT] = {16,17,18,19,20,21,22,23};
int gpioLedInit(void);
void gpioLedSet(long);
void gpioLedFree(void);
int gpioKeyInit(void);
int gpioKeyGet(void);
void gpioKeyFree(void);
asmlinkage long sys_mysyscall(long val)
{
// printk(KERN_INFO "Welcome to KCCI's Embedded System!! app value=%ld\n",val);
int ret;
ret=gpioLedInit();
if(ret < 0)
return ret;
gpioLedSet(val);
gpioLedFree();
ret=gpioKeyInit();
if(ret < 0)
return ret;
ret=gpioKeyGet();
gpioKeyFree();
return ret;
}
int gpioLedInit(void)
{
int i;
int ret=0;
char gpioName[10];
for(i=0;i<GPIOLEDCNT;i++)
{
sprintf(gpioName,"led%d",i);
ret = gpio_request(gpioLed[i],gpioName);
if(ret < 0) {
printk("Failed gpio_request() gpio%d error \n",i);
return ret;
}
ret = gpio_direction_output(gpioLed[i],OFF);
if(ret < 0) {
printk("Failed gpio_direction_output() gpio%d error \n",i);
return ret;
}
}
return ret;
}
void gpioLedSet(long val)
{
int i;
for(i=0;i<GPIOLEDCNT;i++)
{
gpio_set_value(gpioLed[i],(val>>i) & 0x1);
}
}
void gpioLedFree(void)
{
int i;
for(i=0;i<GPIOLEDCNT;i++)
{
gpio_free(gpioLed[i]);
}
}
int gpioKeyInit(void)
{
int i;
int ret=0;
char gpioName[10];
for(i=0;i<GPIOKEYCNT;i++)
{
sprintf(gpioName,"key%d",gpioKey[i]);
ret = gpio_request(gpioKey[i], gpioName);
if(ret < 0) {
printk("Failed Request gpio%d error\n", 6);
return ret;
}
}
for(i=0;i<GPIOKEYCNT;i++)
{
ret = gpio_direction_input(gpioKey[i]);
if(ret < 0) {
printk("Failed direction_output gpio%d error\n", 6);
return ret;
}
}
return ret;
}
int gpioKeyGet(void)
{
int i;
int ret;
int keyData=0;
for(i=0;i<GPIOKEYCNT;i++)
{
// ret=gpio_get_value(gpioKey[i]) << i;
// keyData |= ret;
ret=gpio_get_value(gpioKey[i]);
keyData = keyData | ( ret << i );
}
return keyData;
}
void gpioKeyFree(void)
{
int i;
for(i=0;i<GPIOKEYCNT;i++)
{
gpio_free(gpioKey[i]);
}
}
파일이름 led.c로
Makefile 내용 수정해주고 led를 make하겠다.라는 뜻임
ubuntu@ubuntu8:~/pi_bsp/drivers/p106_led$ vi Makefile
1 MOD := led
커널에 동적으로 로드 될 때 led 8개 켜지고
커널에 동적으로 내릴 때 led 8개 꺼지도록
코드를 작성해봅시다~
ubuntu@ubuntu8:~/pi_bsp/drivers/p106_led$ vi test_mysyscall.c
test_mysyscall.c의 36번부터 끝까지 복사하고 싶으니, 열어주고 vi에서
:36,$w gpio.txt
36번라인부터 $끝까지 write하겠다. gpio.txt파일로
자 그럼 led.c로 가서 붙여넣고 싶은 위치로 이동 후 :r gpio.txt 하면 현재 커서 뒤로 쭉 붙여넣기 됨.
ubuntu@ubuntu8:~/pi_bsp/drivers/p106_led$ cat led.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#define OFF 0
#define ON 1
#define GPIOLEDCNT 8
#define GPIOKEYCNT 8
static int gpioLed[GPIOLEDCNT] = {6,7,8,9,10,11,12,13};
static int gpioKey[GPIOKEYCNT] = {16,17,18,19,20,21,22,23};
static int gpioLedInit(void);
static void gpioLedSet(long);
static void gpioLedFree(void);
static int gpioKeyInit(void);
static int gpioKeyGet(void);
static void gpioKeyFree(void);
static int gpioLedInit(void)
{
int i;
int ret=0;
char gpioName[10];
for(i=0;i<GPIOLEDCNT;i++)
{
sprintf(gpioName,"led%d",i);
ret = gpio_request(gpioLed[i],gpioName);
if(ret < 0) {
printk("Failed gpio_request() gpio%d error \n",i);
return ret;
}
ret = gpio_direction_output(gpioLed[i],OFF);
if(ret < 0) {
printk("Failed gpio_direction_output() gpio%d error \n",i);
return ret;
}
}
return ret;
}
static void gpioLedSet(long val)
{
int i;
for(i=0;i<GPIOLEDCNT;i++)
{
gpio_set_value(gpioLed[i],(val>>i) & 0x1);
}
}
static void gpioLedFree(void)
{
int i;
for(i=0;i<GPIOLEDCNT;i++)
{
gpio_free(gpioLed[i]);
}
}
static int gpioKeyInit(void)
{
int i;
int ret=0;
char gpioName[10];
for(i=0;i<GPIOKEYCNT;i++)
{
sprintf(gpioName,"key%d",gpioKey[i]);
ret = gpio_request(gpioKey[i], gpioName);
if(ret < 0) {
printk("Failed Request gpio%d error\n", 6);
return ret;
}
}
for(i=0;i<GPIOKEYCNT;i++)
{
ret = gpio_direction_input(gpioKey[i]);
if(ret < 0) {
printk("Failed direction_output gpio%d error\n", 6);
return ret;
}
}
return ret;
}
static int gpioKeyGet(void)
{
int i;
int ret;
int keyData=0;
for(i=0;i<GPIOKEYCNT;i++)
{
// ret=gpio_get_value(gpioKey[i]) << i;
// keyData |= ret;
ret=gpio_get_value(gpioKey[i]);
keyData = keyData | ( ret << i );
}
return keyData;
}
static void gpioKeyFree(void)
{
int i;
for(i=0;i<GPIOKEYCNT;i++)
{
gpio_free(gpioKey[i]);
}
}
static int hello_init(void)
{
int ret;
printk("Hello, world \n");
ret=gpioLedInit();
if(ret < 0)
return ret;
gpioLedSet(0xff);
printk("led all on \n");
return 0;
}
static void hello_exit(void)
{
printk("Goodbye, world \n");
gpioLedSet(0x00);
printk("led all off \n");
gpioLedFree();
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("Dual BSD/GPL");
커널에 동적으로 로드 될 때 led 8개 켜지고
커널에 동적으로 내릴 때 led 8개 꺼지죠?
자 이제 커널에 올릴 때 led 다 켜지고
버튼을 누를경우 해당 버튼에 해당되는 led만 켜지도록 수정
커널 내릴 때 led 다 꺼지게 만들어 보자
아래 코드를 윗 코드랑 합쳐서 만들자~
#include <common.h>
#include <command.h>
#include <asm/io.h>
#define BCM2711_GPIO_GPFSEL0 0xFE200000
#define BCM2711_GPIO_GPFSEL1 0xFE200004
#define BCM2711_GPIO_GPFSEL2 0xFE200008
#define BCM2711_GPIO_GPSET0 0xFE20001C
#define BCM2711_GPIO_GPCLR0 0xFE200028
#define BCM2711_GPIO_GPLEV0 0xFE200034
#define GPIO6_9_SIG_OUTPUT 0x09240000
#define GPIO10_13_SIG_OUTPUT 0x00000249
struct cmd_tbl_t;
void led_init(void)
{
unsigned long temp;
temp = readl(BCM2711_GPIO_GPFSEL0);
temp = temp & 0x0003ffff;
// temp = temp & ~0xfffc0000;
temp = temp | GPIO6_9_SIG_OUTPUT;
writel(temp,BCM2711_GPIO_GPFSEL0);
// writel(GPIO6_9_SIG_OUTPUT,BCM2711_GPIO_GPFSEL0);
temp = readl(BCM2711_GPIO_GPFSEL1); //gpio10~13 read
temp = temp & 0x3ffff000; //gpio10~13 clear
temp = temp | GPIO10_13_SIG_OUTPUT;//gpio10~13 output
writel(temp,BCM2711_GPIO_GPFSEL1); //gpio10~13 write
// writel(GPIO10_13_SIG_OUTPUT,BCM2711_GPIO_GPFSEL1);
}
void led_write(unsigned long led_data)
{
writel(0x3fc0,BCM2711_GPIO_GPCLR0); //led all off
led_data = led_data << 6;
writel(led_data,BCM2711_GPIO_GPSET0); //ledX on
}
void key_init(void)
{
unsigned long temp;
temp = readl(BCM2711_GPIO_GPFSEL1);
temp = temp & 0x0003ffff; //gpio16~20 input
writel(temp,BCM2711_GPIO_GPFSEL1);
temp = readl(BCM2711_GPIO_GPFSEL2);
temp = temp & 0x3ffff000; //gpio21~23 input
writel(temp,BCM2711_GPIO_GPFSEL2);
}
void key_read(unsigned long * key_data)
{
*key_data =(readl(BCM2711_GPIO_GPLEV0) >> 16) & 0x000000ff;
}
static int do_KCCI_LED(struct cmd_tbl *cmdtp,int flag, int argc, char * const argv[])
{
unsigned long led_data;
unsigned long key_data;
unsigned long key_data_old=0;
unsigned long i;
if(argc != 2)
{
cmd_usage(cmdtp);
return 1;
}
printf("*LED TEST START\n");
led_init();
led_data = simple_strtoul(argv[1],NULL,16);
led_write(led_data);
key_init();
do {
key_read(&key_data);
if(key_data != key_data_old)
{
if(key_data)
{
led_write(key_data);
puts("0:1:2:3:4:5:6:7\n");
for(i=0;i<8;i++)
{
if(key_data & (0x01 << i))
putc('O');
else
putc('X');
if(i !=7 )
putc(':');
else
putc('\n');
}
putc('\n');
}
key_data_old = key_data;
if (key_data == 0x80)
break;
}
} while(1);
printf("*LED TEST END(%s : %#04x)\n\n ",argv[0],(unsigned int)key_data);
return 0;
}
U_BOOT_CMD(
led,2,0,do_KCCI_LED,
"led - kcci LED Test.",
"number - Input argument is only one.(led [0x00~0xff])\n");
Makefile
MOD := ledkey
ledkey.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#define OFF 0
#define ON 1
#define GPIOLEDCNT 8
#define GPIOKEYCNT 8
static int gpioLed[GPIOLEDCNT] = {6,7,8,9,10,11,12,13};
static int gpioKey[GPIOKEYCNT] = {16,17,18,19,20,21,22,23};
static int gpioLedInit(void);
static void gpioLedSet(long);
static void gpioLedFree(void);
static int gpioKeyInit(void);
static unsigned long gpioKeyGet(void);
static void gpioKeyFree(void);
static int gpioLedInit(void)
{
int i;
int ret=0;
char gpioName[10];
for(i=0;i<GPIOLEDCNT;i++)
{
sprintf(gpioName,"led%d",i);
ret = gpio_request(gpioLed[i],gpioName);
if(ret < 0) {
printk("Failed gpio_request() gpio%d error \n",i);
return ret;
}
ret = gpio_direction_output(gpioLed[i],OFF);
if(ret < 0) {
printk("Failed gpio_direction_output() gpio%d error \n",i);
return ret;
}
}
return ret;
}
static void gpioLedSet(long val)
{
int i;
for(i=0;i<GPIOLEDCNT;i++)
{
gpio_set_value(gpioLed[i],(val>>i) & 0x1);
}
}
static void gpioLedFree(void)
{
int i;
for(i=0;i<GPIOLEDCNT;i++)
{
gpio_free(gpioLed[i]);
}
}
static int gpioKeyInit(void)
{
int i;
int ret=0;
char gpioName[10];
for(i=0;i<GPIOKEYCNT;i++)
{
sprintf(gpioName,"key%d",gpioKey[i]);
ret = gpio_request(gpioKey[i], gpioName);
if(ret < 0) {
printk("Failed Request gpio%d error\n", 6);
return ret;
}
}
for(i=0;i<GPIOKEYCNT;i++)
{
ret = gpio_direction_input(gpioKey[i]);
if(ret < 0) {
printk("Failed direction_output gpio%d error\n", 6);
return ret;
}
}
return ret;
}
static unsigned long gpioKeyGet(void)
{
int i;
int ret;
unsigned long keyData=0;
for(i=0;i<GPIOKEYCNT;i++)
{
// ret=gpio_get_value(gpioKey[i]) << i;
// keyData |= ret;
ret=gpio_get_value(gpioKey[i]);
keyData = keyData | ( ret << i );
}
return keyData;
}
static void gpioKeyFree(void)
{
int i;
for(i=0;i<GPIOKEYCNT;i++)
{
gpio_free(gpioKey[i]);
}
}
static int hello_init(void)
{
int ret;
unsigned long led_data;
unsigned long key_data;
unsigned long key_data_old=0;
unsigned long i;
int index =0;
printk("Hello, world \n");
ret=gpioLedInit();
if(ret < 0)
return ret;
gpioLedSet(0xff);
printk("led all on \n");
ret=gpioKeyInit();
if(ret < 0)
return ret;
do{
char printmsg[20];
key_data=gpioKeyGet();
if(key_data!=key_data_old)
{
if(key_data)
{
gpioLedSet(key_data);
printk("0:1:2:3:4:5:6:7\n");
for(i=0;i<8;i++)
{
if(key_data & (0x01 << i))
printmsg[index++]='O';
else
printmsg[index++]='X';
if(i !=7 )
printmsg[index++]=':';
}
printmsg[index]='\0';
printk("%s\n\n",printmsg);
index=0;
}
}
key_data_old = key_data;
if(key_data == 0x80)
break;
}while(1);
return 0;
}
static void hello_exit(void)
{
printk("Goodbye, world \n");
gpioLedSet(0x00);
printk("led all off \n");
gpioLedFree();
gpioKeyFree();
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("Dual BSD/GPL");
이렇게 하면 잘됨 b
하지만 좋은 코드는 아님.
커널 내부에서 무한 루프를 돌리게 되면 커널에 부하를 많이 주게 되므로,
다른 곳에서 커널 사용하는데 영향을 많이 미침.
순수하게 led와 key만 한번 제어해보자고 사용하는거임.
실제로는 이렇게 짜면 절대 안됨.
좀 더 펌웨어적으로 최적화된 코드
#include <linux/delay.h>
126 if(key_data!=key_data_old)
127 {
128 if(key_data)
129 {
130 mdelay(100);
mdelay를 추가해서 부하를 조금이라도 줄여주는거
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#define OFF 0
#define ON 1
#define GPIOLEDCNT 8
#define GPIOKEYCNT 8
static int gpioLed[GPIOLEDCNT] = {6,7,8,9,10,11,12,13};
static int gpioKey[GPIOKEYCNT] = {16,17,18,19,20,21,22,23};
static int gpioLedInit(void);
static void gpioLedSet(long);
static void gpioLedFree(void);
static int gpioKeyInit(void);
static int gpioKeyGet(void);
static void gpioKeyFree(void);
static int gpioLedInit(void)
{
int i;
int ret=0;
char gpioName[10];
for(i=0;i<GPIOLEDCNT;i++)
{
sprintf(gpioName,"led%d",i);
ret = gpio_request(gpioLed[i],gpioName);
if(ret < 0) {
printk("Failed gpio_request() gpio%d error \n",i);
return ret;
}
ret = gpio_direction_output(gpioLed[i],OFF);
if(ret < 0) {
printk("Failed gpio_direction_output() gpio%d error \n",i);
return ret;
}
}
return ret;
}
static void gpioLedSet(long val)
{
int i;
for(i=0;i<GPIOLEDCNT;i++)
{
gpio_set_value(gpioLed[i],(val>>i) & 0x1);
}
}
static void gpioLedFree(void)
{
int i;
for(i=0;i<GPIOLEDCNT;i++)
{
gpio_free(gpioLed[i]);
}
}
static int gpioKeyInit(void)
{
int i;
int ret=0;
char gpioName[10];
for(i=0;i<GPIOKEYCNT;i++)
{
sprintf(gpioName,"key%d",gpioKey[i]);
ret = gpio_request(gpioKey[i], gpioName);
if(ret < 0) {
printk("Failed Request gpio%d error\n", 6);
return ret;
}
}
for(i=0;i<GPIOKEYCNT;i++)
{
ret = gpio_direction_input(gpioKey[i]);
if(ret < 0) {
printk("Failed direction_output gpio%d error\n", 6);
return ret;
}
}
return ret;
}
static int gpioKeyGet(void)
{
int i;
int ret;
int keyData=0;
for(i=0;i<GPIOKEYCNT;i++)
{
// ret=gpio_get_value(gpioKey[i]) << i;
// keyData |= ret;
ret=gpio_get_value(gpioKey[i]);
keyData = keyData | ( ret << i );
}
return keyData;
}
static void gpioKeyFree(void)
{
int i;
for(i=0;i<GPIOKEYCNT;i++)
{
gpio_free(gpioKey[i]);
}
}
static int hello_init(void)
{
int ret, i;
int key_data;
int key_data_old = 0;
char ledStatus[16]=" : : : : : : : ";
printk("Hello, world \n");
ret=gpioLedInit();
if(ret < 0)
return ret;
ret=gpioKeyInit();
if(ret < 0)
return ret;
do {
// key_read(&key_data);
key_data = gpioKeyGet();
if(key_data != key_data_old)
{
if(key_data)
{
// led_write(key_data);
gpioLedSet(key_data);
printk("0:1:2:3:4:5:6:7\n");
for(i=0;i<8;i++)
{
if((key_data >> i) & 0x01)
ledStatus[i*2] = 'O';
// putc('O');
else
// putc('X');
ledStatus[i*2] = 'X';
}
// putc('\n');
printk("%s\n",ledStatus);
}
key_data_old = key_data;
if (key_data == 0x80)
break;
}
} while(1);
// gpioLedSet(0xff);
// printk("led all on \n");
return 0;
}
static void hello_exit(void)
{
printk("Goodbye, world \n");
gpioLedSet(0x00);
// printk("led all off \n");
gpioLedFree();
gpioKeyFree();
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("Dual BSD/GPL");
커널 메시지 확인 방법
1.
dmesg 하면 부팅하고 지금까지 쌓여있는게 한번에 다 출력됨. 쌓이면 출력하는데 1~2분 걸림
dmesg | grep welcome 이런식으로 찾는거도 가능하긴함.
2.
sudo cat /proc/kmsg 를 치면 버퍼에 있는 내용을 비워주면서 실시간으로 출력해줌 버퍼에서 비워지면 없어지므로 한번만 출력이 가능함. 최근 커널 메시지를 실시간으로 볼 때 유용함.
3.
apt에서 rsyslog 패키지를 설치하고
/var/log 디렉터리에서
tail -f kern.log를 치면 명령어를 실행할 때마다 실시간으로 확인이 가능하다.
최근 커널 메시지 확인만 하고 싶다면 아래 명령어 사용
pi@pi08:/var/log $ tail -5 kern.log를 쓰면 5개만 출력하고 끝남.
gets 와 fgets의 차이
gets는 문자열의 시작주소만 넘겨줌, \0이 있을 때 까지 출력하므로, Buffer Overflow 발생 가능성이 있음.
gets는 문자열의 시작주소와 읽을 주소와 문자열의 길이를 넘겨줌, 문자열의 길이만큼 출력하므로, Buffer Overflow 발생 가능성이 없음.
나중에 커널 부팅시에 프로그램을 실행하도록 하고 싶다면?
static int __hello_init(void)
static void __hello_exit(void)
이런식으로 init과 exit 함수 앞에 __를 붙여줘야함
insmod로 커널에 적재되어 있을 때 해당되는 파일이 몇번지를 사용하는지 알고 싶다면
sudo cat /proc/kallsyms |grep hello
몇번지에 로드되어 실행되는지 출력해준다.
pi@pi08:/lib/modules/6.1.77-v7l+ $ sudo cat /proc/kallsyms |grep hello
bf707040 t hello_init [ledkey]
bf7072cc t hello_exit [ledkey]
ubuntu@ubuntu8:~/pi_bsp/drivers/p106_ledkey$ vi ledkey.c
최하단 license 위에 추가해주자
164 MODULE_AUTHOR("WCM-device driver");
165 MODULE_DESCRIPTION("led key test module");
make 해주고나면
pi에서 modinfo로 ko파일의 내용을 확인 할 수 있음.
아까 작성했던 내용들이 여기에 출력됨.
pi@pi08:/mnt/ubuntu_nfs $ modinfo ledkey.ko
filename: /mnt/ubuntu_nfs/ledkey.ko
license: Dual BSD/GPL
description: led key test module
author: WCM-device driver
srcversion: 495D804C6E4FA94A3EB7292
depends:
name: ledkey
vermagic: 6.1.77-v7l+ SMP mod_unload modversions ARMv7 p2v8
'Linux BSP' 카테고리의 다른 글
[RaspberryPi DeviceDriver] 디바이스 드라이버 매개변수 명령어로 입력 받는 함수 만들기 (0) | 2024.02.22 |
---|---|
Makefile은 왜 사용하며, 어떻게 사용하는가 (2) | 2024.02.22 |
[RaspberryPi DeviceDriver] Yocto Project 설정 초기화 및 디바이스 파일 만들어보기 (0) | 2024.02.21 |
[Linux File System] Yocto Project 2 (0) | 2024.02.20 |
[Linux] fork()와 exec()를 이용한 프로세스 생성 과정 (1) | 2024.02.19 |