1. 程式人生 > >Linux裝置驅動之button按鍵驅動學習與小結

Linux裝置驅動之button按鍵驅動學習與小結

button按鍵驅動,相對於前面的LED驅動來說。增加了中斷處理以及阻塞與非阻塞方式等新知識點。

先上學習的驅動程式碼。

核心:linux3.0

板子:fl2440

/*********************************************************************************
 *      Copyright:  (C) 2011 Guo Wenxue<[email protected]>  
 *                  All rights reserved.
 *
 *       Filename:  plat_button.c
 *    Description:  This is the common button driver runs on S3C2440
 *                 
 *        Version:  1.0.0(10/27/2011~)
 *         Author:  Guo Wenxue <
[email protected]
> * ChangeLog: 1, Release initial version on "10/27/2011 11:39:10 AM" * ********************************************************************************/ #include "s3c_driver.h" #define DRV_AUTHOR "Guo Wenxue <[email protected]>" #define DRV_DESC "S3C24XX button driver" /* Driver version*/ #define DRV_MAJOR_VER 1 #define DRV_MINOR_VER 0 #define DRV_REVER_VER 0 #define DEV_NAME DEV_BUTTON_NAME //#define DEV_MAJOR DEV_BUTTON_MAJOR #ifndef DEV_MAJOR #define DEV_MAJOR 0 /* dynamic major by default */ #endif #define BUTTON_UP 0 /* Button status is up */ #define BUTTON_DOWN 1 /* Button status is pushed down */ #define BUTTON_UNCERTAIN 2 /* Button status uncerntain */ #define TIMER_DELAY_DOWN (HZ/50) /*Remove button push down dithering timer delay 20ms */ #define TIMER_DELAY_UP (HZ/10) /*Remove button up dithering timer delay 100ms */ static int debug = DISABLE; static int dev_major = DEV_MAJOR; static int dev_minor = 0; /*============================ Platform Device part ===============================*/ /* Button hardware informtation structure*/ struct s3c_button_info { unsigned char num; /*Button nubmer 按鍵號*/ char * name; /*Button nubmer 按鍵名*/ int nIRQ; /*Button IRQ number 中斷號*/ unsigned int setting; /*Button IRQ Pin Setting 中斷引腳配置*/ unsigned int gpio; /*Button GPIO port 對應的IO引腳*/ }; /* The button plaotform device private data structure */ struct s3c_button_platform_data //按鍵資料結構體 { struct s3c_button_info *buttons; //用來訪問按鍵硬體資訊的指標 int nbuttons;//按鍵數量 }; /* Button hardware informtation data*/ //具體的相應按鍵資訊 static struct s3c_button_info s3c_buttons[] = { [0] = { .num = 1, .name = "KEY1", .nIRQ = IRQ_EINT0,//中斷號 .gpio = S3C2410_GPF(0), .setting = S3C2410_GPF0_EINT0,//datasheet手冊上對應的IO中斷口 }, [1] = { .num = 2, .name = "KEY2", .nIRQ = IRQ_EINT2, .gpio = S3C2410_GPF(2), .setting = S3C2410_GPF2_EINT2, }, [2] = { .num = 3, .name = "KEY3", .nIRQ = IRQ_EINT3, .gpio = S3C2410_GPF(3), .setting = S3C2410_GPF3_EINT3, }, [3] = { .num = 4, .name = "KEY4", .nIRQ = IRQ_EINT4, .gpio = S3C2410_GPF(4), .setting = S3C2410_GPF4_EINT4, }, }; /* The button platform device private data */ static struct s3c_button_platform_data s3c_button_data = { .buttons = s3c_buttons, .nbuttons = ARRAY_SIZE(s3c_buttons), }; struct button_device { unsigned char *status; /* The buttons Push down or up status */ struct s3c_button_platform_data *data; /* The buttons hardware information data */ struct timer_list *timers; /* The buttons remove dithering timers */ wait_queue_head_t waitq; /* Wait queue for poll() */ volatile int ev_press; /* Button pressed event */ struct cdev cdev; struct class *dev_class; } button_device; static void platform_button_release(struct device * dev) { return; } static struct platform_device s3c_button_device = { .name = "s3c_button", .id = 1, .dev = { .platform_data = &s3c_button_data, .release = platform_button_release, }, }; static irqreturn_t s3c_button_intterupt(int irq,void *de_id) //按鍵中斷服務程式 { int i; int found = 0; struct s3c_button_platform_data *pdata = button_device.data; for(i=0; i<pdata->nbuttons; i++) { if(irq == pdata->buttons[i].nIRQ)//找到具體的中斷號 { found = 1; break; } } if(!found) /* An ERROR interrupt */ return IRQ_NONE; /* Only when button is up then we will handle this event */ if(BUTTON_UP == button_device.status[i]) { button_device.status[i] = BUTTON_UNCERTAIN;//因為要防抖動,且不確定是否為有效按鍵,所以先設定為不確定狀態 mod_timer(&(button_device.timers[i]), jiffies+TIMER_DELAY_DOWN); } return IRQ_HANDLED; } static void button_timer_handler(unsigned long data) //定時器中斷服務程式 { struct s3c_button_platform_data *pdata = button_device.data; int num =(int)data; int status = s3c2410_gpio_getpin( pdata->buttons[num].gpio ); if(LOWLEVEL == status) { if(BUTTON_UNCERTAIN == button_device.status[num]) /* Come from interrupt */ { //dbg_print("Key pressed!\n"); button_device.status[num] = BUTTON_DOWN; printk("%s pressed.\n", pdata->buttons[num].name); //~!@#)¥%……&^.,( /* Wake up the wait queue for read()/poll() */ button_device.ev_press = 1; wake_up_interruptible(&(button_device.waitq)); ev_press喚醒等待佇列 } /* Cancel the dithering */ mod_timer(&(button_device.timers[num]), jiffies+TIMER_DELAY_UP);//重新啟用並設定定時器 } else { //dbg_print("Key Released!\n"); button_device.status[num] = BUTTON_UP; // enable_irq(pdata->buttons[num].nIRQ); } return ; } /*===================== Button device driver part ===========================*/ static int button_open(struct inode *inode, struct file *file) { struct button_device *pdev ; struct s3c_button_platform_data *pdata; int i, result; pdev = container_of(inode->i_cdev,struct button_device, cdev); pdata = pdev->data; file->private_data = pdev; /* Malloc for all the buttons remove dithering timer */ pdev->timers = (struct timer_list *) kmalloc(pdata->nbuttons*sizeof(struct timer_list), GFP_KERNEL); if(NULL == pdev->timers)//核心裡的記憶體申請失敗 { printk("Alloc %s driver for timers failure.\n", DEV_NAME); return -ENOMEM; } memset(pdev->timers, 0, pdata->nbuttons*sizeof(struct timer_list)); /* Malloc for all the buttons status buffer */ pdev->status = (unsigned char *)kmalloc(pdata->nbuttons*sizeof(unsigned char), GFP_KERNEL); if(NULL == pdev->status) { printk("Alloc %s driver for status failure.\n", DEV_NAME); result = -ENOMEM; goto ERROR; } memset(pdev->status, 0, pdata->nbuttons*sizeof(unsigned char)); init_waitqueue_head(&(pdev->waitq));//初始化等待佇列頭 for(i=0; i<pdata->nbuttons; i++) { /* Initialize all the buttons status to UP */ pdev->status[i] = BUTTON_UP; /* Initialize all the buttons' remove dithering timer */ setup_timer(&(pdev->timers[i]), button_timer_handler, i); //初始化每個定時器 /* Set all the buttons GPIO to EDGE_FALLING interrupt mode */ s3c2410_gpio_cfgpin(pdata->buttons[i].gpio, pdata->buttons[i].setting);//按鍵相應的管腳配置成IRQ中斷模式 irq_set_irq_type(pdata->buttons[i].nIRQ, IRQ_TYPE_EDGE_FALLING);//把相應的中斷號設定為下降沿觸發方式 /* Request for button GPIO pin interrupt */ result = request_irq(pdata->buttons[i].nIRQ, s3c_button_intterupt, IRQF_DISABLED, DEV_NAME, (void *)i);//註冊給核心,一旦發生中斷號的中斷就呼叫s3c_button_intterupt這個中斷處理程式 if( result ) { result = -EBUSY; goto ERROR1; } } return 0; ERROR1: kfree((unsigned char *)pdev->status); while(--i) { disable_irq(pdata->buttons[i].nIRQ); free_irq(pdata->buttons[i].nIRQ, (void *)i); } ERROR: kfree(pdev->timers); return result; } static int button_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct button_device *pdev = file->private_data; struct s3c_button_platform_data *pdata; int i, ret; unsigned int status = 0; pdata = pdev->data; dbg_print("ev_press: %d\n", pdev->ev_press); if(!pdev->ev_press) //ev_press為按鍵識別符號,即按下時才為1.結合下面等待佇列程式 { if(file->f_flags & O_NONBLOCK) { dbg_print("read() without block mode.\n");// O_NONBLOCK是設定為非阻塞模式 return -EAGAIN;//若沒有按鍵按下,還採用非阻塞模式則會一直浪費CPU的時間等待。 } else { /* Read() will be blocked here */ dbg_print("read() blocked here now.\n"); wait_event_interruptible(pdev->waitq, pdev->ev_press); //在阻塞模式讀取且沒按鍵按下則讓等待佇列進入睡眠,直到ev_press為1 } } pdev->ev_press = 0;清除標識,準備下一次 for(i=0; i<pdata->nbuttons; i++) { dbg_print("button[%d] status=%d\n", i, pdev->status[i]); status |= (pdev->status[i]<<i); } ret = copy_to_user(buf, (void *)&status, min(sizeof(status), count)); return ret ? -EFAULT : min(sizeof(status), count); } static unsigned int button_poll(struct file *file, poll_table * wait)//類似於應用層的select輪詢監聽 { struct button_device *pdev = file->private_data; unsigned int mask = 0; poll_wait(file, &(pdev->waitq), wait);//新增等待佇列到等待佇列中 if(pdev->ev_press) { mask |= POLLIN | POLLRDNORM; /* The data aviable */ } return mask; } static int button_release(struct inode *inode, struct file *file) { int i; struct button_device *pdev = file->private_data; struct s3c_button_platform_data *pdata; pdata = pdev->data; for(i=0; i<pdata->nbuttons; i++) { disable_irq(pdata->buttons[i].nIRQ); free_irq(pdata->buttons[i].nIRQ, (void *)i); del_timer(&(pdev->timers[i])); } kfree(pdev->timers); kfree((unsigned char *)pdev->status); return 0; } static struct file_operations button_fops = { .owner = THIS_MODULE, .open = button_open, .read = button_read, .poll = button_poll, .release = button_release, }; static int s3c_button_probe(struct platform_device *dev) { int result = 0; dev_t devno; /* Alloc the device for driver */ if (0 != dev_major) { devno = MKDEV(dev_major, dev_minor); result = register_chrdev_region(devno, 1, DEV_NAME); } else { result = alloc_chrdev_region(&devno, dev_minor, 1, DEV_NAME); dev_major = MAJOR(devno); } /* Alloc for device major failure */ if (result < 0) { printk("%s driver can't get major %d\n", DEV_NAME, dev_major); return result; } /* Initialize button_device structure and register cdev*/ memset(&button_device, 0, sizeof(button_device)); button_device.data = dev->dev.platform_data; cdev_init (&(button_device.cdev), &button_fops); button_device.cdev.owner = THIS_MODULE; result = cdev_add (&(button_device.cdev), devno , 1); if (result) { printk (KERN_NOTICE "error %d add %s device", result, DEV_NAME); goto ERROR; } button_device.dev_class = class_create(THIS_MODULE, DEV_NAME); if(IS_ERR(button_device.dev_class)) { printk("%s driver create class failture\n",DEV_NAME); result = -ENOMEM; goto ERROR; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) device_create(button_device.dev_class, NULL, devno, NULL, DEV_NAME); #else device_create (button_device.dev_class, NULL, devno, DEV_NAME); #endif printk("S3C %s driver version %d.%d.%d initiliazed.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER); return 0; ERROR: printk("S3C %s driver version %d.%d.%d install failure.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER); cdev_del(&(button_device.cdev)); unregister_chrdev_region(devno, 1); return result; } static int s3c_button_remove(struct platform_device *dev) { dev_t devno = MKDEV(dev_major, dev_minor); cdev_del(&(button_device.cdev)); device_destroy(button_device.dev_class, devno); class_destroy(button_device.dev_class); unregister_chrdev_region(devno, 1); printk("S3C %s driver removed\n", DEV_NAME); return 0; } /*===================== Platform Device and driver regist part ===========================*/ static struct platform_driver s3c_button_driver = { .probe = s3c_button_probe, .remove = s3c_button_remove, .driver = { .name = "s3c_button", .owner = THIS_MODULE, }, }; static int __init s3c_button_init(void) { int ret = 0; ret = platform_device_register(&s3c_button_device); if(ret) { printk(KERN_ERR "%s: Can't register platform device %d\n", __FUNCTION__, ret); goto fail_reg_plat_dev; } dbg_print("Regist S3C %s Device successfully.\n", DEV_NAME); ret = platform_driver_register(&s3c_button_driver); if(ret) { printk(KERN_ERR "%s: Can't register platform driver %d\n", __FUNCTION__, ret); goto fail_reg_plat_drv; } dbg_print("Regist S3C %s Driver successfully.\n", DEV_NAME); return 0; fail_reg_plat_drv: platform_driver_unregister(&s3c_button_driver); fail_reg_plat_dev: return ret; } static void s3c_button_exit(void) { platform_driver_unregister(&s3c_button_driver); dbg_print("S3C %s platform device removed.\n", DEV_NAME); platform_device_unregister(&s3c_button_device); dbg_print("S3C %s platform driver removed.\n", DEV_NAME); } module_init(s3c_button_init); module_exit(s3c_button_exit); module_param(debug, int, S_IRUGO); module_param(dev_major, int, S_IRUGO); module_param(dev_minor, int, S_IRUGO); MODULE_AUTHOR(DRV_AUTHOR); MODULE_DESCRIPTION(DRV_DESC); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:S3C24XX_button");

學習小結

(一)

request_irq  (中斷號,中斷處理程式,標誌位,裝置名,中斷處理的引數)

在linux核心中用於申請中斷的函式是request_irq(),函式原型在Kernel/irq/manage.c中定義:

int request_irq( unsigned int irq,

irq_handler_t handler,

unsigned long irqflags, 

const char *devname, 

void *dev_id)

irq是要申請的硬體中斷號。

handler是向系統註冊的中斷處理函式,是一個回撥函式,中斷髮生時,系統呼叫這個函式,dev_id引數將被傳遞給它。

irqflags 是中斷處理的屬性

若設定了IRQF_DISABLED (老版本中的SA_INTERRUPT,本版zhon已經不支援了),則表示中斷處理程式是快速處理程式,快速處理程式被呼叫時遮蔽所有中斷,慢速處理程式不遮蔽;

若設定了IRQF_SHARED (老版本中的SA_SHIRQ),則表示多個裝置共享中斷。

若設定了IRQF_SAMPLE_RANDOM(老版本中的SA_SAMPLE_RANDOM),表示對系統熵有貢獻,對系統獲取隨機數有好處。(這幾個flag是可以通過或的方式同時使用的)

devname設定中斷名稱,通常是裝置驅動程式的名稱  在cat /proc/interrupts中可以看到此名稱。

dev_id在中斷共享時會用到,一般設定為這個裝置的裝置結構體或者NULL

request_irq()返回0表示成功返回-INVAL表示中斷號無效或處理函式指標為NULL,返回-EBUSY表示中斷已經被佔用且不能共享。

(二)

首先在open函式裡面會獲得裝置資訊,並且會動態的申請記憶體為每一個button都建立一個定時器。再有就是動態的建立儲存狀態status的buf。然後初始化讓所有按鍵的狀態為BUTTON_UP以及呼叫Setup_timer初始化定時器以及設定定時器的回撥函式button_timer_handler.,s3c2410_gpio_cfgpin把相應的管腳設定為IRQ中斷模式(否則可能是GPIO模式),irq_set_irq_type把相應的中斷號設定為下降沿觸發的方式。然後request_irq()把中斷註冊給核心。一旦發生中斷則呼叫s3c_button_intterupt這個中斷處理程式。

緊接著來到s3c_button_intterupt處理程式:通過判斷獲取具體的中斷號之後便進行消抖的處理。(此時通過按鍵的狀態不管是否按下依然為BUTTON_up狀態,這是我們最初認為設定的)緊接著通過mod_timer啟用定時器,在超時之後,然後進入定時器原本設定好的定時器中斷處理程式button_timer_handler中正式的處理這個中斷請求。也就是說中斷處理程式s3c_button_intterupt()只是確認按鍵是否有效,真正處理中斷的程式是定時器裡面的button_timer_handler( )

再看Button_timer_handler函式:因為當按下的時候進入了s3c_button_intterupt函式然後定時器超時呼叫到了button_timer_handler裡,此時為低電平。然後我們這時候將他設定為BUTTON_DOWN狀態。且喚醒等待佇列讓裝置進行讀取ev_press為按鍵按下的發生標識,按下ev_press即為1也通過ev_press引數值來設定工作模式,選定阻塞或者是非阻塞模式。

對於read函式來說:獲取了按鍵的裝置資訊之後通過ev_press來剔除非阻塞模式選擇阻塞模式,在阻塞模式下讀取且沒按鍵按下則讓等待佇列進入睡眠,直到ev_press為1。通過位運算來判斷哪一個按鍵按下並儲存狀態值到status中。

另外還有poll函式,類似於應用層select,是通過輪詢方式不斷的監聽。說一下驅動中的輪詢。這個與應用程式中select的使用相對應

/* 輪詢的概念和作用:

使用非阻塞I/O的應用程式通常會使用select()和poll()用於查詢裝置的狀態,以便獲知使用者程式是否能對裝置進行非阻塞的訪問.他們都需要裝置驅動程式中的poll函式支援。select()和poll()系統呼叫最終會引發裝置驅動中的poll()函式被執行,poll()函式為最終的執行體。

Linux下select呼叫的過程:

1.使用者層應用程式呼叫select(),底層呼叫poll()

2.核心層呼叫sys_select() -> do_select() 最終呼叫檔案描述符fd對應的struct file型別變數的structfile_operations fops中的polll函式。

使用者空間的select函式的用法:先呼叫巨集FD_ZERO將指定的fd_set清零,然後呼叫巨集FD_SET將需要測試的fd加入fd_set,接著呼叫函式select測試fd_set中的所有fd,最後用巨集FD_ISSET檢查某個fd在函式select呼叫後,相應位是否仍然為1。

理解select模型的關鍵在於理解fd_set,為說明方便,取fd_set長度為1位元組,fd_set中的每一bit可以對應一個檔案描述符fd。則1位元組長的fd_set最大可以對應8個fd

   (1)執行fd_set set; FD_ZERO(&set);則set用位表示是0000,0000。
   (2)若fd=5,執行FD_SET(fd,&set);後set變為0001,0000(第5位置為1)
   (3)若再加入fd=2,fd=1,則set變為0001,0011
   (4)執行select(6,&set,0,0,0)阻塞等待//最大fd值+1
   (5)若fd=1,fd=2上都發生可讀事件,則select返回,此時set變為0000,0011。注意:沒有事件發生的fd=5被清空

下面簡介阻塞與非阻塞方式:

阻塞操作: 是指在執行裝置操作時,若不能獲得資源,則掛起程序直到滿足可操作的條件後再進行操作,被掛起的程序會進入休眠狀態,被從排程器的執行佇列中移除,直到條件被滿足。
非阻塞操作: 是指在執行裝置操作時,若不能獲得資源,並不掛起,或者放棄他或者不停地的查詢,直到可執行時

而我們驅動中等待佇列使用的則是阻塞的方式,首先申請一個等待佇列,一旦阻塞該程序就進入休眠將資源讓給其他程序的,然後直到滿足條件再喚醒等待佇列,重新執行程式。

(三)

個人覺得高深莫測,牛逼轟轟的是對核心中的那些巨集以及功能函式的創造,比如container_of與timer。簡直神奇。

小插曲:起初看程式有兩個中斷程式,以為註冊中斷後發生中斷返回的中斷服務程式是正牌。其實不然,對於高階的CPU都是會找個定時器來幫助處理中斷。就好比領導不會何事都親力親為一樣。那樣浪費時間,不小心就把領導累死了。。。有了中斷,從中斷服務程式獲得了具體的裝置號且為有效按鍵中斷之後就由定時器代理領導來全盤接手。如果要處理中斷就會呼叫定時器的handler中斷處理程式來處理。

還有在消抖處理那段程式時,習慣性的想的太智慧,忘記了status的狀態值是程式碼中起初自己設定好的,即使那個時候你按鍵是按下的,狀態也是status_UP。當時困擾了很久,想著若是按下後狀態自然就應該是down和低電平%……&**¥#@

另外起初看到setup _timer是初始化定時器,一直在納悶,搞不明白到底在哪裡給定時器賦了初始值,還找到回撥函式handler那去了,後面看消抖呼叫mod_timer搞了半天才明白原來這個初始化的真正意思其實是說:把每個最初的定時器賦予超時便返回到指定的處理函式的功能。這也是初始化,只是說沒有具體給這個定時器馬上賦初始值而已。


下面是按鍵測試程式:

/*********************************************************************************
 *      Copyright:  (C) 2015 songyong<handy_skyoutlook.com>
 *                  All rights reserved.
 *
 *       Filename:  copy.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(2015年04月18日)
 *         Author:  sky <[email protected]>
 *      ChangeLog:  1, Release initial version on "2015年04月18日 13時17分14秒"
 *                 
 ********************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/ioctl.h>
#include<sys/time.h>

#define BUTTON_STATUS  4 
#define KEY1  0x1 
#define KEY2  0x2 
#define KEY3  0x4 
#define KEY4  0x8 
/********************************************************************************
 *  Description:
 *   Input Args:
 *  Output Args:
 * Return Value:
 ********************************************************************************/
int main (int argc, char **argv)
{
    int i = 0;
    int button_fd;
    int ret;
    int current_button;

    button_fd = open("/dev/button",0);

    if(button_fd < 0)
    {
        printf("Open buttons device faild!\n");
        exit(1);
    }
    while(1)
    {
         ret = read(button_fd,¤t_button,sizeof(BUTTON_STATUS));

    if (ret != sizeof(current_button) )
         {
           printf("Read button device faild.\n"); 
         }
    else 
        {
    switch(current_button)
            {
                case KEY1: printf("KEY1 Down.!\n");break;
                case KEY2: printf("KEY2 Down.!\n");break;
                case KEY3: printf("KEY3 Down.!\n");break;
                case KEY4: printf("KEY4 Down.!\n");break;//其實在驅動程式碼的定時器中斷處理程式handler中已有輸出列印程式碼
                default: printf("kkey error\n");
            }
        }
    }
    return 0;
} /* ----- End of main() ----- */

接下來弄按鍵點亮LED燈^。^

相關推薦

Linux裝置驅動button按鍵驅動學習小結

button按鍵驅動,相對於前面的LED驅動來說。增加了中斷處理以及阻塞與非阻塞方式等新知識點。 先上學習的驅動程式碼。 核心:linux3.0 板子:fl2440 /***************************************************

Linux裝置模型tty&&uart驅動架構分析

五: uart_add_one_port()操作 在前面提到.在對uart裝置檔案過程中.會將操作轉換到對應的port上,這個port跟uart_driver是怎麼關聯起來的呢?這就是uart_add_ont_port()的主要工作了. 顧名思義,這個函式是在uart_driver增加一個port.程式碼如

嵌入式Linux裝置驅動開發按鍵驅動程式例項

11.6  按鍵驅動程式例項 11.6.1  按鍵工作原理 高電平和低電平相接怎麼會變成低電平呢 就像你把電源正極的負極相連一樣會把電壓拉低。大電流會從高電平引腳流向低電平引腳,把高電平引腳拉低。 LED和蜂鳴器是最簡單的GPIO的應用,都不需要任何外部

Linux裝置模型tty驅動架構分析

------------------------------------------ 本文系本站原創,歡迎轉載!轉載請註明出處:http://ericxiao.cublog.cn/------------------------------------------一:前言Tty這個名稱源於電傳打位元組的簡稱。

linux裝置模型uart驅動架構分析

一:前言 接著前面的終端控制檯分析,接下來分析serial的驅動.在linux中,serial也對應著終端,通常被稱為串列埠終端.在shell上,我們看到的/dev/ttyS*就是串列埠終端所對應的裝置節點. 在分析具體的serial驅動之前.有必要先分析uart

Linux裝置驅動USB hub驅動(續)

5.2.2:介面驅動中的hub_thread()函式 我們之前在分析usb_hub_init()的程式碼的時候,忽略掉了一部份. 程式碼片段如下所示: int usb_hub_init(void) {    ……     khubd_task = kthread_run(hub_thread, NULL, "

linux裝置模型匯流排 裝置驅動

《Linux核心修煉之道》讀書筆記 1、 裝置模型的上層建築由匯流排(bus) 、裝置(device)、 驅動(device_driver)這3個數據結構構成,裝置模型表示了它們之間的連線關係。

47 使用linux核心原始碼裡的按鍵驅動

這個裝置驅動適用於,每個按鍵是連線到一個io口, 而且這個io口還有中斷功能的 需要在linux核心配置裡選上相關的配置。在核心原始碼目錄下: make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-gn

tiny4412 裝置SD卡驅動(三)

開發板:tiny4412(1611) 核心:linux4.4 編譯器:arm-none-linux-gnueabi-gcc (gcc version 4.8.3 20140320) 在linux核心中,SD卡屬於MMC子系統,簡單的介紹: http://blog.

第18章 ARM Linux裝置四(常用的OF API)

18.4 常用的OF API除了前文介紹的of_machine_is_compatible()、of_device_is_compatible()等常用函式以外,在Linux的BSP和驅動程式碼中,經常會使用到一些Linux中其他裝置樹的API,這些API通常被冠以of_字首

linux裝置模型I2C子系統

=============================== 本文系本站原創,歡迎轉載! 轉載請註明出處:http://blog.csdn.net/gdt_a20 ===============================       I2c子系統將i2c控制器(

linux裝置模型spi子系統

=============================== 本文系本站原創,歡迎轉載! 轉載請註明出處:http://www.cnblogs.com/gdt-a20 ===============================       相比於前面介紹的i2c子系統,spi子系

linux裝置模型mmc,sd子系統

struct mmc_host { 171         struct device           *parent;          172         struct device           class_dev; 173         int                    

linux裝置gpio

#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/version.h> #include &

SPI驅動主控制器驅動程式

 嵌入式微處理器訪問SPI裝置有兩種方式:使用GPIO模擬SPI介面的工作時序或者使用SPI控制器。使用GPIO模擬SPI介面的工作時序是非常容易實現的,但是會導致大量的時間耗費在模擬SPI介面的時序上,訪問效率比較低,容易成為系統瓶頸。這裡主要分析使用SPI控制器的情

linux裝置模型bus,device,driver分析二

=============================== 本文系本站原創,歡迎轉載! 轉載請註明出處:http://blog.csdn.net/gdt_a20 ===============================   上篇分析了bus,driver的註冊過程

linux裝置模型Class

    參考:http://www.wowotech.net/device_model/class.html     剛開始寫字元裝置驅動程式的時候,老師教我們自動建立裝置節點,“要先建立類,在類下面建立裝置,類名字不重要“。         firstdrv_class

【原創】linux裝置模型kset/kobj/ktype分析

# 背 景 - `Read the fucking source code!` --By 魯迅 - `A picture is worth a thousand words.` --By 高爾基 說明: 1. Kernel版本:4.14 2. ARM64處理器,Contex-A53,雙核 3. 使用工具:

Linux運維計算機硬件組成基本工作原理+服務器簡單介紹

linux 服務器 運維 第1章 計算硬件組成與基本工作原理1.1 計算機組成 1.顯示器2.機箱(主機) | |-----CPU |-----硬盤 |-----內存 |-----電源

學習Linux裝置模型淺析驅動篇》筆記(一)

原文中說了,核心版本為2.6.29;這裡都貼3.15的核心原始碼; 檔案/drivers/rtc/rtc-s3c.c static struct platform_driver s3c_rtc_driver = {         .probe= s3c_rtc_pro