linux4.9通過ioctl進(jìn)行底層和上層通訊的功能说莫,其中已實(shí)現(xiàn)應(yīng)用層通過初始化底層設(shè)備參數(shù),以及先給底層設(shè)備設(shè)置所需要讀取的內(nèi)容奢入,再獲取設(shè)備對(duì)應(yīng)內(nèi)容產(chǎn)生的數(shù)據(jù)展辞。
公共參數(shù)如下:
????????typedef struct {
????????????int channel_value;
????????????int adc_value;
? ? ? ? }TEST_ADC_CONFIG_READ;
????????#define TESTADC_IOC_MAGIC 'a'
????????#define IOCTL_TEST_INIT? _IO(TESTADC_IOC_MAGIC, 0)
????????#define IOCTL_TEST_SET_CHANNEL_READ_VALUE? _IO(TESTADC_IOC_MAGIC, 1)
底層部分:
? ? 1:申明一個(gè)misc設(shè)備,以及其自帶的文件操作接口
????????#define DEVICE_NAME kyan
? ? ? ? static const struct file_operations kyan_fops =
? ? ? ? {
? ? ? ? ? ? .open? ? = ms_kyan_open,
? ? ? ? ? ? .unlocked_ioctl = ms_kyan_ioctl,
? ? ? ? };
? ? ? ? static struct miscdevice kyan_miscdev = {MISC_DYNAMIC_MINOR, DEVICE_NAME, &kyan_fops};
? ? 2:通過設(shè)備注冊(cè)將misc設(shè)備注冊(cè)進(jìn)內(nèi)核划提,注冊(cè)成功之后會(huì)在dev目錄下新建命名為kyan的文件枫弟。
? ? ? ? misc_register(&kyan_miscdev);
? ? 3:當(dāng)?shù)讓愉N毀時(shí),將來注銷misc設(shè)備
? ? ? ? misc_deregister(&kyan_miscdev);
? ? 4:ioctl函數(shù)實(shí)現(xiàn)
????????????#define TEST_ADC_CONFIG_READ adctest //申明一個(gè)adc配置對(duì)象用于數(shù)據(jù)的設(shè)置和采集
? ? ? ????? static long ms_kyan_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
? ? ? ????? {
? ? ? ? ? ????? switch(cmd)
? ? ? ? ????? ? {
? ? ? ? ????? ? case IOCTL_TEST_INIT:
? ? ? ? ? ? ? ????? //此處可增加初始化該設(shè)備參數(shù)的功能函數(shù)
? ? ? ? ? ? ? ????? break;
? ? ? ? ????? ? case IOCTL_TEST_SET_CHANNEL_READ_VALUE:
? ? ? ? ? ? ? ????? //此處可直接操作應(yīng)用層對(duì)底層的讀和寫功能
? ? ? ? ? ? ? ????? //分別使用copy_from_user獲取用戶空間數(shù)據(jù)鹏往,來進(jìn)行底層功能的設(shè)置淡诗,或者通過使用copy_to_user將來底層數(shù)據(jù)傳給用戶空間
? ? ? ? ? ? ? ????? if(copy_from_user(&adctest, (TEST_ADC_CONFIG_READ __user *)arg, sizeof(TEST_ADC_CONFIG_READ)))
? ? ? ? ? ? ? ????? {
? ? ? ? ? ? ? ????? ? ? return EFAULT;
? ? ? ? ? ? ? ????? }
? ? ? ? ? ? ? ????? channel = adctest.channel_value & 3;//由于底層chanel的值只有0、1伊履、2韩容、3 四種狀態(tài),所以此處可以直接與上3進(jìn)行取值唐瀑。
? ? ? ? ? ? ? ????? adctest.adc_value = ms_kyan_get(channel);//此處為底層數(shù)據(jù)的實(shí)際讀取函數(shù)群凶,該函數(shù)可通過直接讀取寄存器方式進(jìn)行數(shù)據(jù)的獲取
? ? ? ? ? ? ? ????? printk("channel = %d , adc =%d \n",channel, adctest.adc_value);
? ? ? ? ? ? ? ????? if(copy_to_user((TEST_ADC_CONFIG_READ __user *)arg, &adctest, sizeof( TEST_ADC_CONFIG_READ)))
? ? ? ? ? ? ????? ? {
? ? ? ? ? ? ? ????? ? ? return EFAULT;
? ? ? ? ? ? ? ????? }
? ? ? ? ? ? ? ????? break;
? ? ? ? ? ? default:
? ? ? ? ? ? ? ? printk("ioctl: unknown command\n");
? ? ? ? ? ? ? ? return -ENOTTY;
? ? ? ? ? ? }
? ? ? ? }
? ? 5:編譯報(bào)錯(cuò)
如果在編譯過程中報(bào)以下錯(cuò)時(shí),主要因?yàn)槲丛黾?include <linux/uaccess.h>頭文件哄辣。
應(yīng)用層部分:
1:定義采樣對(duì)象的變量请梢,主要通過該變量與底層進(jìn)行交互
????????TEST_ADC_CONFIG_READ adctest;
2:打開dev下對(duì)應(yīng)的設(shè)備以供后續(xù)操作
????????int fd = open("/dev/kyan", O_WRONLY);
3:通過ioctl機(jī)制配置底層參數(shù)以及進(jìn)行設(shè)置和數(shù)據(jù)采集
????????ioctl(fd, IOCTL_TEST_INIT, NULL)//對(duì)底層功能進(jìn)行初始化
????????ioctl(fd, IOCTL_TEST_SET_CHANNEL_READ_VALUE, &adctest)//對(duì)底層所需要獲取的值進(jìn)行設(shè)置以及數(shù)據(jù)的讀取
4:獲取底層上報(bào)的數(shù)據(jù)
????????printf("SAR: get value %d\n", adctest.adc_value);