天嵌 ARM开发社区

 找回密码
 注册
查看: 4596|回复: 16

無法新增led範例內ioctl的操作功能

[复制链接]
s1005056 发表于 2014-5-12 15:44:17 | 显示全部楼层 |阅读模式
各位版友們好,

在寫GPIO練習的時候遇上一些問題,還請高手幫忙看一下。因為想提供多一點細節,文長還請多包涵。
想要達成的目的是GPH3_0輸出高電平,利用GPH3_3監看輸入電平,然後在ioctl內多出IOCTL_GPIO_READ的操作,其他架構跟LED範例手冊內的相同。
程式碼如下:
  1. /* use led sample to test GPH3 is fine under control */
  2. /* run a complete LED sample, just change pins! */

  3. #include <linux/miscdevice.h>
  4. #include <linux/input.h>
  5. #include <linux/clk.h>
  6. #include <linux/delay.h>
  7. #include <asm/io.h>
  8. #include <asm/uaccess.h>

  9. #include <mach/map.h>
  10. #include <mach/gpio.h>
  11. //#include <mach/gpio-bank.h>
  12. #include <mach/regs-gpio.h>
  13. #include <plat/gpio-core.h>
  14. #include <plat/gpio-cfg.h>
  15. #include <plat/gpio-cfg-helpers.h>



  16. #define DEVICE_NAME "led3" /* change the name! */

  17. enum{
  18.         IOCTL_GPIO_ON = 0,
  19.         IOCTL_GPIO_READ,
  20.         IOCTL_GPIO_OFF,
  21. };

  22. //#define IOCTL_GPIO_ON        0
  23. //#define IOCTL_GPIO_OFF        1
  24. //#define IOCTL_GPIO_READ        2

  25. static unsigned long gpio_table [] =
  26. {
  27.         S5PV210_GPH3(1), /* output, KP_ROW1, have voltage change */
  28.         S5PV210_GPH3(3), /* input, KP_ROW3 */
  29. };

  30. static unsigned int gpio_cfg_table [] =
  31. {
  32. //        S3C_GPIO_SFN(1),
  33. //        S3C_GPIO_SFN(1),
  34.         S3C_GPIO_SFN(1),
  35.         S3C_GPIO_SFN(0),
  36. };


  37. static int tq210_gpio_open(struct inode *inode, struct file *file)
  38. {
  39.         int i;
  40.         int err;
  41.         err = gpio_request(gpio_table[0], "GPH3_1");
  42.         if(err)
  43.         {
  44.                 printk(KERN_ERR "failed to request GPH3_1 for LVDS PWDN pin\n");
  45.         return err;
  46.         }
  47.         err = gpio_request(gpio_table[1], "GPH3_3");
  48.         if(err)
  49.         {
  50.                 printk(KERN_ERR "failed to request GPH3_3 for LVDS PWDN pin\n");
  51.         return err;
  52.         }
  53.         printk(KERN_INFO " leds opened\n");
  54.         for (i = 0; i < sizeof(gpio_table)/sizeof(unsigned long); i++)
  55.         {
  56.                 s3c_gpio_cfgpin(gpio_table[i], gpio_cfg_table[i]);
  57.                 // gpio_direction_output(gpio_table[i], 0);
  58.         }

  59.         gpio_direction_output(gpio_table[0], 0);
  60.         gpio_direction_input(gpio_table[1]);

  61.         return 0;

  62. }


  63. static long tq210_gpio_ioctl(
  64.         struct file *file,
  65.         unsigned int cmd,
  66.         unsigned long arg)
  67. {
  68.         int res;
  69.         
  70.         printk(KERN_INFO "+%s, cmd = %hd\n", __func__, cmd);
  71.                
  72.         arg -= 1;
  73.         if (arg > sizeof(gpio_table)/sizeof(unsigned long))
  74.         {
  75.                 printk(KERN_INFO "error! ");
  76.                 return -EINVAL;
  77.         }

  78.         switch(cmd)
  79.         {
  80.                 case IOCTL_GPIO_ON:
  81.                         printk(KERN_INFO "[OUTPUT] HIGH ");
  82.                         gpio_direction_output(gpio_table[arg], 1);
  83.                         return 0;

  84.                 case IOCTL_GPIO_OFF:
  85.                         printk(KERN_INFO "[OUTPUT] LOW ");
  86.                         gpio_direction_output(gpio_table[arg], 0);
  87.                         return 0;

  88.                 case IOCTL_GPIO_READ:
  89.                         res = gpio_get_value(gpio_table[arg]);
  90.                         if (res < 0){
  91.                                 printk(KERN_INFO "(X) Fail");
  92.                         }else if(res == 0){
  93.                                 printk(KERN_INFO "[INPUT] LOW ");
  94.                         }else{
  95.                                 printk(KERN_INFO "[INPUT] HIGH");
  96.                         }
  97.                         return 0;

  98.                 default:
  99.                         return -EINVAL;
  100.         }
  101. }

  102. static int tq210_gpio_close(struct inode *inode, struct file *file)
  103. {
  104.         gpio_free(gpio_table[0]);
  105.         gpio_free(gpio_table[1]);
  106.         printk(KERN_INFO "TQ210 LEDs driver successfully close\n");
  107.         return 0;
  108. }

  109. static struct file_operations dev_fops = {
  110.         .owner        =        THIS_MODULE,
  111.         .unlocked_ioctl        =        tq210_gpio_ioctl,
  112.         .open = tq210_gpio_open,
  113.         .release = tq210_gpio_close,
  114. };

  115. static struct miscdevice misc = {
  116.         .minor = MISC_DYNAMIC_MINOR,
  117.         .name = DEVICE_NAME,
  118.         .fops = &dev_fops,
  119. };

  120. static int __init dev_init(void)
  121. {
  122.         int ret;

  123.         ret = misc_register(&misc);
  124.         if(ret == 0)
  125.                 printk(KERN_INFO "TQ210 LEDs driver successfully probed\n");

  126.         return ret;
  127. }

  128. static void __exit dev_exit(void)
  129. {
  130.         misc_deregister(&misc);
  131.         gpio_free(gpio_table[0]);
  132.         gpio_free(gpio_table[1]);
  133.         printk(KERN_INFO "TQ210 LEDs driver successfully exit\n");
  134. }

  135. module_init(dev_init);
  136. module_exit(dev_exit);

  137. MODULE_LICENSE("GPL");
  138. MODULE_AUTHOR("Paul <shufexiu@163.com>");
  139. MODULE_DESCRIPTION("LEDS' Driver");
复制代码

測試用之應用程式的主要流程:open->LED1輸出高電平->讀取LED2腳位10次->LED2輸出低電平,期間可以手動插拔電線就可以改變電平,確認輸入值的變動。
程式碼如下:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/types.h>
  4. #include <asm/types.h>
  5. #include <linux/fb.h>
  6. #include <linux/kernel.h>
  7. #include <linux/fs.h>
  8. #include <fcntl.h>
  9. #include<string.h>
  10. #include<unistd.h>
  11. #include<sys/mman.h>
  12. #include <sys/poll.h>

  13. #define DEV_FILE_NAME                "/dev/led3"        
  14. /* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */     
  15. /* #define IOCTL_GPIO_ON        0
  16. #define IOCTL_GPIO_OFF        1
  17. #define IOCTL_GPIO_READ        2 */
  18. enum{
  19.         IOCTL_GPIO_ON = 0,
  20.         IOCTL_GPIO_READ,
  21.         IOCTL_GPIO_OFF,
  22. };

  23. #define LED1                1               
  24. #define LED2                2               
  25.                      
  26. int main(void)
  27. {
  28.         int devfd;
  29.         int i,err;
  30.         
  31.         devfd = open(DEV_FILE_NAME,O_RDWR);               

  32.         if(devfd < 0)                        
  33.         {
  34.                 printf("can't open dev (%s)",DEV_FILE_NAME);
  35.                 return 0;
  36.         }


  37.         err = ioctl(devfd,IOCTL_GPIO_ON,LED1);
  38.         if(err<0)
  39.                 printf("GPIO_ON faild! (%d)\n",err);
  40.         sleep(1);        
  41.         
  42.         for(i=0;i<10;++i)
  43.         {
  44.                
  45.                 err = ioctl(devfd,IOCTL_GPIO_READ,LED2);
  46.                 if(err<0)
  47.                         printf("GPIO_READ faild! (%d)\n",err);                        
  48.                 sleep(2);        

  49.         }

  50.         err = ioctl(devfd,IOCTL_GPIO_OFF,LED1);//关闭LED1。
  51.         if(err<0)
  52.                 printf("GPIO_OFF faild! (%d)\n",err);
  53.         sleep(2);        //休眠1S
  54.         
  55.         close(devfd);//关闭设备。对应驱动中的tq210_gpio_close
  56.         return 0;
  57. }

复制代码

目前遇到的問題是,在最前面定義ioctl的cmd參數時,不曉得為什麼只能新增兩個參數,不管是用define或是enum,不管是從0開始還是從1開始,都會發生如下的狀況:
(一)參數從0開始
  1. enum{
  2.         IOCTL_GPIO_ON = 0,
  3.         IOCTL_GPIO_READ,
  4.         IOCTL_GPIO_OFF,
  5. };
复制代码
則輸出如下圖,可以發現IOCTL_GPIO_ON(0)以及IOCTL_GPIO_READ(1)皆正常進入操作,而IOCTL_GPIO_OFF(2)則運行失敗...



(二)後來想把enum從1開始試試,
  1. enum{
  2. IOCTL_GPIO_ON = 1,
  3. IOCTL_GPIO_READ,
  4. IOCTL_GPIO_OFF,
  5. };
复制代码
卻是IOCTL_GPIO_ON(1)以及IOCTL_GPIO_OFF(3)正常運作,反而是夾在中間的IOCTL_GPIO_READ(2)無法進行操作


到底要怎麼修改才能加入新的操作呢...或是有哪裏使用了不正確的語法,還請各位大師們解惑,感激不盡~~

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
Calvin 发表于 2014-5-13 13:42:12 | 显示全部楼层
本帖最后由 Calvin 于 2014-5-13 13:43 编辑

好低级的错误啊  自己围绕一下数组的相关知识再查看一下 最好再仔细看一下我们提供的例程;你自己的程序有问题
 楼主| s1005056 发表于 2014-5-13 16:21:26 | 显示全部楼层
Calvin 发表于 2014-5-13 13:42
好低级的错误啊  自己围绕一下数组的相关知识再查看一下 最好再仔细看一下我们提供的例程;你自己 ...

正是因為看了一兩天還看不出來所以才上來詢問的~"~
做練習的意義就是想要知道自己哪裡還沒看懂,但是現在這個錯誤實在毫無頭緒...

可以請Calvin再多給些提示嗎?
Calvin 发表于 2014-5-14 08:59:44 | 显示全部楼层
s1005056 发表于 2014-5-13 16:21
正是因為看了一兩天還看不出來所以才上來詢問的~"~
做練習的意義就是想要知道自己哪裡還沒看懂,但是現 ...

你一行一行对比我们给的例程 就可以发现了
 楼主| s1005056 发表于 2014-5-14 11:56:00 | 显示全部楼层
本帖最后由 s1005056 于 2014-5-14 13:19 编辑

------如下------
 楼主| s1005056 发表于 2014-5-14 11:57:30 | 显示全部楼层
剛剛在比對的過程中,想到會不會是ioctl的cmd是不正確的,亦即不能使用2作為cmd,因為兩個方式都是無法讓參數2的命令正確被執行,似乎在user space就被擋下了
 楼主| s1005056 发表于 2014-5-14 13:19:10 | 显示全部楼层
Calvin 发表于 2014-5-14 08:59
你一行一行对比我们给的例程 就可以发现了

剛剛比對了一下,還是沒意會到關於数组的任何錯誤

可以請Calvin大指出是哪一個函數的哪部分嗎?
或許是我的觀念原本就錯了,所以怎麼看也看不出來
感謝您的幫忙
 楼主| s1005056 发表于 2014-5-14 13:20:24 | 显示全部楼层
Calvin 发表于 2014-5-14 08:59
你一行一行对比我们给的例程 就可以发现了

剛剛在比對的過程中,想到會不會是ioctl的cmd是不正確的,亦即不能使用2作為cmd,因為兩個方式都是無法讓參數2的命令正確被執行,似乎在user space就被擋下了
 楼主| s1005056 发表于 2014-5-14 13:40:46 | 显示全部楼层
本帖最后由 s1005056 于 2014-5-14 14:40 编辑

由於在比對之後還是沒看到有什麼錯誤,所以還是把我的想法先列出來,Calvin大可以直接點出在哪一個步驟有問題。我想這樣會比較快,若是一開始就想錯了,再看個幾百次也沒用。

首先是驅動程式:

變數新增的部分:
1. 不想與TQ210自帶的led驅動相重疊,所以修改了一個DEVICE_NAME成為"led3"
2. 需要多一個IOCTL_GPIO_READ指令,使用enum列舉需要的狀態,以後需要新增刪除指令時也不會太麻煩
3. 修改gpio_table,改為使用GPH3_1以及GPH3_3的腳位
4. 修改gpio_cfg_table,需要GPH3_1為輸出,而GPH3_3為輸入,參考s5pv210晶片手冊,確認S3C_GPIO_SFN之參數設定,搜尋kernel源碼,確認該管腳沒有被占用(key_ownx.c為自行新增之檔案)















dev_init以及dev_exit:
1. 在init的部分,將CONFIG_TQ210_DEBUG_LEDS的部分刪去,將這部分的功能留在open的時候才執行。因此init內部僅剩註冊功能,加入ret==0判斷是確保device driver有正常註冊
2.在exit的部分,維持原有的撤銷driver以及釋放gpio
3. miscdevice以及file_operations結構皆與範例程式相同

tq210_gpio_open與tq210_gpio_close中對管腳的設定:
1. 修改gpio_request申請的gpio管腳以及label
2. 修改for迴圈中對管腳的初始設定,官方範使用s3c_gpio_cfgpin(gpio_table, gpio_cfg_table)為管腳配置指定功能,這部分繼續放置在for迴圈中;而gpio_direction_output(gpio_table, 0);為方向標記設定,由於管腳需分別進行輸出/輸入方向標記設定,因此拉出for迴圈之外
3. gpio_direction_output設定為模仿範例設定;gpio_direction_input設定為參考說明手冊,http://www.eoeandroid.com/blog-23065-4660.html中說明gpio_direction_input似乎僅設定訊號方向,而非如手冊中所述可以「讀取管腳gpio狀態」,這部分還待版上高手分析與解惑,目前功力還無法參透源碼中的含意
4. tq210_gpio_close與範例程式相同



tq210_gpio_ioctl對指令的設定:
1. 使用printk顯示當前收到的cmd數值,另一方面也是可以確認驅動程式是否有正確執行,若有成功呼叫到驅動,則會顯示該行訊息,然而在使用測試程式的ioctl呼叫錯誤發生時,該行訊息並無出現,故推測應該是卡在更之前的流程
2. 在switch中新增「case IOCTL_GPIO_READ:」, 使用http://www.eoeandroid.com/blog-23065-4660.html中所述之gpio_get_value函數來實作讀取管腳輸入數值的動作,並依據回傳值而有不同的printk輸出





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
 楼主| s1005056 发表于 2014-5-14 15:22:19 | 显示全部楼层
接下來為應用測試程式:

變數設置:
1. 修改DEV_FILE_NAME為"/dev/led3"與驅動程式內DEVICE_NAME相符
2. 設置IOCTL_GPIO_READ指令,一樣使用enum列舉需要的指令
3. 續用LED1與LED2做識別
[size=15.555556297302246px]

[size=15.555556297302246px]

open device file與範例相同




接下來的部分更動了程式流程:
1. 讓GPH3_1持續輸出高電平
2. 之後便每隔兩秒讀取GPH3_3的輸入值,讀取10次
3. 之後便關閉GPH3_3的輸出,關閉device file


1 & 3皆與範例程式相同





2的部分則為自行新增的功能
err = ioctl(devfd,IOCTL_GPIO_READ,LED2);,關於第2個參數IOCTL_GPIO_READ,應用程式與驅動使用相同的enum進行枚舉,故應為相同之數值2;關於第3個參數,在應用程式中雖然為2,但是tq210_gpio_ioctl驅動中有將arg -=1;因此是指向gpio_table[1]沒錯,(Calvin大所說與数组有關的錯誤,目前只想到可能會是這裡,不知道哪裡還有錯誤的用法,還請Calvin大提醒)



[size=15.555556297302246px]

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
 楼主| s1005056 发表于 2014-5-15 13:41:59 | 显示全部楼层
本帖最后由 s1005056 于 2014-5-20 17:32 编辑

--如#9所示--
 楼主| s1005056 发表于 2014-5-20 17:30:36 | 显示全部楼层
Calvin 发表于 2014-5-14 08:59
你一行一行对比我们给的例程 就可以发现了

Calvin版主好:
這幾天還是看不出哪裡有數組的相關錯誤,已將程式碼以及流程置於9樓、10樓,還請您抽空解惑一下,謝謝。
 楼主| s1005056 发表于 2014-5-23 16:44:20 | 显示全部楼层
Calvin 发表于 2014-5-13 13:42
好低级的错误啊  自己围绕一下数组的相关知识再查看一下 最好再仔细看一下我们提供的例程;你自己 ...

Calvin版主好:
這幾天還是看不出哪裡有數組的相關錯誤,已將程式碼以及流程置於9樓、10樓,還請您抽空解惑一下,謝謝。
copyleft 发表于 2014-6-3 10:18:42 | 显示全部楼层
这个问题我也出现过,在ioctl中我试了很久才发现:
    在内核驱动中ioctl中cmd参数如果是2的话,好像无论如何都不能执行成功,解决办法:
#define IOCTL_GPIO_OFF      0
#define IOCTL_GPIO_ON        1
#define IOCTL_GPIO_READ    3
也就是 ioctl 的命令直接跳过2,就可以了,具体原因我也不知道为什么,感觉好像在2在什么地方已经使用了,但到底在什么使用了,这我就不知道了,我从Android上面传入内核中ioctl的cmd为2时,在内核通过printf得到的cmd好像变成了0,好像是这样,我记不准确了,你可以试试在内核中输出cmd,一个比较方便的解决 方法 就是直接跳过2,使用后面的数字作为cmd
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

i.MX8系列ARM cortex A53 M4 工控板上一条 /1 下一条

Archiver|手机版|小黑屋|天嵌 嵌入式开发社区 ( 粤ICP备11094220号 )

GMT+8, 2024-5-7 01:53 , Processed in 1.046875 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表