基于(修剪)ARM-Linux下遙控器驅(qū)動(dòng)

基于ARM-Linux下遙控器驅(qū)動(dòng)

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/string.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <mach/regs-gpio.h>  // <----相關(guān)的ARM GPIO配置頭文件
#include <mach/hardware.h>   //
#include <asm/gpio.h>
#include <plat/gpio-cfg.h>
MODULE_LICENSE("Dual BSD/GPL");
#define CHARDEVICE_MAJOR   0
#define CHARDEVICE_MINOR   0
//首個(gè)本類設(shè)備的次編號(hào)
#define CHARDEVICE_COUNT   4
//!要管轄4個(gè)本類設(shè)備LED
#define CHARDEVICE_NAME    "con_device"
static dev_t dev = 0;  //用于存首個(gè)設(shè)備編號(hào)
static int state=0;

#define IOCTL_GPIO_MOVE 1
#define IOCTL_GPIO_BACK 0
#define IOCTL_GPIO_STOP 2
#define IOCTL_GPIO_TURN_LEFT 3
#define IOCTL_GPIO_TURN_RIGHT 4
#define IOCTL_GPIO_PIN 5
 

static unsigned long gpio_table [] =
{
 S3C2410_GPF3,
 S3C2410_GPF4,
 S3C2410_GPG0,
 S3C2410_GPG3,
};

static unsigned int gpio_cfg_table [] =
{
 S3C2410_GPF3_INP,
 S3C2410_GPF4_INP,
 S3C2410_GPG0_INP,
 S3C2410_GPG3_INP,
};

static unsigned long gpio_irq_table [] = //作為中斷源的引腳
{
 S3C2410_GPF3,
 S3C2410_GPF4,
 S3C2410_GPG0,
 S3C2410_GPG3,
};
static unsigned long gpio_irq_cfg_table [] = //引腳設(shè)置為哪一號(hào)中斷源
{
 IRQ_EINT3,
 IRQ_EINT4,
 IRQ_EINT8,
 IRQ_EINT11,
};
static char* gpio_irq_name_cfg_table [4] = //給中斷引腳一個(gè)標(biāo)識(shí)符,相當(dāng)于ID
{
 "S3C2410_GPF3_EINT1",
 "S3C2410_GPF4_EINT4",
 "S3C2410_GPG0_EINT2",
 "S3C2410_GPG3_EINT0"
};
#define CHARDEVICE_CLASS_NAME "con_device_class"  
//類名稱相同,驅(qū)動(dòng)將會(huì)有沖突
//定義以下變量方便動(dòng)態(tài)存主次編號(hào)
static u32 chardevice_major=CHARDEVICE_MAJOR;
static u32 chardevice_minor=CHARDEVICE_MINOR;
static int irq_nLED=0;
//用于自動(dòng)配置節(jié)點(diǎn)文件
static struct class *dev_class=NULL;
struct self_cdev
{
   struct device *dev_class_node;//設(shè)備節(jié)點(diǎn)對(duì)象
   struct cdev i_cdev;//字符設(shè)備驅(qū)動(dòng)實(shí)例,內(nèi)含兩個(gè)重要參數(shù):設(shè)備編號(hào)和服務(wù)接口結(jié)構(gòu)
   u8 led;
   u8 bLighting;//具體設(shè)備實(shí)例的私有數(shù)據(jù),第幾號(hào)LED
};//!用戶自定義的字符設(shè)備結(jié)構(gòu)<--方便具體設(shè)備的管理,比如指定設(shè)備的管理對(duì)象喊衫,它的私有數(shù)據(jù)(例如LED的當(dāng)前電平狀態(tài)變量)
//!ioctl接口處理函數(shù)<--可以不用依賴open函數(shù)來得到file參數(shù)芦昔,它可以直接處理node,也可以通過file參數(shù)來直接操作(雙通道);cmd表示控制命令參數(shù);arg表示命令cmd的附加參數(shù)
static int chardevice_ioctl(struct inode* node,struct file *filep,unsigned int cmd,unsigned long arg){
   struct self_cdev* scdevp=filep->private_data;//!接回容器實(shí)例首地址
  // printk(KERN_ALERT "Entry %s function!\n",__FUNCTION__);
 //  printk(KERN_ALERT "LED:%d\n",scdevp->led);
   return 0;  
}
//!open接口處理函數(shù)
//參數(shù)node:用于傳入指定的設(shè)備節(jié)點(diǎn)文件結(jié)構(gòu)體疟游;filep:用于回饋一個(gè)文件實(shí)例指針
//!<--注意這里的接口處理函數(shù)的參數(shù)設(shè)置跟系統(tǒng)調(diào)用函數(shù)open的參數(shù)設(shè)置是不一樣的
static int chardevice_open(struct inode* node,struct file *filep){
   struct self_cdev* scdevp=NULL;//容器類型指針
   printk(KERN_ALERT "Entry %s function!\n",__FUNCTION__);
   scdevp=container_of(node->i_cdev,struct self_cdev,i_cdev);  
   //container_of作用是從節(jié)點(diǎn)文件所在的結(jié)構(gòu)體中提取所對(duì)應(yīng)設(shè)備的容器(包含了cdev等管理對(duì)象,也包含有設(shè)備的私有數(shù)據(jù))
   //原型:container_of(節(jié)點(diǎn)的i_cdev,自定義的容器結(jié)構(gòu)類型,容器結(jié)構(gòu)中的cdev成員名)
   scdevp->led=MINOR(node->i_rdev);
   filep->private_data=scdevp;//!讓文件實(shí)例指針能透過成員private_data全面管轄到指定的設(shè)備
   return 0;  
}
static int chardevice_read(struct file *filep,char __user *buf,size_t count,loff_t *offset){
   struct self_cdev* scdevp=filep->private_data;//!接回容器實(shí)例首地址
   int i,j,k,l;
   i=s3c2410_gpio_getpin(gpio_table[0]);
   j=s3c2410_gpio_getpin(gpio_table[1]);
   k=s3c2410_gpio_getpin(gpio_table[2]);
   l=s3c2410_gpio_getpin(gpio_table[3]);
  
   if(i!=0){
   strcpy(buf,"w");
 
  }
   else if(k!=0){
   strcpy(buf,"r");
 
  }
  
   else if(j!=0){
   strcpy(buf,"b");
 
  }
   else if(l!=0){
   strcpy(buf,"l");
 
  }
   else if (i==0&&k==0&&l==0&&j==0)
      {
      strcpy(buf,"s");     
      }
 
   return 0;
}
//!release/close接口處理函數(shù)<--可以不用依賴open函數(shù)來得到file參數(shù)勇凭,它可以直接處理node,也可以通過file參數(shù)來直接操作(雙通道)
static int chardevice_release(struct inode* node,struct file *filep){
   struct self_cdev* scdevp=filep->private_data;//!接回容器實(shí)例首地址
   printk(KERN_ALERT "Entry %s function!\n",__FUNCTION__);
   printk(KERN_ALERT "LED:%d\n",scdevp->led);
   return 0;  
}
//!指定部分結(jié)構(gòu)的成員進(jìn)行初始化
static struct file_operations i_cdev_fops = {
   .owner=THIS_MODULE, //預(yù)定義好的宏,表示本模塊
    .open=chardevice_open, //指定open接口處理函數(shù)是右側(cè)函數(shù)
   .ioctl=chardevice_ioctl,
    .read=chardevice_read,
   .release=chardevice_release
};//類似QT里的connect()
static struct self_cdev* i_scdev=NULL;

static int chardevice_add(struct self_cdev* pscdev,int index)
{
   dev_t ldev; int ret =-EFAULT;   int ret2 =-EFAULT;
   printk(KERN_ALERT "Entry %s function!\n",__FUNCTION__);  
   //!添加字符設(shè)備實(shí)例
   ldev=MKDEV(chardevice_major,chardevice_minor+index);//!建立設(shè)備編號(hào)
   cdev_init(&pscdev->i_cdev,&i_cdev_fops);//!綁定服務(wù)接口
   ret=cdev_add(&pscdev->i_cdev,ldev,1);//添加字符設(shè)備實(shí)例進(jìn)內(nèi)核
   if(ret<0){printk("Failture to add cdev to kernel!\n");
      return ret;
   }
   printk("Success to add cdev to kernel!\n");
   //!添加對(duì)應(yīng)的設(shè)備節(jié)點(diǎn)文件<--不需要重復(fù)建立dev_calss
   pscdev->dev_class_node=
   device_create(dev_class,NULL,ldev,NULL,"%s%d",
                 CHARDEVICE_NAME,MINOR(ldev));
   if(pscdev->dev_class_node==NULL){
     printk("Can not create a device file:/dev/%s%d\n",CHARDEVICE_NAME,MINOR(ldev));
     ret=PTR_ERR(pscdev->dev_class_node);
     return ret;//提取dev_class_node中的錯(cuò)誤代號(hào)給ret
   }
   printk("Success to create device node file:/dev/%s%d\n",CHARDEVICE_NAME,MINOR(ldev));
  
   s3c2410_gpio_cfgpin(gpio_table[index], gpio_cfg_table[index]);//配置對(duì)應(yīng)LED的GPIO引腳為輸出
   s3c2410_gpio_setpin(gpio_table[index], 1);
   //!s3c2410_gpio_cfgpin用于配置控制寄存器
   return 0;
}

static int __init chardevice_init(void)
{
   int ret=-EFAULT, i=0,x=0;
   printk(KERN_ALERT "Entry %s function!\n",__FUNCTION__);
   //!注冊(cè)設(shè)備編號(hào)
   if(chardevice_major!=0){//!手動(dòng)指定生成設(shè)備編號(hào)
     dev=MKDEV(CHARDEVICE_MAJOR,CHARDEVICE_MINOR);//由主次編號(hào)合成  
     ret=register_chrdev_region(dev,CHARDEVICE_COUNT,
                              CHARDEVICE_NAME);//在系統(tǒng)中注冊(cè)
   }
   else {//!由系統(tǒng)自動(dòng)動(dòng)態(tài)生成設(shè)備編號(hào)
     ret=alloc_chrdev_region(&dev,chardevice_minor,CHARDEVICE_COUNT,
                              CHARDEVICE_NAME);//由alloc_chrdev_region動(dòng)態(tài)確定一個(gè)空閑的設(shè)備編號(hào)供應(yīng)給dev
     chardevice_major=MAJOR(dev);//在設(shè)備編號(hào)中提取主編號(hào)                       
   }
   //!錯(cuò)誤處理 
     if(ret<0){
       printk("Can not reg char dev:Major:%d!\n",
              chardevice_major); goto failure_reg_chrdev;
     }
       printk("Success to reg char dev:Major:%d!\n",
              chardevice_major);
   //建立類對(duì)象
   dev_class=class_create(THIS_MODULE,CHARDEVICE_CLASS_NAME);//創(chuàng)建并限定類結(jié)構(gòu)變量指向本模塊,并指定類名稱
   if(dev_class==NULL){printk("Can not create a device class:%s!\n",
      CHARDEVICE_CLASS_NAME); ret=PTR_ERR(dev_class);
      goto failure_create_class;//提取dev_class中的錯(cuò)誤代號(hào)給ret
   } 
   printk("Success to create device class:%s!\n",CHARDEVICE_CLASS_NAME);  
 
   //!動(dòng)態(tài)分配內(nèi)核空間并在內(nèi)核中添加一個(gè)(以上)自定義的字符設(shè)備實(shí)例
   i_scdev=
   kmalloc(sizeof(struct self_cdev)*CHARDEVICE_COUNT,GFP_KERNEL);
   if(i_scdev==NULL){printk("No enough memory for i_scdev!\n");
   ret=PTR_ERR(i_scdev);goto failure_alloc_scdev;}
   memset(i_scdev,0,sizeof(struct self_cdev)*CHARDEVICE_COUNT);
   for(i=0;i<CHARDEVICE_COUNT;i++){
      ret=chardevice_add(&i_scdev[i],i);//第二個(gè)參數(shù)指定次設(shè)備號(hào)偏移量(在首個(gè)設(shè)備次設(shè)備號(hào)基礎(chǔ))
      if(ret<0)goto failure_scdev_add;
   }
   return 0;
//定義下邊這些錯(cuò)誤處理是因?yàn)樵诔跏蓟痏_init里出問題,是不能用rmmod去反安裝模塊,也就不會(huì)調(diào)用到__exit相關(guān)的函數(shù)
failure_scdev_add:
   for(x=0;x<i;x++){
   device_destroy(dev_class,MKDEV(chardevice_major,chardevice_minor+x));
   cdev_del(&(i_scdev[x].i_cdev));
   }
   class_destroy(dev_class);
failure_create_class:
   kfree(i_scdev);
failure_alloc_scdev:
   unregister_chrdev_region(dev,CHARDEVICE_COUNT);
failure_reg_chrdev:
   return ret;
}
static void __exit chardevice_exit(void)
{
   int x;
   printk(KERN_ALERT "Entry %s function!\n",__FUNCTION__);
  
   for(x=0;x<CHARDEVICE_COUNT;x++){
   //!清理指定設(shè)備的節(jié)點(diǎn)文件
   device_destroy(dev_class,MKDEV(chardevice_major,chardevice_minor+x));
   //!刪除內(nèi)核中的指定設(shè)備實(shí)例
   cdev_del(&(i_scdev[x].i_cdev));
   }
   //!刪除類對(duì)象
   class_destroy(dev_class);
   //!釋放內(nèi)核堆空間
   kfree(i_scdev);
   //!注銷設(shè)備編號(hào)
   unregister_chrdev_region(dev,CHARDEVICE_COUNT);
}
module_init(chardevice_init);
module_exit(chardevice_exit);
MODULE_AUTHOR("ELCO");
MODULE_DESCRIPTION("...");
MODULE_VERSION("1.0.0");
MODULE_ALIAS("CharDevice!");
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市义辕,隨后出現(xiàn)的幾起案子虾标,更是在濱河造成了極大的恐慌,老刑警劉巖灌砖,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件璧函,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡基显,警方通過查閱死者的電腦和手機(jī)蘸吓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來撩幽,“玉大人美澳,你說我怎么就攤上這事。” “怎么了制跟?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵舅桩,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我雨膨,道長(zhǎng)擂涛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任聊记,我火速辦了婚禮撒妈,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘排监。我一直安慰自己狰右,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布舆床。 她就那樣靜靜地躺著棋蚌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪挨队。 梳的紋絲不亂的頭發(fā)上谷暮,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音盛垦,去河邊找鬼湿弦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛腾夯,可吹牛的內(nèi)容都是我干的颊埃。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蝶俱,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼竟秫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起跷乐,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤肥败,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后愕提,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體馒稍,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年浅侨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纽谒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡如输,死狀恐怖鼓黔,靈堂內(nèi)的尸體忽然破棺而出央勒,到底是詐尸還是另有隱情,我是刑警寧澤澳化,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布崔步,位于F島的核電站,受9級(jí)特大地震影響缎谷,放射性物質(zhì)發(fā)生泄漏井濒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一列林、第九天 我趴在偏房一處隱蔽的房頂上張望瑞你。 院中可真熱鬧,春花似錦希痴、人聲如沸者甲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽虏缸。三九已至,卻和暖如春纺铭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背刀疙。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工舶赔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谦秧。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓竟纳,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親疚鲤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子锥累,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容