지난 시간에는 1바이트만 보냈는데 이제 더 많은 데이터를 보내려 한다
8바이트를 보내보자
파일 이름만 수정한다
Makefile 수정
Pi에서 잘 되는 것 확인했다
이제 배열로 바꾼다
app.c 파일 수정한다
11 char buff[8];
34 for(i=0;i<8;i++)
35 {
36 buff[i] = (val >> i) & 0x01;
37 }
dev.c 파일에서 1바이트때는 getuser 해도 됐지만, 여러개면 배열을 사용한다
(copy_from_user)
수정하면 아래와 같다
app.c이고
dev.c이다
근데 app.c에서 usleep(100000)을 빼면
cpu 점유율이 100이된다
작성된 예제를 분석하고 넘어가기로 함
make를 하고 다음과 같이 만든다
주번호를 조사하고 부번호를 조사해서 등록한다
같은 주번호의 open에서 부번호를 operation을 정의하고 open에서 부번호를 재정의
주번호가 256개밖에 안되기 때문에 부번호로 분류함
부번호를 정하는 용도
잡다한 주변장치가 주번호 10번에 있다
이 것을 misc라고 한다
지금부터 5챕터의 내용들을 응용해서 최종 과제를 할 것이다
첫 문제는 디바이스 드라이버의 타이머를 제어해야한다
vforl : video for linux
ioctl : io control
지금까지 open close read write를 했다
다양한 부가 기능을 read write로만으로는 구현할 수 없다
그래서 표준 시스템 콜 함수인 ioctl을 사용한다
fd :
request : command
arqp : 자료형이 필요할 때 사용하는 매개변수(가변인자)
inode값을 주지 않는다
호출은 위와 같이 한다
ioctl 함수의 특징
동작하는 개념
맨 위에 4가지 함수의 매크로가 있다
최상위 2비트에 쓰여져서 구분된다
자세한 내용은 p296~301을 참고할 것
p306을 mnt에서 복사해와서 실행해본다
잘 된다
사용 권한이 없을 때
1. sudo를 붙여서 사용
2. sudo chmod 를 이용해서 권한 부여하기
여기서 00003600이 출력 되었는데
.h 파일을 보면
6을 아스키코드로 하면 36이라 그렇다
만약 이거로 하면 00003604가 출력된다
이것은 맨 처음에 01
두번째에 84(8진수 132를 16진수로 바꾸면 1000 0100이므로)
세번째 36
네번째 05
그래서 80843605가 출력된다
매크로 함수는 전처리기된걸 컴파일하기 때문에 디버깅이 어렵다
매크로 상수값이 8 이상이면 MAXNR로 정의한다
내가 처리하려는 명령어가 맞는지 확인하는 부분
(아스키코드가 의도한대로 된건지 확인
8이 넘는지 확인)
기본 코드가 출력만 0x00 0xff가 반복적으로 토글되는 것이었다
이제는 ff에는 모든 불빛이 나오게 수정한다(완료)
과제
매개변수로 받아서 보수값으로 교차 토글하기
스위치를 누르면 해당 led 토글 및 보수값 교차 토글
app.c 파일
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#define DEVICE_FILENAME "/dev/kerneltimer"
void print_led(unsigned char);
void print_key(unsigned char);
int main(int argc,char * argv[])
{
int dev;
char buff = 0;
char oldBuff = 0;
int ret;
if(argc < 2)
{
printf("USAGE : %s [ledval] \n",argv[0]);
return 1;
}
// buff = atoi(argv[1]);
buff = (char)strtoul(argv[1],0,16);
dev = open( DEVICE_FILENAME, O_RDWR|O_NDELAY );
if(dev<0)
{
perror("open()");
return 2;
}
ret = write(dev,&buff,sizeof(buff));
if(ret < 0)
{
perror("write()");
return 3;
}
print_led(buff);
buff = 0;
do {
read(dev,&buff,sizeof(buff));
// buff = 1 << buff-1;
if((buff != 0) && (oldBuff != buff))
{
printf("key : %#04x\n",buff);
// print_key(buff);
write(dev,&buff,sizeof(buff));
print_led(buff);
oldBuff = buff;
if(buff == 0x80) //key:8
break;
}
} while(1);
close(dev);
return 0;
}
void print_led(unsigned char led)
{
int i;
puts("1:2:3:4:5:6:7:8");
for(i=0;i<=7;i++)
{
if(led & (0x01 << i))
putchar('O');
else
putchar('X');
if(i < 7 )
putchar(':');
else
putchar('\n');
}
return;
}
void print_key(unsigned char key)
{
int i;
puts("1:2:3:4:5:6:7:8");
for(i=0;i<=7;i++)
{
if(i+1 == key)
putchar('O');
else
putchar('X');
if(i < 7 )
putchar(':');
else
putchar('\n');
}
return;
}
dev.c 파일
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/gpio.h>
#include <linux/moduleparam.h>
#define DEBUG 1
#define GPIOLEDCNT 8
#define GPIOKEYCNT 8
#define OFF 0
#define ON 1
#define LEDKEY_DEV_NAME "kerneltimer_dev"
#define LEDKEY_DEV_MAJOR 230
int gpioLed[GPIOLEDCNT] = {6,7,8,9,10,11,12,13};
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 timerVal = 100; // f=100Hz, T=1/100=10ms, 100*10ms=1Sec
module_param(timerVal, int, 0);
static int ledVal = 0;
module_param(ledVal, int, 0);
struct timer_list timerLed;
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 Request gpio%d error\n", 6);
return ret;
}
}
for(i=0;i<GPIOLEDCNT;i++)
{
ret = gpio_direction_output(gpioLed[i], OFF);
if(ret < 0) {
printk("Failed direction_output gpio%d error\n", 6);
return ret;
}
}
return ret;
}
void gpioLedSet(long val)
{
int i;
for(i=0;i<GPIOLEDCNT;i++)
{
gpio_set_value(gpioLed[i], (val>>i) & 0x01);
}
}
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 ledkey_open(struct inode *inode, struct file *filp)
{
int num0 = MAJOR(inode->i_rdev);
int num1 = MINOR(inode->i_rdev);
printk("ledkey open-> major : %d\n", num0);
printk("ledkey open-> minor : %d\n", num1);
try_module_get(THIS_MODULE);
return 0;
}
static loff_t ledkey_llseek(struct file *filp, loff_t off, int whence)
{
printk("ledkey llseek -> off : %08X, whence : %08X\n", (unsigned int)off, whence);
return 0x23;
}
static ssize_t ledkey_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
char kbuf;
// printk("ledkey read -> buf : %08X, count : %08X \n", (unsigned int)buf, count);
kbuf=(char)gpioKeyGet();
put_user(kbuf, buf);
return 0x33;
}
static ssize_t ledkey_write(struct file *filp, const char *buf, size_t count, loff_t *f_ops)
{
char kbuff;
get_user(kbuff, buf);
ledVal = kbuff;
return count;
}
static long ledkey_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
printk("ledkey ioctl -> cmd : %08X, arg : %08X\n", cmd, (unsigned int)arg);
return 0x53;
}
static int ledkey_release(struct inode *inode, struct file *filp)
{
printk("ledkey release \n");
module_put(THIS_MODULE);
return 0;
}
struct file_operations ledkey_fops =
{
.llseek = ledkey_llseek,
.read = ledkey_read,
.write = ledkey_write,
.unlocked_ioctl = ledkey_ioctl,
.open = ledkey_open,
.release = ledkey_release,
};
void kerneltimer_func(struct timer_list *t);
void kerneltimer_registertimer(unsigned long timeover)
{
timer_setup(&timerLed, kerneltimer_func, 0);
timerLed.expires = get_jiffies_64() + timeover; // 10ms * 100 = 1sec
add_timer(&timerLed);
}
void kerneltimer_func(struct timer_list * t)
{
#if DEBUG
printk("ledVal : %#04x\n", (unsigned int)(ledVal));
#endif
ledVal = ~ledVal & 0xff;
gpioLedSet(ledVal);
mod_timer(t, get_jiffies_64() + timerVal);
}
int kerneltimer_init(void)
{
int ret;
#if DEBUG
printk("timerVal : %d, sec : %d \n", timerVal, timerVal/HZ);
#endif
kerneltimer_registertimer(timerVal);
ret = gpioLedInit();
if(ret<0){ return ret; }
ret = gpioKeyInit();
if(ret<0){ return ret; }
ret = register_chrdev(LEDKEY_DEV_MAJOR, LEDKEY_DEV_NAME, &ledkey_fops );
return ret;
}
void kerneltimer_exit(void)
{
if(timer_pending(&timerLed))
del_timer(&timerLed);
unregister_chrdev(LEDKEY_DEV_MAJOR, LEDKEY_DEV_NAME);
gpioLedFree();
gpioKeyFree();
}
module_init(kerneltimer_init);
module_exit(kerneltimer_exit);
MODULE_AUTHOR("KCCI-AIOT PYG");
MODULE_DESCRIPTION("led key test module");
MODULE_LICENSE("Dual BSD/GPL");
수정내용
이렇게 read에 KeyGet 함수와 put_user로 키 값을 받아와서 쓰고
write 함수에 get_user로 해당 값을 가져와서 ledVal(전역변수)에 쓴다
그리고 kerneltimer_func에 해당 키값으로 Led를 키고
init에서 led와 key를 init한 뒤 register_chrdev를 이용한다
exit에서는 unregister_chrdev를 이용한 뒤 led와 key를 Free 해준다