BEGIN{FS=OFS=","}
FNR==NR{
a[$1]=$2
next
}
{ if ($1 in a) {print $1, a[$1]} else {print $1, "NA"} }
[카테고리:] 생활코딩
-

xbox 360 드라이버 만지기1
내 라즈베리 파이에 usb 타입 xbox360 패드를 붙여 보고싶다. 리눅스 커널 xpad.c에 마이크로소프트 거의 모든 제품 usb vendor, product id가 등록되어 있다. xpad.c가 조금 복작하여 usb 인터럽트 사용 방법을 잘 이해할 수 없다. 키 입력 설정을 어떻게 할지는 나중 문제고… usb-skeletion.c 문서 역시 어렵다. 여기는 인터럽트 대신 대용량 데이터 전송을 목표로 했다.
그 중 가장 비슷한 usb 마우스 드라이버를 커널에서 찾았다. 커널이 성경과 같아 모든 물음에 대한 답을 한다. 200줄 약간 넘어가는 코드로 정말 인터럽트 핵심만 작성했다.
대략 구성은 아래와 같이 된다.
- usb 구조체 선언.
- 사용가능한 usb 번호 찾음, 등록.
- 입력 설정.
- 인터럽트 설정.
usb_fill_int_urb로 call 함수를 등록하여 인터럽트를 사용하면 된다. usb 인터럽트가 일정 주기로 발생한다. 계속 실행하기 위해 인터럽트로 실행할 함수 안에 usb_submit_urb를 넣는다. 알고보면 참 쉬운데 처음 이해하기 어렵다. xpad.c도 같은 방식이다. 처음에 왜 안보였는지…아직 키 입력을 설정하지 않았고, 커널에 test를 출력하도록 했다.
usb 구조체는 여러 정보를 쉽게 사용하려 군더더기를 많이 붙이는 듯 하다.
#include <linux/kernel.h> #include <linux/input.h> #include <linux/module.h> #include <linux/usb/input.h> #include <linux/init.h> #include <linux/device.h> #include <linux/usb/input.h> #include <linux/slab.h> #define USB_XBOX_MINOR_BASE 1 //구조체 선언. struct usb_xpad{ struct input_dev *dev; /* input device interface */ struct usb_device *udev; /* usb device */ struct usb_interface *intf; /* usb interface */ __u8 irq_in_endpointAddr; /* interrupt in address*/ __u8 irq_out_endpointAddr; /* interrupt out address*/ struct usb_endpoint_descriptor *endpoint_in, *endpoint_out; signed char *data; /* input data */ struct urb *irq_in; /* urb for interrupt in report*/ struct work_struct work; /* init/remove device from callback */ }; static struct usb_xpad *myPad; static int xpad_init_input(struct usb_xpad *xpad); static void xpad_deinit_input(struct usb_xpad *xpad); static void usb_xpad_irq(struct urb *urb){ pr_info("test\n"); usb_submit_urb(urb, GFP_KERNEL); } static int xpad_init_urb(struct usb_interface *intf, struct usb_xpad *xpad); static ssize_t xbox_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { pr_info("device was read.\n"); return 0; } static ssize_t xbox_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos) { return 0; } static int xbox_open(struct inode *inode, struct file *file) { int retval; struct urb *ptr_urb; ptr_urb = usb_alloc_urb(0, GFP_KERNEL); pr_info("device was opened.\n"); if (!ptr_urb) { retval = -ENOMEM; goto error; } return 0; error: if(ptr_urb) { usb_free_urb(ptr_urb); } return retval; } static int xbox_release(struct inode *inode, struct file *file) { pr_info("xbox was released\n"); return 0; } static int xbox_flush(struct file *file, fl_owner_t id) { return 0; } static const struct file_operations xboxtest_fops = { .owner = THIS_MODULE, .read = xbox_read, .write = xbox_write, .open = xbox_open, .release = xbox_release, .flush = xbox_flush, .llseek = noop_llseek, }; /* * usb class driver info in order to get a minor number from the usb core, * and to have the device registered with the driver core */ static struct usb_class_driver xbox_class = { .name = "xbox%d", .fops = &xboxtest_fops, .minor_base = USB_XBOX_MINOR_BASE, }; static struct usb_driver xpad_test_driver; static const struct usb_device_id xpad_table[] = { //{ USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ //XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */ {USB_DEVICE(0x045e, 0x028e)}, { } }; static const signed short xpad_common_btn[] = { BTN_A, BTN_B, BTN_X, BTN_Y, /* "analog" buttons */ BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */ -1 /* terminating entry */ }; MODULE_DEVICE_TABLE(usb, xpad_table); static int xpad_init_input(struct usb_xpad *xpad) { struct input_dev *input_dev; int i, error; int pipe, maxp; input_dev = input_allocate_device(); if (!input_dev) return -ENOMEM; xpad->dev = input_dev; usb_to_input_id(xpad->udev, &input_dev->id); input_set_drvdata(input_dev, xpad); /* set up standard buttons */ for (i = 0; xpad_common_btn[i] >= 0; i++) input_set_capability(input_dev, EV_KEY, xpad_common_btn[i]); pipe = usb_rcvintpipe(xpad->udev, xpad->irq_in_endpointAddr); maxp = usb_maxpacket(xpad->udev, pipe, usb_pipeout(pipe)); usb_fill_int_urb(xpad->irq_in, xpad->udev, pipe, xpad->data, (maxp > 8 ? 8 : maxp), usb_xpad_irq, xpad, xpad->endpoint_in->bInterval); error = input_register_device(input_dev); if (error) goto err_free_dev; pr_info("usb input was registered\n"); usb_submit_urb(xpad->irq_in, GFP_KERNEL); return 0; //return ok; err_free_dev: input_free_device(input_dev); return error; } static void xpad_deinit_input(struct usb_xpad *xpad) { pr_info("xpad is %p, ->dev is %p.\n",xpad, xpad->dev); if(xpad->dev) input_unregister_device(xpad->dev); } static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_xpad *xpad; struct usb_device *udev; struct usb_endpoint_descriptor *ep_irq_in,*ep_irq_out; struct usb_host_interface *intf_tmp; int retval; udev = interface_to_usbdev(intf); xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL); if (!xpad) return -ENOMEM; //초기화 //kzallocd으로 0으로 초기화 //xpad->odata_serial = 0; xpad->udev = udev; xpad->intf = intf; myPad = xpad; pr_info("xpad is %p, myPad is %p\n", xpad->intf, myPad->intf); pr_info("interface is %p\n", intf); //if (intf->cur_altsetting->desc.bNumEndpoints != 2) // return -ENODEV; intf_tmp = intf->cur_altsetting; // find common usb endpoint helper 사용 //https://lkml.org/lkml/2020/9/21/1239 /* set up the endpoint information */ /* use only the first bulk-in and bulk-out endpoints */ retval = usb_find_common_endpoints(intf_tmp, NULL, NULL, &ep_irq_in, &ep_irq_out); if (retval) { dev_err(&intf->dev, "Could not find both irq-in and irq-out endpoints\n"); goto error; } xpad->irq_in_endpointAddr = ep_irq_in->bEndpointAddress; xpad->irq_out_endpointAddr = ep_irq_out->bEndpointAddress; xpad->endpoint_in = ep_irq_in; xpad->endpoint_out = ep_irq_out; xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL); if (!xpad->irq_in) { retval = -ENOMEM; goto err_free_in_urb; } usb_set_intfdata(intf, xpad); pr_info("[info]: found interrupt end point, in: %d, out: %d", ep_irq_in->bEndpointAddress, ep_irq_out->bEndpointAddress); pr_info("probe \n"); //pr_info("%04X:%04X pluged \n", id->idVendor, id->idProduct); retval = usb_register_dev(intf, &xbox_class); if (retval< 0) { pr_err("usb_register failed for the "__FILE__ "driver." "Error number %d", retval); usb_set_intfdata(intf, NULL); goto error; } /* let the user know what node this device is now attached to */ dev_info(&intf->dev, "USB Skeleton device now attached to USBSkel-%d", intf->minor); //input으로 등록. xpad_init_input(xpad); return 0; error: kfree(xpad); return retval; err_free_in_urb: usb_free_urb(xpad->irq_in); return retval; } static void xpad_disconnect(struct usb_interface *intf) { struct usb_xpad *xpad; xpad = usb_get_intfdata(intf); pr_info("xpad address is %p\n", xpad); xpad_deinit_input(xpad); usb_deregister_dev(intf, &xbox_class); usb_set_intfdata(intf, NULL); kfree(xpad); pr_info("disconnected\n"); } static int xpad_suspend(struct usb_interface *intf, pm_message_t message) { pr_info("suspendes\n"); return 0; } static int xpad_resume(struct usb_interface *intf) { pr_info("resumed\n"); return 0; } static struct usb_driver xpad_test_driver = { .name = "xbox360_test", .probe = xpad_probe, .disconnect = xpad_disconnect, .suspend = xpad_suspend, .resume = xpad_resume, .id_table = xpad_table, }; static int xpad_init_urb(struct usb_interface *intf, struct usb_xpad *xpad) { int retval; xpad->irq_in= usb_alloc_urb(0, GFP_KERNEL); if (!xpad->irq_in) { retval = -ENOMEM; goto error; } return 0; error: return retval; } // 모듈 loading, unloading 테스트를 위해 과거 방식으로 사용 //module_init(usb_xboxtest_init); //module_exit(usb_xboxtest_exit); //Macro module_usb_driver(xpad_test_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("now0930"); MODULE_DESCRIPTION("Hello, xbox pad!");[45180.903315] xpad is ea6ce566, myPad is ea6ce566 [45180.903332] interface is ea6ce566 [45180.903349] [info]: found interrupt end point, in: 129, out: 1 [45180.903360] probe [45180.903636] xbox360_test 1-1.2:1.0: USB Skeleton device now attached to USBSkel-1 [45180.903815] input: Unspecified device as /devices/virtual/input/input8 [45180.904290] usb input was registered [45180.904475] xpad is 50c63d58, myPad is 50c63d58 [45180.904489] interface is 50c63d58 [45180.904506] [info]: found interrupt end point, in: 130, out: 2 [45180.904518] probe [45180.904685] xbox360_test 1-1.2:1.1: USB Skeleton device now attached to USBSkel-2 [45180.904841] input: Unspecified device as /devices/virtual/input/input9 [45180.905155] usb input was registered [45180.905310] xpad is 3bfd76ed, myPad is 3bfd76ed [45180.905323] interface is 3bfd76ed [45180.905342] xbox360_test 1-1.2:1.2: Could not find both irq-in and irq-out endpoints [45180.905432] xpad is 07d8d175, myPad is 07d8d175 [45180.905451] interface is 07d8d175 [45180.905469] xbox360_test 1-1.2:1.3: Could not find both irq-in and irq-out endpoints [45180.905585] usbcore: registered new interface driver xbox360_test [45180.909177] test [45180.913170] test [45210.971462] test [45210.984592] test [45210.997466] test [45211.010595] test [45211.075485] test [45211.088606] test [45211.109483] test [45211.130612] test [45211.151488] test [45211.168617] test [45211.181493] test [45211.754713] test [45211.799598] test [45211.812711] test [45212.329679] test [45217.545918] usbcore: deregistering interface driver xbox360_test [45217.546248] test [45217.546378] xpad address is 99d70f22 [45217.546411] xpad is 99d70f22, ->dev is 8784f33d. [45217.699130] disconnected [45217.699578] test [45217.699674] xpad address is 0764c1af [45217.699692] xpad is 0764c1af, ->dev is 379dff77. [45217.779137] disconnected
-

docker cgoup issue
데비안 11로 업데이트 후 에러로 docker를 실행할 수 없다.
docker: Error response from daemon: cgroups: cgroup mountpoint does not exist: unknown. ERRO[0000] error waiting for container: context canceled인터넷에 역시 해결 방법이 있었다.
I ran into similar issue found a temp fix on another place. Temp fix: sudo mkdir /sys/fs/cgroup/systemd sudo mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd/etc/fstab에 기록하면 된다.
$ cat /etc/fstab | tail -10 #docker error #docker: Error response from daemon: cgroups: cgroup mountpoint does not exist: unknown. #mkdir /sys/fs/cgroup/systemd #mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd cgroup /sys/fs/cgroup/systemd cgroup none,name=systemd 0 0https://waspro.tistory.com/556
docker root directory 변경
https://fliedcat.tistory.com/113
-
spinlock, mutex 실습
모듈을 로딩하면 kernel thread부터 만들어야 한다. 같은 책 초반에 나왔는데, 다시 보니 기억할 수 없다. 스레드를 만든 후 함수와 데이터를 넘겨야 하는데, 데이터가 void 포인터다. struct로 캐스팅 하고 싶은데, 에러가 났다. kernel 코드를 보고 괄호를 몇 번 붙였다. 아! ㅅㅂ. 구글 찾아보기보다 시(간)성비가 더 좋다.
pi@raspberrypi:~/linux $ grep -wn "kthread_create" -r ./drivers ./drivers/usb/usbip/usbip_common.h:285: = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \ ./drivers/usb/atm/ueagle-atm.c:2228: sc->kthread = kthread_create(uea_kthread, sc, "ueagle-atm"); ./drivers/usb/atm/usbatm.c:977: t = kthread_create(usbatm_do_heavy_init, instance, "%s", ./drivers/usb/gadget/file_storage.c:3527: fsg->thread_task = kthread_create(fsg_main_thread, fsg, ./drivers/usb/gadget/function/u_serial.c:1059: info->console_thread = kthread_create(gs_console_thread, ./drivers/usb/gadget/function/f_mass_storage.c:2924: kthread_create(fsg_main_thread, common, "file-storage"); ./drivers/usb/host/dwc_common_port/dwc_common_fbsd.c:981: retval = kthread_create((void (*)(void *))func, data, &thread->proc, ./drivers/iio/adc/ina2xx-adc.c:840: task = kthread_create(ina2xx_capture_thread, (void *)indio_dev, pi@raspberrypi:~/linux $ vi ./drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data) { int retval; dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread)); if (!thread) { return NULL; } thread->abort = 0; retval = kthread_create((void (*)(void *))func, data, &thread->proc, RFPROC | RFNOWAIT, 0, "%s", name); if (retval) { DWC_FREE(thread); return NULL; } return thread; }spinlock을 만든 후 초기화 하지 않으면, 사용할 수 없다. kernel에 메모리를 할당 받으면 초기화는 꼭 해줘야 하는 느낌이다.
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/gpio.h> //GPIO #include <linux/cdev.h> #include <linux/device.h> #include <linux/uaccess.h> #include <linux/fcntl.h> #define GPIO_10_OUT (10) #define DEVICE_DATA_MAX 256 #include <linux/kthread.h> #include <linux/delay.h> #include <linux/spinlock.h> unsigned int GPIO_irqNumber; /*사용자 데이터 부분*/ struct my_device_data{ struct cdev cdev; int index; char my_string[DEVICE_DATA_MAX]; struct timer_list simple_timer; spinlock_t lock; struct task_struct *kthread1; struct task_struct *kthread2; } ; int run_this_thread1(void* data); int run_this_thread2(void* data); int run_this_thread1(void* data) { //while(1)로 하면 kthread_stop을 할 수 없음. //루프가 없으면 kthread_stop을 불렀을 경우, segment error. //thread가 없다면, 종료를 할 수 없어 보임.. while(!kthread_should_stop()) { //data is my_device_data struct my_device_data *ptr_main_data; //ptr_main_data = data; ptr_main_data = (struct my_device_data(*))data; //공통이 구조체 접근. spin_lock(&ptr_main_data->lock); ptr_main_data->index++; //pr_info("spin lock is %0x\n",ptr_main_data->lock); pr_info("==============\n"); pr_info("[+]index is %d\n", ptr_main_data->index); pr_info("==============\n"); spin_unlock(&ptr_main_data->lock); //pr_info("spin lock is %0x\n",ptr_main_data->lock); msleep(500); } return 0; } int run_this_thread2(void* data) { while(!kthread_should_stop()) { //data is my_device_data struct my_device_data *ptr_main_data; ptr_main_data = (struct my_device_data(*))data; // //공통이 구조체 접근. spin_lock(&ptr_main_data->lock); ptr_main_data->index++; pr_info("==============\n"); pr_info("[+]index is %d\n", ptr_main_data->index); pr_info("==============\n"); spin_unlock(&ptr_main_data->lock); msleep(500); } return 0; } static irqreturn_t gpio_irq_handler(int irq, void *dev_id) { /*Scheduling work queue*/ return IRQ_HANDLED; } //device driver 작성 부분. /*************드라이버 함수 ******************/ static int mydriver_open(struct inode *inode, struct file *file); static int mydriver_release(struct inode *inode, struct file *file); static ssize_t mydriver_read(struct file *flip, char *buf, size_t len, loff_t *off); static ssize_t mydriver_write(struct file *flip, const char *buf, size_t len, loff_t *off); /********************************************/ //file operation structure static struct file_operations fops = { .owner = THIS_MODULE, .read = mydriver_read, .write = mydriver_write, .open = mydriver_open, .release = mydriver_release, }; static int mydriver_open(struct inode *inode, struct file *file) { pr_info("Deviced file was opend.\n"); return 0; } static int mydriver_release(struct inode *inode, struct file *file) { pr_info("Deviced file was closed.\n"); return 0; } static int mydriver_read(struct file *file, char *buf, size_t len, loff_t *off) { pr_info("read\n"); return 0; } static int mydriver_write(struct file *flip, const char *buf, size_t len, loff_t *off) { return 0; } dev_t dev = 0; static struct cdev my_cdev; static struct class *dev_class; struct my_device_data *main_data; static int __init init_hw(void) { //디바이스 등록 if(( alloc_chrdev_region(&dev, 0, 1, "test_device") < 0)) { pr_err("[!]character device was not allocated\n"); goto r_unreg; } pr_info("[=]%d-%d, was allocated\n", MAJOR(dev), MINOR(dev)); //초기화 cdev_init(&my_cdev, &fops); pr_info("[=]driver was initialized\n"); //시스템에 추가 if((cdev_add(&my_cdev, dev, 1)) < 0) { pr_err("[!]cannot add device to kernel\n"); goto r_del; } //class 만듦. if((dev_class=class_create(THIS_MODULE, "my_class")) == NULL) { pr_err("[!]cannot add class\n"); goto r_class; } if((device_create(dev_class, NULL, dev, NULL, "my_device")) == NULL) { pr_err("[!]cannot create device\n"); goto r_device; } //gpio 10번을 사용. //export하여 간단히 사용. //입력은 값을 써 넣을 수 없음. 출력으로 설정. GPIO_irqNumber = gpio_to_irq(GPIO_10_OUT); pr_info("[=]irq %d was assinged\n",GPIO_irqNumber); //interrupt 등록 필요 if (request_irq(GPIO_irqNumber, (void*)gpio_irq_handler, IRQF_TRIGGER_RISING, "my_device", NULL)) { pr_err("[!]my_device: cannot register IRQ\n"); goto r_gpio; } pr_info("[=]module was installed\n"); //메모리 공간 할당. main_data = kmalloc(sizeof(struct my_device_data), GFP_KERNEL); //spin lock init spin_lock_init(&main_data->lock); main_data->index=0; if(!main_data) { pr_err("[!]cannot alloc memory\n"); goto r_memory; } pr_info("[=]got memory\n"); //thread create. main_data->kthread1 = kthread_create(run_this_thread1, main_data, "my_thread1"); main_data->kthread2 = kthread_create(run_this_thread2, main_data, "my_thread2"); if(main_data->kthread1) { wake_up_process(main_data->kthread1); pr_info("wake up thread1 at %p\n", main_data->kthread1); } if(main_data->kthread2) { wake_up_process(main_data->kthread2); pr_info("wake up thread2 at %p\n", main_data->kthread2); } return 0; r_gpio: gpio_free(GPIO_10_OUT); r_device: device_destroy(dev_class,dev); r_class: class_destroy(dev_class); r_del: cdev_del(&my_cdev); r_unreg: unregister_chrdev_region(dev,1); r_memory: ; return -1; } static void __exit exit_hw(void) { free_irq(GPIO_irqNumber, NULL); gpio_free(GPIO_10_OUT); //flush_work(struct work_struct *work); device_destroy(dev_class,dev); //class_unregister(dev_class); class_destroy(dev_class); cdev_del(&my_cdev); unregister_chrdev_region(dev,1); if(main_data->kthread1) kthread_stop(main_data->kthread1); if(main_data->kthread2) kthread_stop(main_data->kthread2); pr_info("kthread was stopped\n"); pr_info("wake up thread1 at %p\n", main_data->kthread1); pr_info("wake up thread2 at %p\n", main_data->kthread2); kfree(main_data); printk(KERN_INFO "module was removed\n"); } module_init(init_hw); module_exit(exit_hw); MODULE_LICENSE("GPL"); MODULE_AUTHOR("noname"); MODULE_DESCRIPTION("Hello, world!");spin lock을 적용하지 않을 경우, 겹쳐쓴다. 적용하면 순서대로 실행된다 믿는다.
[ 1749.848372] ============== [ 1749.848376] [+]index is 108 [ 1749.848380] ============== [ 1750.378381] ============== [ 1750.378392] [+]index is 109 [ 1750.378399] ============== [ 1750.378414] ============== [ 1750.378421] [+]index is 110 [ 1750.378428] ============== [ 1750.898416] ============== [ 1750.898431] [+]index is 111 [ 1750.898439] ============== [ 1750.898461] ============== [ 1750.898470] [+]index is 112 [ 1750.898478] ============== [ 1751.418404] ============== [ 1751.418417] [+]index is 113 [ 1751.418426] ============== [ 1751.418446] ============== [ 1751.418455] [+]index is 114 [ 1751.418463] ============== [ 1751.938485] ============== [ 1751.938501] [+]index is 115 [ 1751.938512] ============== [ 1751.938537] ============== [ 1751.938547] [+]index is 116 [ 1751.938556] ============== [ 1752.458509] ============== [ 1752.458529] [+]index is 117 [ 1752.458538] ============== [ 1752.458560] ============== [ 1752.458570] [+]index is 118 [ 1752.458578] ============== [ 1752.978388] ============== [ 1752.978394] [+]index is 119 [ 1752.978398] ============== [ 1753.498497] kthread was stopped [ 1753.498515] wake up thread1 at 39208d2a [ 1753.498524] wake up thread2 at 5bdf5278 [ 1753.498536] module was removed [ 1773.404079] [=]236-0, was allocated [ 1773.404089] [=]driver was initialized [ 1773.406890] [=]irq 54 was assinged [ 1773.406942] [=]module was installed [ 1773.406952] [=]got memory [ 1773.410837] wake up thread1 at 6acc0d97 [ 1773.410859] wake up thread2 at 9613521a [ 1773.411132] ============== [ 1773.411143] [+]index is 1 [ 1773.411151] ============== [ 1773.411794] ============== [ 1773.411805] [+]index is 2 [ 1773.411812] ============== [ 1773.528622] ============== [ 1773.528626] ============== [ 1773.528636] [+]index is 4 [ 1773.528637] [+]index is 4 [ 1773.528640] ============== [ 1773.528641] ============== [ 1773.648584] ============== [ 1773.648585] ============== [ 1773.648589] [+]index is 6 [ 1773.648590] [+]index is 6 [ 1773.648593] ============== [ 1773.648594] ============== [ 1773.768583] ============== [ 1773.768584] ============== [ 1773.768588] [+]index is 8 [ 1773.768589] [+]index is 8 [ 1773.768591] ============== [ 1773.768594] ============== [ 1773.888583] ============== [ 1773.888587] [+]index is 9 [ 1773.888589] ============== [ 1773.888591] ============== [ 1773.888595] [+]index is 10 [ 1773.888598] ============== [ 1774.008583] ============== [ 1774.008585] ============== [ 1774.008588] [+]index is 12 [ 1774.008591] [+]index is 12 [ 1774.008594] ============== [ 1774.008596] ============== [ 1774.128592] ============== [ 1774.128593] ============== [ 1774.128597] [+]index is 14 [ 1774.128599] [+]index is 14 [ 1774.128601] ============== [ 1774.128604] ============== [ 1774.248635] ============== [ 1774.248638] ============== [ 1774.248648] [+]index is 16 [ 1774.248652] [+]index is 16 [ 1774.248657] ============== [ 1774.248663] ============== [ 1774.368631] ============== [ 1774.368642] [+]index is 17 [ 1774.368649] ============== [ 1774.378613] ============== [ 1774.378622] [+]index is 18
https://embetronicx.com/tutorials/linux/device-drivers/spinlock-in-linux-kernel-1/
-
timer 실습
kernel timer를 실습했다. callback 함수 argrument로 timer를 가지고 있는 구조체 데이터를 전달할 수 있다. work queue와 같은 방식이다. 커널 특정 버전부터 이런 식으로 변경되었는 듯 하다. 타이머가 만료되면 다시 등록하도록 했다.
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/gpio.h> //GPIO #include <linux/cdev.h> #include <linux/device.h> #include <linux/uaccess.h> #include <linux/fcntl.h> #include <linux/timer.h> #include <linux/jiffies.h> #define GPIO_10_OUT (10) #define DEVICE_DATA_MAX 256 unsigned int GPIO_irqNumber; /*\uc0ac\uc6a9\uc790 \ub370\uc774\ud130 \ubd80\ubd84*/ static struct my_device_data{ struct cdev cdev; int index; char my_string[DEVICE_DATA_MAX]; struct timer_list simple_timer; } my_data1; void timer_action_fn(struct timer_list *t); void timer_action_fn(struct timer_list *t) { struct my_device_data *ptr1; pr_info("%ld: timer function was activated\n", jiffies); ptr1=from_timer(ptr1, t, simple_timer); ptr1->index++; pr_info("index is %d\n", ptr1->index); mod_timer(&my_data1.simple_timer, jiffies+msecs_to_jiffies(1000)); } static int init_timer(void){ timer_setup(&my_data1.simple_timer, timer_action_fn, 0); pr_info("%ld: timer was setup\n", jiffies); mod_timer(&my_data1.simple_timer, jiffies+msecs_to_jiffies(1000)); return 0; } static irqreturn_t gpio_irq_handler(int irq, void *dev_id) { /*Scheduling work queue*/ return IRQ_HANDLED; } //device driver \uc791\uc131 \ubd80\ubd84. /*************\ub4dc\ub77c\uc774\ubc84 \ud568\uc218 ******************/ static int mydriver_open(struct inode *inode, struct file *file); static int mydriver_release(struct inode *inode, struct file *file); static ssize_t mydriver_read(struct file *flip, char *buf, size_t len, loff_t *off); static ssize_t mydriver_write(struct file *flip, const char *buf, size_t len, loff_t *off); /********************************************/ //file operation structure static struct file_operations fops = { .owner = THIS_MODULE, .read = mydriver_read, .write = mydriver_write, .open = mydriver_open, .release = mydriver_release, }; static int mydriver_open(struct inode *inode, struct file *file) { pr_info("Deviced file was opend.\n"); return 0; } static int mydriver_release(struct inode *inode, struct file *file) { pr_info("Deviced file was closed.\n"); return 0; } static int mydriver_read(struct file *file, char *buf, size_t len, loff_t *off) { pr_info("read\n"); return 0; } static int mydriver_write(struct file *flip, const char *buf, size_t len, loff_t *off) { return 0; } dev_t dev = 0; static struct cdev my_cdev; static struct class *dev_class; static int __init init_hw(void) { //\ub514\ubc14\uc774\uc2a4 \ub4f1\ub85d if(( alloc_chrdev_region(&dev, 0, 1, "test_device") < 0)) { pr_err("[!]character device was not allocated\n"); goto r_unreg; } pr_info("[=]%d-%d, was allocated\n", MAJOR(dev), MINOR(dev)); //\ucd08\uae30\ud654 cdev_init(&my_cdev, &fops); pr_info("[=]driver was initialized\n"); //\uc2dc\uc2a4\ud15c\uc5d0 \ucd94\uac00 if((cdev_add(&my_cdev, dev, 1)) < 0) { pr_err("[!]cannot add device to kernel\n"); goto r_del; } //class \ub9cc\ub4e6. if((dev_class=class_create(THIS_MODULE, "my_class")) == NULL) { pr_err("[!]cannot add class\n"); goto r_class; } if((device_create(dev_class, NULL, dev, NULL, "my_device")) == NULL) { pr_err("[!]cannot create device\n"); goto r_device; } //gpio 10\ubc88\uc744 \uc0ac\uc6a9. //export\ud558\uc5ec \uac04\ub2e8\ud788 \uc0ac\uc6a9. //\uc785\ub825\uc740 \uac12\uc744 \uc368 \ub123\uc744 \uc218 \uc5c6\uc74c. \ucd9c\ub825\uc73c\ub85c \uc124\uc815. GPIO_irqNumber = gpio_to_irq(GPIO_10_OUT); pr_info("[=]irq %d was assinged\n",GPIO_irqNumber); //interrupt \ub4f1\ub85d \ud544\uc694 if (request_irq(GPIO_irqNumber, (void*)gpio_irq_handler, IRQF_TRIGGER_RISING, "my_device", NULL)) { pr_err("[!]my_device: cannot register IRQ\n"); goto r_gpio; } pr_info("[=]module was installed\n"); //timer setup init_timer(); return 0; r_gpio: gpio_free(GPIO_10_OUT); r_device: device_destroy(dev_class,dev); r_class: class_destroy(dev_class); r_del: cdev_del(&my_cdev); r_unreg: unregister_chrdev_region(dev,1); return -1; } static void __exit exit_hw(void) { free_irq(GPIO_irqNumber, NULL); gpio_free(GPIO_10_OUT); //flush_work(struct work_struct *work); device_destroy(dev_class,dev); //class_unregister(dev_class); class_destroy(dev_class); cdev_del(&my_cdev); unregister_chrdev_region(dev,1); //timer delete del_timer(&my_data1.simple_timer); printk(KERN_INFO "module was removed\n"); } module_init(init_hw); module_exit(exit_hw); MODULE_LICENSE("GPL"); MODULE_AUTHOR("noname"); MODULE_DESCRIPTION("Hello, world!");[146685.757495] [=]236-0, was allocated [146685.757504] [=]driver was initialized [146685.757960] [=]irq 54 was assinged [146685.757984] [=]module was installed [146685.757991] 14638325: timer was setup [146686.818385] 14638432: timer function was activated [146686.818398] index is 1 [146687.858398] 14638536: timer function was activated [146687.858402] index is 2 [146688.898415] 14638640: timer function was activated [146688.898428] index is 3 [146689.938432] 14638744: timer function was activated [146689.938445] index is 4 [146690.978452] 14638848: timer function was activated [146690.978457] index is 5 [146692.018469] 14638952: timer function was activated [146692.018483] index is 6 [146693.058494] 14639056: timer function was activated [146693.058500] index is 7 [146694.098512] 14639160: timer function was activated [146694.098548] index is 8 [146695.138529] 14639264: timer function was activated [146695.138563] index is 9 [146696.178545] 14639368: timer function was activated [146696.178573] index is 10 [146697.218575] 14639472: timer function was activated [146697.218607] index is 11 [146698.258571] 14639576: timer function was activated [146698.258587] index is 12

https://embetronicx.com/tutorials/linux/device-drivers/using-kernel-timer-in-linux-device-driver/
https://stackoverflow.com/questions/14953871/how-to-pass-custom-argument-to-linux-timers-function