欧美亚洲一区二区三区,午夜欧美艳情视频免费看,欧美XXXXX又粗又大,国精品产露脸偷拍视频

技術(shù)文摘

GSC3280的ADC子系統(tǒng)驅(qū)動模型(二)












一、ADC子系統(tǒng)--創(chuàng)建設(shè)備文件

本部分包括創(chuàng)建設(shè)備節(jié)點和在應(yīng)用層通過操作/dev目錄下的設(shè)備節(jié)點來控制設(shè)備。

1.1、創(chuàng)建設(shè)備節(jié)點

在第一篇文章中的ADC子系統(tǒng)核心的注冊函數(shù)中,調(diào)用了adc_dev_init();函數(shù),該函數(shù)如下:

1.  void __init adc_dev_init(void)

2.  {

3.      int err;

4.   

5.      err = alloc_chrdev_region(&adc_devt, 0, ADC_DEV_MAX, "adc");

6.      if (err < 0) {

7.          DBG("!!!!!!alloc chrdev region error!!!!!!\n");

8.          printk(KERN_ERR "%s: failed to allocate char dev region\n", __FILE__);

9.      }

10.}


對應(yīng)退出函數(shù),調(diào)用adc_dev_exit();函數(shù),函數(shù)如下:
1.  void __exit adc_dev_exit(void)
2.  {
3.      if (adc_devt)
4.          unregister_chrdev_region(adc_devt, ADC_DEV_MAX);
5.  }

說明:

1、初始化函數(shù)主要為創(chuàng)建設(shè)備節(jié)點做準備。

2、退出函數(shù)是初始化函數(shù)的相反過程。

在第一篇文章的ADC子系統(tǒng)核心注冊和注銷函數(shù)中,調(diào)用了dev增加設(shè)備函數(shù)adc_dev_add_device()和dev刪除函數(shù)adc_dev_del_device(),程序如下:

1.  void adc_dev_add_device(struct adc_core_dev *adc)

2.  {

3.      if (cdev_add(&adc->char_dev, adc->dev.devt, 1)) {

4.          DBG("!!!!!!cdev add error.!!!!!!\n");

5.          printk(KERN_WARNING "%s: failed to add char device %d:%d\n",

6.                  adc->name, MAJOR(adc_devt), adc->id);

7.      }

8.      else {

9.          pr_debug("%s: dev (%d:%d)\n", adc->name, MAJOR(adc_devt), adc->id);

10.    }

11.}

12. 

13.void adc_dev_del_device(struct adc_core_dev *adc)

14.{

15.    if (adc->dev.devt)

16.        cdev_del(&adc->char_dev);

17.}


在ADC子系統(tǒng)核心注冊函數(shù)中,調(diào)用了adc_dev_prepare()函數(shù)實現(xiàn)增加dev操作函數(shù)集,具體內(nèi)容如下:

1.  static const struct file_operations adc_dev_fops = {

2.      .owner            = THIS_MODULE,

3.      .llseek            = no_llseek,

4.      .unlocked_ioctl    = adc_dev_ioctl,

5.      .open            = adc_dev_open,

6.      .release            = adc_dev_release,

7.  };

8.   

9.  void adc_dev_prepare(struct adc_core_dev *adc)

10.{

11.    if (!adc_devt) {

12.        DBG("!!!!!!adc_devt = 0!!!!!!\n");

13.        return;

14.    }

15.    if (adc->id >= ADC_DEV_MAX) {

16.        DBG("!!!!!!adc dev prepare error,id too many!!!!!!\n");

17.        pr_debug("%s: too many ADC devices\n", adc->name);

18.        return;

19.    }

20.    adc->dev.devt = MKDEV(MAJOR(adc_devt), adc->id);

21.    cdev_init(&adc->char_dev, &adc_dev_fops);

22.    adc->char_dev.owner = adc->owner;

23.}


說明:

1、首先對設(shè)備號進行檢查。

2、計算設(shè)備號。

3、增加操作函數(shù)集,該函數(shù)集主要涉及到兩個函數(shù),一個打開函數(shù)adc_dev_open()和一個控制函數(shù)adc_dev_ioctl(),首先看下打開函數(shù):

1.  static int adc_dev_open(struct inode *inode, struct file *file)

2.  {

3.      int err;

4.      struct adc_core_dev *adc = container_of(inode->i_cdev, struct adc_core_dev, char_dev);

5.   

6.      if (test_and_set_bit_lock(ADC_DEV_BUSY, &adc->flags))

7.          return -EBUSY;

8.      file->private_data = adc;

9.      err = adc->ops->open ? adc->ops->open(adc->dev.parent) : 0;

10.    if (err == 0) {

11.        return 0;

12.    }

13.    /* something has gone wrong */

14.    clear_bit_unlock(ADC_DEV_BUSY, &adc->flags);

15.    return err;

16.}


說明:

1、使用container_of通過設(shè)備號獲取在adc_device_register()函數(shù)中創(chuàng)建的adc-core結(jié)構(gòu)體。

2、測試設(shè)備是否忙,如果忙,直接退出。如果不忙,設(shè)置忙標志。

3、判斷adc-core的操作函數(shù)集是否包括open函數(shù),通過第一篇文章我們知道,adc-core的函數(shù)操作集只有一個轉(zhuǎn)換函數(shù),所以此處err直接等于0,退出。

命令控制函數(shù)adc_dev_ioctl()如下:

1.  #define ADC_DEV_IOC_MAGIC            'a'

2.  #define ADC_DEV_IOC_MAXNR            2

3.  #define ADC_DEV_CON_PBAT            _IOR(ADC_DEV_IOC_MAGIC, 0, int)

4.  #define ADC_DEV_CON_CHX            _IOWR(ADC_DEV_IOC_MAGIC, 1, int)

5.  static long adc_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

6.  {

7.      int err = 0, channel = 0;

8.      unsigned short adc_cmd = 0;

9.      struct adc_core_dev *adc = file->private_data;

10.    void __user *argp = (void __user *)arg;

11.    int __user *p = argp;

12. 

13.    err = mutex_lock_interruptible(&adc->ops_lock);

14.    if (err)

15.        return err;

16.    if ((_IOC_TYPE(cmd) != ADC_DEV_IOC_MAGIC) || (_IOC_NR(cmd) > ADC_DEV_IOC_MAXNR)) {

17.        err = -ENOTTY;

18.        goto exit;

19.    }

20.    switch(cmd) {

21.    case ADC_DEV_CON_PBAT:

22.        adc_cmd = CMD_AD_CON_PBAT;

23.        break;

24.    case ADC_DEV_CON_CHX:

25.        if (get_user(channel, p)) {

26.            err = -EFAULT;

27.            goto exit;

28.        }

29.        switch (channel) {

30.        case 0:

31.            adc_cmd = CMD_AD_CON_CH0;

32.            break;

33.        case 1:

34.            adc_cmd = CMD_AD_CON_CH1;

35.            break;

36.        case 2:

37.            adc_cmd = CMD_AD_CON_CH2;

38.            break;

39.        case 3:

40.            adc_cmd = CMD_AD_CON_CH3;

41.            break;

42.        }

43.        break;

44.    default:

45.        err = -ENOTTY;

46.        goto exit;

47.    }

48.    DBG("adc_cmd = 0x%x\n", adc_cmd);

49.    put_user(adc->ops->convert(adc_cmd), p);

50. 

51.exit:

52.    mutex_unlock(&adc->ops_lock);

53.    return err;

54.}

說明:
1、此處共有兩條命令。
2、命令控制函數(shù)首先對命令有效性進行檢查。
3、第一條是測量pbat命令,直接賦命令值。
4、第二條命令是對AD轉(zhuǎn)換通道進行測量,此處包括一個通道值,所以先從應(yīng)用層獲取通道值。
5、最后調(diào)用adc-core操作函數(shù)集中的轉(zhuǎn)換函數(shù),也就是第一篇文章中的gsc3280AdcCon()進行AD轉(zhuǎn)換。
6、將轉(zhuǎn)換結(jié)果發(fā)送給應(yīng)用層。

dev釋放函數(shù)adc_dev_release()如下:

1.  static int adc_dev_release(struct inode *inode, struct file *file)

2.  {

3.      struct adc_core_dev *adc = file->private_data;

4.   

5.      if (adc->ops->release)

6.          adc->ops->release(adc->dev.parent);

7.      clear_bit_unlock(ADC_DEV_BUSY, &adc->flags);

8.      return 0;

9.  }


說明:

1、判斷adc-core的操作函數(shù)集是否包括release函數(shù),通過第一篇文章我們知道,adc-core的函數(shù)操作集只有一個轉(zhuǎn)換函數(shù),所以此處不執(zhí)行if語句里面內(nèi)容。

2、清除忙標志。







1.2、應(yīng)用層測試程序

應(yīng)用層測試程序如下:

1.  #include <fcntl.h>

2.  #include <stdio.h>

3.  #include <stdlib.h>

4.  #include <sys/ioctl.h>

5.  #include <linux/ioctl.h>

6.   

7.  #define ADC_DEV_IOC_MAGIC            'a'

8.  #define ADC_DEV_IOC_MAXNR            2

9.  #define ADC_DEV_CON_PBAT            _IOR(ADC_DEV_IOC_MAGIC, 0, int)

10.#define ADC_DEV_CON_CHX            _IOWR(ADC_DEV_IOC_MAGIC, 1, int)

11.int main(int argc, char **argv)

12.{

13.    //unsigned char buff[2] = {0};

14.    unsigned int idCmd = 0;

15.    int fd = 0, ret = 0, data = 0;

16.    

17.    //以阻塞方式打開設(shè)備文件,非阻塞時flags=O_NONBLOCK

18.    fd = open("/dev/adc0", 0);

19.    if (fd < 0) {

20.        printf("Open ADC Device Faild!\n");

21.        exit(1);

22.    }

23.    while(1) {

24.        data = 1;

25.        idCmd = ADC_DEV_CON_CHX;

26.        ret = ioctl(fd, idCmd, &data);

27.        if (ret != 0) {

28.            printf("Read ADC Device Faild!\n");

29.            break;

30.        } else {

31.            //data = buff[0] | (buff[1] << 8);

32.            printf("Read ADC value is: %d\n", data);

33.        }

34.        for (ret = 0; ret < 6553600; ret++)

35.            ; 

36.    }

37.    close(fd);

38.    return 0;

39.}

說明:
1、首先打開設(shè)備
2、設(shè)置通道1和采集通道命令,調(diào)用ioctl實現(xiàn)AD采集
3、如果采集正確,打印數(shù)據(jù)
4、延時后,循環(huán)再一次采集數(shù)據(jù),具體測試圖如下:


應(yīng)用層測試程序.png







二、sysfs文件系統(tǒng)和測試

2.1、sysfs文件系統(tǒng)

在第一篇文章中的ADC子系統(tǒng)核心的注冊函數(shù)中,調(diào)用了adc_sysfs_init();函數(shù),該函數(shù)如下:
1.  void __init adc_sysfs_init(struct class *adc_class)
2.  {
3.      adc_class->dev_attrs = adc_attrs;
4.  }


該函數(shù)增加了一個device_attribute屬性--adc_attrs,device_attribute屬性將在第三篇文章講述,adc_attrs具體內(nèi)容如下:

1.  #define to_adc_device(d) container_of(d, struct adc_core_dev, dev)

2.  /* device attributes */

3.  static ssize_t

4.  adc_sysfs_show_name(struct device *dev, struct device_attribute *attr, char *buf)

5.  {

6.      return sprintf(buf, "%s\n", to_adc_device(dev)->name);

7.  }

8.   

9.  static ssize_t

10.adc_sysfs_show_pbat(struct device *dev, struct device_attribute *attr,

11.        char *buf)

12.{

13.    int result = 0;

14.    struct adc_core_dev *adc = to_adc_device(dev);

15. 

16.    result = adc->ops->convert(CMD_AD_CON_PBAT);

17.    printk(KERN_INFO "pbat = %d\n", result);

18.    sprintf(buf, "%d\n", result);

19.    return 0;

20.}

21. 

22.static ssize_t

23.adc_sysfs_show_ch0(struct device *dev, struct device_attribute *attr,

24.        char *buf)

25.{

26.    int result = 0;

27.    struct adc_core_dev *adc = to_adc_device(dev);

28. 

29.    result = adc->ops->convert(CMD_AD_CON_CH0);

30.    printk(KERN_INFO "ch0 = %d\n", result);

31.    sprintf(buf, "%d\n", result);

32.    return 0;

33.}

34. 

35.static ssize_t

36.adc_sysfs_show_ch1(struct device *dev, struct device_attribute *attr,

37.        char *buf)

38.{

39.    int result = 0;

40.    struct adc_core_dev *adc = to_adc_device(dev);

41. 

42.    result = adc->ops->convert(CMD_AD_CON_CH1);

43.    printk(KERN_INFO "ch1 = %d\n", result);

44.    sprintf(buf, "%d\n", result);

45.    return 0;

46.}

47. 

48.static ssize_t

49.adc_sysfs_show_ch2(struct device *dev, struct device_attribute *attr,

50.        char *buf)

51.{

52.    int result = 0;

53.    struct adc_core_dev *adc = to_adc_device(dev);

54. 

55.    result = adc->ops->convert(CMD_AD_CON_CH2);

56.    printk(KERN_INFO "ch2 = %d\n", result);

57.    sprintf(buf, "%d\n", result);

58.    return 0;

59.}

60. 

61.static ssize_t

62.adc_sysfs_show_ch3(struct device *dev, struct device_attribute *attr,

63.        char *buf)

64.{

65.    int result = 0;

66.    struct adc_core_dev *adc = to_adc_device(dev);

67. 

68.    result = adc->ops->convert(CMD_AD_CON_CH3);

69.    printk(KERN_INFO "ch3 = %d\n", result);

70.    sprintf(buf, "%d\n", result);

71.    return 0;

72.}

73. 

74.static struct device_attribute adc_attrs[] = {

75.    __ATTR(name, S_IRUGO, adc_sysfs_show_name, NULL),

76.    __ATTR(pbat, S_IRUGO, adc_sysfs_show_pbat, NULL),

77.    __ATTR(ch0, S_IRUGO, adc_sysfs_show_ch0, NULL),

78.    __ATTR(ch1, S_IRUGO, adc_sysfs_show_ch1, NULL),

79.    __ATTR(ch2, S_IRUGO, adc_sysfs_show_ch2, NULL),

80.    __ATTR(ch3, S_IRUGO, adc_sysfs_show_ch3, NULL),

81.    { },

82.};


由以上程序可知,該屬性成員總共有六個成員,通過這種賦值,系統(tǒng)起來后,在根文件目錄/sys/class/adc/adc0下就有相應(yīng)的節(jié)點,操作相應(yīng)的節(jié)點,就相當于調(diào)相應(yīng)的函數(shù),比如操作節(jié)點pbat,則調(diào)用函數(shù)adc_sysfs_show_pbat()。其他節(jié)點類似。

各個節(jié)點函數(shù)類似,首先都是獲取adc-core結(jié)構(gòu)體,然后根據(jù)節(jié)點內(nèi)容不同,賦值不同命令,最后調(diào)用adc-core中的函數(shù)操作集中的轉(zhuǎn)換函數(shù)實現(xiàn)AD轉(zhuǎn)換。







2.2、應(yīng)用層測試

應(yīng)用層測試采用命令行的方式,具體如下圖:

應(yīng)用層測試程序2.png







三、proc文件系統(tǒng)和測試

3.1、proc文件系統(tǒng)

在ADC子系統(tǒng)注冊函數(shù)adc_device_register()中,調(diào)用了adc-proc.c中的adc_proc_add_device(adc);

函數(shù),具體內(nèi)容如下:
1.  static const struct file_operations adc_proc_fops = {

2.      .open    = adc_proc_open,

3.      .read    = seq_read,

4.      .llseek    = seq_lseek,

5.      .release    = adc_proc_release,

6.  };

7.   

8.  void adc_proc_add_device(struct adc_core_dev *adc)

9.  {

10.    if (adc->id == 0)

11.        proc_create_data("driver/adc", 0, NULL, &adc_proc_fops, adc);

12.}

13. 

14.void adc_proc_del_device(struct adc_core_dev *adc)

15.{

16.    if (adc->id == 0)

17.        remove_proc_entry("driver/adc", NULL);

18.}


說明:

1、使用proc_create_data()函數(shù)創(chuàng)建了函數(shù)操作函數(shù)集adc_proc_fops。

2、adc_proc_del_device()函數(shù)在ADC子系統(tǒng)注銷函數(shù)中調(diào)用,是adc_proc_add_device()函數(shù)的相反過程。

3、操作函數(shù)集adc_proc_fops涉及的函數(shù)如下:
1.  static int adc_proc_show(struct seq_file *seq, void *offset)

2.  {

3.      int result = 0;

4.      struct adc_core_dev *adc = seq->private;

5.      

6.      result = adc->ops->convert(CMD_AD_CON_PBAT);

7.      seq_printf(seq, "PBAT:%d\n", result);

8.      result = adc->ops->convert(CMD_AD_CON_CH0);

9.      seq_printf(seq, "CH0:%d\n", result);

10.    result = adc->ops->convert(CMD_AD_CON_CH1);

11.    seq_printf(seq, "CH1:%d\n", result);

12.    result = adc->ops->convert(CMD_AD_CON_CH2);

13.    seq_printf(seq, "CH2:%d\n", result);

14.    result = adc->ops->convert(CMD_AD_CON_CH3);

15.    seq_printf(seq, "CH3:%d\n", result);

16.    if (adc->ops->proc)

17.        adc->ops->proc(adc->dev.parent, seq);

18.    return 0;

19.}

20. 

21.static int adc_proc_open(struct inode *inode, struct file *file)

22.{

23.    int ret;

24.    struct adc_core_dev *adc = PDE(inode)->data;

25. 

26.    if (!try_module_get(THIS_MODULE)) {

27.        DBG("!!!!!!try_module_get error!!!!!!\n");

28.        return -ENODEV;

29.    }

30.    ret = single_open(file, adc_proc_show, adc);

31.    if (ret)

32.        module_put(THIS_MODULE);

33.    return ret;

34.}

35. 

36.static int adc_proc_release(struct inode *inode, struct file *file)

37.{

38.    int res = single_release(inode, file);

39.    module_put(THIS_MODULE);

40.    return res;

41.}


說明:       

1、open函數(shù)中首先獲得adc-core設(shè)備結(jié)構(gòu)體,使用single_open()函數(shù)調(diào)用dc_proc_show()函數(shù)。

2、釋放函數(shù)調(diào)用single_release()釋放設(shè)備。

3、adc_proc_show()函數(shù)中,使用adc-core的操作函數(shù)集的AD轉(zhuǎn)換函數(shù),實現(xiàn)AD轉(zhuǎn)換,也就是調(diào)用第一篇文章中設(shè)備驅(qū)動的gsc3280AdcCon()函數(shù)。

 4、gsc3280AdcCon()分別實現(xiàn)5路AD的轉(zhuǎn)換。







3.2、應(yīng)用層測試

應(yīng)用層測試采用命令行的方式,具體如下圖:

應(yīng)用層測試程序3.png







四、總結(jié)

在調(diào)試過程中出現(xiàn)過內(nèi)存泄露的問題,經(jīng)過調(diào)試發(fā)現(xiàn)是在系統(tǒng)啟動過程中,根據(jù)模塊啟動宏的不同,初始化是有順序的。把先使用的模塊先初始化,比如subsys_initcall(gsc_adc_init);。        

ADC核心使底層硬件對用戶來說是透明的,并且減少了編寫驅(qū)動程序的工作量。ADC新的驅(qū)動接口提供了更多的功能,使系統(tǒng)可以同時存在多個ADC。/dev,sysfs,proc這三種機制的實現(xiàn)使得應(yīng)用程序能靈活的使用ADC。

ADC核心代碼的組織方式值得學習,不同功能的代碼放在不同的文件中,簡單明了。

如果系統(tǒng)有另外一個AD轉(zhuǎn)換芯片,那么只需新增加設(shè)備驅(qū)動程序,在新的設(shè)備驅(qū)動程序中,使用函數(shù)adc_device_register() 注冊ADC子系統(tǒng),通過idr的id即可區(qū)分不同的ADC設(shè)備。




原文參見:http://blog.chinaunix.net/uid-25445243-id-4011337.html