SMALL
ioctl 구성
32bit로 구성
[2] [ 14(데이터 크기) ] [ 8 (매직넘버) ] [ 8(구분번호) ]
매직넘버 : 아스키값도 가능 사이즈만 넘지 않자
cmd 명령의 해석 매크로 함수
_IOC_NR : 구분 번호 필드 값을 읽는 매크로
_IOC_TYPE : 매직 넘버 필드값을 읽는 매크로
_IOC_SIZE : 데이터의 크기 필드값을 읽는 매크로
_IOC_DIR : 읽기와 쓰기 속성 필드값을 읽는 매크로
cmd 명령의 작성 매크로 함수
_IO : 부가적인 데이터가 없는 명령을 만드는 매크로
_IOR : 데이터를 읽어오기 위한 명령을 작성
_IOW : 데이터를 써 넣기 위한 명령을 작성
_IOWR : 디바이스 드라이버에서 읽고 쓰기위한 명령을 작성하는 매크로
해당 프로그램은 보드에 led를 제어하는 커맨드를 ioctl로 내리는 것임.
이를 통해 user app 이 드라이버에 명령을 주고 받을수 있음.
ioctl 커맨더 정의 헤더
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | #ifndef _IOCTL_MYDRV_H_ #define _IOCTL_MYDRV_H_ #define IOCTL_MAGIC 254 typedef struct { unsigned char commander[26]; unsigned char password[12]; } __attribute__ ((packed)) ioctl_buf; typedef struct { unsigned char product[13]; unsigned char serial[20]; unsigned char day[12]; } __attribute__ ((packed)) info; //ioctl의 command 를 만들어 주는 것 //device driver가 어떻게 동작하라는 commnad //device 특성에 따라서 커맨드를 만들자 #define IOCTL_MYDRV_TEST _IO( IOCTL_MAGIC, 0 ) #define IOCTL_MYDRV_READ _IOR( IOCTL_MAGIC, 1 , ioctl_buf ) #define IOCTL_MYDRV_WRITE _IOW( IOCTL_MAGIC, 2 , ioctl_buf ) #define IOCTL_MYDRV_LED_OFF _IOW( IOCTL_MAGIC, 3 , ioctl_buf ) #define IOCTL_MYDRV_LED_ON _IOW( IOCTL_MAGIC, 4 , ioctl_buf ) #define IOCTL_MYDRV_GET_INFO _IOW( IOCTL_MAGIC, 5 , info ) #define IOCTL_MAXNR 4 #endif // _IOCTL_MYDRV_H_ | cs |
여기서 IOCTL_MAGIC 은 디바이스의 주 번호와 같이 생각하면 된다.
그리고 이제 각 커맨드에 번호를 할당 하고 , 사용할 구조체의 형식을 정하면 된다.
#define IOCTL_MYDRV_LED_ON _IOW( IOCTL_MAGIC, 4 , ioctl_buf )
해당 부분을 정리해보면,
IOCTL_MYDRV_LED_ON 은 드라이버에 데이터를 쓰는데 사용하는 커맨드이고 IOCTL_MAGIC을 가지고 4번에 ioctl_buf형식 의 데이터를 주고 받겠다.
mydrv.c식
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | /* mydrv.c - kernel 3.0 skeleton device driver */ #include <linux/init.h> #include <asm/uaccess.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/delay.h> #include <asm/io.h> // ioremap(),iounmap() #include <linux/kernel.h> /* printk() */ #include <linux/slab.h> /* kmalloc() */ #include <linux/fs.h> /* everything... */ #include <linux/errno.h> /* error codes */ #include <linux/types.h> /* size_t */ #include <linux/kdev_t.h> #include <linux/cdev.h> #include <linux/device.h> #include "my_ioctl.h" #define DEVICE_NAME "mydrv" static int mydrv_major = 245; static unsigned long * kva = 0; static unsigned long * kva2 = 0; module_param(mydrv_major, int, 0); int flag = 0; static void init_led(void) { kva = ioremap(0xE02002C0,0x10) ; printk("kva = 0x%x\n",(int)kva); *((unsigned long*)kva)=0x11111111; *(unsigned long*)((unsigned char*)kva+8)= 0x00000000; } static void init_led2(void) { kva2 = ioremap(0xe02002a0,0x10) ; printk("kva2 = 0x%x\n",(int)kva); *((unsigned long*)kva2)=0x11111111; *(unsigned long*)((unsigned char*)kva2+8)= 0x00000000; } static void led_on_1(void) { *(unsigned char*)((unsigned char*)kva+4) =0xff; } static void led_off_1(void) { *(unsigned char*)((unsigned char*)kva+4) =0x00; } static void led_on_2(void) { *(unsigned char*)((unsigned char*)kva2+4) =0xff; } static void led_off_2(void) { *(unsigned char*)((unsigned char*)kva2+4) =0x00; } void led_all(void) { init_led(); init_led2(); led_on_1(); mdelay(500); led_off_1(); mdelay(500); led_on_2(); mdelay(500); led_off_2(); mdelay(500); } //io addr static int mydrv_open(struct inode *inode, struct file *file) { init_led2(); init_led(); printk("mydrv opened !!\n"); return 0; } static int mydrv_release(struct inode *inode, struct file *file) { printk("mydrv released !!\n"); return 0; } static ssize_t mydrv_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { printk("mydrv_read is invoked\n"); return 0; } static ssize_t my_led_write(struct file *filp,const char __user *buf, size_t len, loff_t *f_pos) { return 0; } static int mydrv_ioctl (struct file *filp, unsigned int cmd, unsigned long arg) { ioctl_buf *k_buf; info* k_buf2; int i,err, size; /* * 해석 매크로 * 검증하는 매크로 if( _IOC_TYPE( cmd ) != IOCTL_MAGIC ) return -EINVAL; if( _IOC_NR( cmd ) >= IOCTL_MAXNR ) return -EINVAL; size = _IOC_SIZE( cmd ); if( size ) { err = -EFAULT; if( _IOC_DIR( cmd ) & _IOC_READ ) err = !access_ok( VERIFY_WRITE, (void __user *) arg, size ); else if( _IOC_DIR( cmd ) & _IOC_WRITE ) err = !access_ok( VERIFY_READ , (void __user *) arg, size ); if( err ) return err; } * 실제 동작 */ switch( cmd ) { case IOCTL_MYDRV_TEST : printk("IOCTL_MYDRV_TEST Processed!!\n"); break; //led on command case IOCTL_MYDRV_LED_ON : k_buf = (ioctl_buf*)arg; printk("Commander : %s\n", k_buf->commander); if(strcmp(k_buf->commander,"human") == 0 && strcmp( k_buf->password,"hello") == 0){ flag = 1; } printk("IOCTL_MYDRV_LED_ON Processed!!\n"); if(flag == 1){ led_on_1(); led_on_2(); } break; //led off command case IOCTL_MYDRV_LED_OFF : k_buf = (ioctl_buf*)arg; printk("Commander : %s\n", k_buf->commander); if(strcmp(k_buf->commander,"human") == 0 && strcmp( k_buf->password,"hello") == 0){ flag = 0; } if(flag == 0){ led_off_1(); led_off_2(); } printk("IOCTL_MYDRV_LED_OFF Processed!!\n"); break; //get info command case IOCTL_MYDRV_GET_INFO : k_buf2 = (info*)kmalloc(sizeof(info),GFP_KERNEL); sprintf(k_buf2->product,"%s","led"); sprintf(k_buf2->serial, "%s","1111222333"); sprintf(k_buf2->day, "%s","2017 10 20"); copy_to_user ( (void __user *) arg, k_buf2, (unsigned long ) sizeof(info) ); break; default : printk("Invalid IOCTL Processed!!\n"); break; } return 0; } /* Set up the cdev structure for a device. */ static void mydrv_setup_cdev(struct cdev *dev, int minor, struct file_operations *fops) { /* * Major 와 Minor를 합친 dev 번호 */ int err, devno = MKDEV(mydrv_major, minor); /* * operaion 과 cdev 설정 */ cdev_init(dev, fops); dev->owner = THIS_MODULE; dev->ops = fops; err = cdev_add (dev, devno, 1); if (err) printk (KERN_NOTICE "Error %d adding mydrv%d", err, minor); } static struct file_operations mydrv_fops = { .owner = THIS_MODULE, .read = mydrv_read, .write = my_led_write, .open = mydrv_open, .release = mydrv_release, .unlocked_ioctl = mydrv_ioctl, }; #define MAX_MYDRV_DEV 1 /* * cdev 포인터 구조체 선언 */ static struct cdev MyDrvDevs[MAX_MYDRV_DEV]; static int mydrv_init(void) { int result; // 디바이스 번호를 설정 // MAJOR 240 부 번호 0 dev_t dev = MKDEV(mydrv_major, 0); /* Figure out our device number. */ /* * manual device number 등록 */ if (mydrv_major) result = register_chrdev_region(dev, //device number 1, //minor count DEVICE_NAME //device name ); /* * auto device number 등록 */ else { result = alloc_chrdev_region(&dev, //dev num poninter if success, return number 0, //allocate poll 설정 1, //minor count DEVICE_NAME); //device name mydrv_major = MAJOR(dev); //major number get } if (result < 0) { printk(KERN_WARNING "mydrv: unable to get major %d\n", mydrv_major); return result; } if (mydrv_major == 0) mydrv_major = result; mydrv_setup_cdev(MyDrvDevs,0, &mydrv_fops); printk("mydrv_init done\n"); return 0; } static void mydrv_exit(void) { cdev_del(MyDrvDevs); unregister_chrdev_region(MKDEV(mydrv_major, 0), 1); printk("mydrv_exit done\n"); } module_init(mydrv_init); module_exit(mydrv_exit); MODULE_LICENSE("GPL"); | cs |
test_mydrv.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | /* test_mydrv.c */ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ioctl.h> #include <fcntl.h> #include "my_ioctl.h" int main() { int fd,i,size,size2; ioctl_buf *buf_in,*buf_out; info *info_data; //할당 size = sizeof(ioctl_buf); buf_in = (ioctl_buf *)malloc(size); buf_out = (ioctl_buf *)malloc(size); size2 = sizeof(info); info_data = (info*)malloc(size2); //오픈 fd = open("/dev/mydrv",O_RDWR); //명령 셋팅 memset(buf_in, 0x00, size); sprintf(buf_in->commander,"%s","human"); sprintf(buf_in->password,"%s","hello"); //LED ON 명 령전달 ioctl(fd, IOCTL_MYDRV_LED_ON, buf_in ); getchar(); ioctl(fd, IOCTL_MYDRV_LED_OFF, buf_in ); ioctl(fd, IOCTL_MYDRV_GET_INFO, info_data ); printf("product : %s\n",info_data->product); printf("serial : %s\n",info_data->serial); printf("dat : %s\n",info_data->day); free(buf_in); free(buf_out); free(info_data); close(fd); return (0); } | cs |
LIST
'학부_대학원 > 임베디드 리눅스' 카테고리의 다른 글
MTD 및 파일시스템 정리 -1 (0) | 2019.05.02 |
---|---|
[임베디드 정리] (0) | 2017.07.17 |
(임베디드)리눅스 커널 모듈 - 인터럽트, 플랫폼 디바이스 드라이버 (0) | 2017.07.13 |
Platform Device Driver Built In[플랫폼 디바이스 드라이버 빌트인] (0) | 2017.07.13 |
(임베디드)리눅스 커널 모듈 - User, Kernel 통신 (0) | 2017.07.13 |