SMALL
케릭터 디바이스 드라이버
틈틈이 드라이버를 만들었지만, 직접 디바이스를 컨트롤 해봄.
비록 간단한 led이지만, 어차피 메모리의 값을 사용하고 특정 핀?으로 데이터를 설정하는건 모두 같은 원리이니까.
linux 2.4 버전의 경우 거의 사용될 일이 없을것 같아 정리하지 않음.
linux 2.6 버전은 4.x 까지 비슷하게 사용가능
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 | register_chrdev_region() 카운트 값을 가지는 디바이스 드라이버 등록 원형 int register_chrdev_region(dev_t fisrt, unsigned int count, char* name) 여기서 카운트 값은 부번호의 리밋 alloc_chrdev_regin() 디바이스 번호를 동적으로 할당 해줌 원형 int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char* name) unregister_chrdev_region() 사용중인 디바이스 번호를 해체 한다. 원형 void unregister_chrdev_region(dev_t first, unsigned int count); dev_t은 Major와 Minor 번호가 조합된 형이다. macro 소개 Major 12bits, Minor 20bits MAJOR(dev_t dev); 주 번호 추출 MINOR(dev_t dev); 부 번호 추출 MKDEV(int ma, int mi) 번호 설정 cdev 구조체 struct cdev{ struct kobject *owner; struct module file_operations *ops struct list_head list; dev_t dev unsigned int count } 2.6 커널은 내부적으로 캐릭터 디바이스를 표현하기 위해 cdev구조체를 사용 —> cdev 구조체가 생성된 이유 cdev_init() cdev 구조체를 초기화 원형 void cdev_init(struct cdev *cdev, struct file_operations *fops) cdev_add() cdev 구조체를 커널에 등록 함 원형 vod cdev_add(struct cdev *cdev, dev_t num, unsigned int count); | cs |
그리고 코드는 직관적으로 알수 있을 것이다.
저기서 led 의 주소 값이 0xE02002C0 을 볼수 있는데, 이건 해당 보드의 led 주소여서 보드마다 상이할 수있음.
여기서 또 주의깊게 볼 함수? 는 ioremap, iounmap함수인데, mmap과 같이 물리 메모리에 직접적으로 접근할 수 있도록 해준다!!
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 | #include <linux/init.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> #define DEVICE_NAME "mydrv" //디바이스 드라이버 주 번호 static int mydrv_major = 245; //io addr static unsigned long * kva = 0; module_param(mydrv_major, int, 0); static void led_on_(void); static void led_off_(void); static void init_led(void); static int mydrv_open(struct inode *inode, struct file *file) { 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) { printk("Let'g go led game\n"); while(1){ led_on_(); mdelay(10000); led_off_(); } 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); /* * operation 과 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, }; #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"); } static void init_led(void) { kva = ioremap(0xE02002C0,0xA6C) ; printk("kva = 0x%x\n",(int)kva); *((unsigned long*)kva)=0x11111111; *(unsigned long*)((unsigned char*)kva+8)= 0x00000000; } static void led_on_(void) { *(unsigned char*)((unsigned char*)kva+4) =0xff; } static void led_off_(void) { *(unsigned char*)((unsigned char*)kva+4) =0x00; } module_init(mydrv_init); module_exit(mydrv_exit); MODULE_LICENSE("GPL"); | cs |
$mknod /dev/mydrv c 245 0
mknod : 장치 파일로만들어라
/dev/mydrv : 경로
c : 케릭터 디바이스
245 : 주 번호
0 : 부 번호
장치 파일로 만들고 앱으로 연결하기
LIST
'학부_대학원 > 임베디드 리눅스' 카테고리의 다른 글
Platform Device Driver Built In[플랫폼 디바이스 드라이버 빌트인] (0) | 2017.07.13 |
---|---|
(임베디드)리눅스 커널 모듈 - User, Kernel 통신 (0) | 2017.07.13 |
Mango Board 정리 (0) | 2017.07.12 |
(임베디드)리눅스 커널 모듈 빌트 인[Built in] (0) | 2017.07.12 |
임베디드 리눅스 커널 포팅 [0] (4) | 2017.07.11 |