2010-02-15 17 views
12

तो मैं एक कर्नेल मॉड्यूल लिखने की कोशिश कर रहा हूं जो linux/timer.h फ़ाइल का उपयोग करता है। मुझे बस मॉड्यूल के अंदर काम करने के लिए मिला, और अब मैं इसे एक उपयोगकर्ता प्रोग्राम से काम करने की कोशिश कर रहा हूं।मैं अपने कर्नेल मॉड्यूल में हेरफेर करने के लिए ioctl() का उपयोग कैसे करूं?

//Necessary Includes For Device Drivers. 
#include <linux/init.h> 
#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/fs.h> 
#include <linux/errno.h> 
#include <linux/proc_fs.h> 
#include <asm/uaccess.h> 
#include <linux/timer.h> 
#include <linux/ioctl.h> 

#define DEVICE_NAME "mytimer" 
#define DEVICE_FILE_NAME "mytimer" 
#define MAJOR_NUM 61 
#define MINOR_NUM 0 

MODULE_LICENSE("Dual BSD/GPL"); 

static struct timer_list my_timer; 

struct file_operations FileOps = 
{ 
    //No File Operations for this timer. 
}; 

//Function to perform when timer expires. 
void TimerExpire(int data) 
{ 
    printk("Timer Data: %d\n", data); 
} 

//Function to set up timers. 
void TimerSetup(void) 
{ 
    setup_timer(&my_timer, TimerExpire, 5678); 
    mod_timer(&my_timer, jiffies + msecs_to_jiffies(5000)); 
} 

//Module Init and Exit Functions. 
int init_module(void) 
{ 
    int initResult = register_chrdev(MAJOR_NUM, "mytimer", &FileOps); 

    if (initResult < 0) 
    { 
     printk("Cannot obtain major number %d\n", MAJOR_NUM); 

     return initResult; 
    } 

printk("Loading MyTimer Kernel Module...\n"); 


return 0; 
} 
void cleanup_module(void) 
{ 
    unregister_chrdev(MAJOR_NUM, "mytimer"); 
    printk("Unloading MyTimer Kernel Module...\n"); 
} 

अधिक विशेष रूप से, मैं TimerSetup() फ़ंक्शन कॉल करने के लिए मेरे उपयोगकर्ता कार्यक्रम हैं:

यहाँ मेरी कर्नेल मॉड्यूल है। मुझे पता है कि मुझे ioctl() का उपयोग करने की आवश्यकता होगी, लेकिन मुझे यकीन नहीं है कि मेरे मॉड्यूल फ़ाइल में निर्दिष्ट कैसे करें कि TimerSetup() को ioctl() के माध्यम से कॉल करने योग्य होना चाहिए।

इसके अलावा, मेरा दूसरा प्रश्न: मैं अपने मॉड्यूल को इन्सोडोड करने और सही प्रमुख संख्या के साथ/dev/mytimer में mknod करने में सक्षम था। लेकिन जब मैंने इसे खोलने की कोशिश की() ताकि मैं इसे फाइल डिस्क्रिप्टर प्राप्त कर सकूं, यह लौटने वाला -1 रखता है, जो मुझे लगता है कि गलत है। मैंने सुनिश्चित किया कि अनुमतियां ठीक थीं (असल में, मैंने इसे सुनिश्चित करने के लिए इसे 777 बना दिया) ... यह अभी भी काम नहीं करता है ... क्या मुझे कुछ याद आ रही है?

यहाँ सिर्फ मामले में उपयोगकर्ता कार्यक्रम है:

#include <stdio.h> 

int main(int argc, char* argv[]) 
{ 
    int fd = open("/dev/mytimer", "r"); 
    printf("fd: %d\n", fd); 

    return 0; 
} 

उत्तर

20

उदाहरण कोड आपको drivers/watchdog/softdog.c (लिनक्स 2.6.33 से लिखा गया था) में पाया जा सकता है, जो उचित फ़ाइल संचालन के साथ-साथ उपयोगकर्तालैंड को ioctl() के साथ संरचना को भरने की अनुमति देता है।

यह वास्तव में किसी भी व्यक्ति के लिए एक महान, काम करने वाला ट्यूटोरियल है जिसे छोटे चरित्र डिवाइस ड्राइवर लिखने की आवश्यकता है।

मैंने answering my own question पर सॉफ्टडॉग के ioctl इंटरफेस को विच्छेदित किया, जो आपके लिए सहायक हो सकता है।

यहाँ यह का सार है (हालांकि अब तक संपूर्ण से) ...

softdog_ioctl() में आप कि कार्यक्षमता, संस्करण और डिवाइस जानकारी का विज्ञापन करता है struct watchdog_info का एक सरल प्रारंभ देखें:

static const struct watchdog_info ident = { 
      .options =    WDIOF_SETTIMEOUT | 
            WDIOF_KEEPALIVEPING | 
            WDIOF_MAGICCLOSE, 
      .firmware_version =  0, 
      .identity =    "Software Watchdog", 
    }; 

हम तो एक साधारण मामले को देखें जहां उपयोगकर्ता केवल इन क्षमताओं को प्राप्त करना चाहता है:

switch (cmd) { 
    case WDIOC_GETSUPPORT: 
      return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; 

... जो निश्चित रूप से, सी भर जाएगा उपरोक्त प्रारंभिक मानों के साथ संबंधित उपयोगकर्ता स्पेस watchdog_info।यदि copy_to_user() विफल हो जाता है, -EFAULT वापस लौटाया जाता है जो संबंधित उपयोगकर्तास्थान ioctl() को एक सार्थक त्रुटि सेट के साथ -1 को वापस करने का कारण बनता है।

ध्यान दें, जादू अनुरोध वास्तव में, linux/watchdog.h में परिभाषित कर रहे हैं ताकि गिरी और यूज़रस्पेस उन्हें साझा:

#define WDIOC_GETSUPPORT  _IOR(WATCHDOG_IOCTL_BASE, 0, struct watchdog_info) 
#define WDIOC_GETSTATUS   _IOR(WATCHDOG_IOCTL_BASE, 1, int) 
#define WDIOC_GETBOOTSTATUS  _IOR(WATCHDOG_IOCTL_BASE, 2, int) 
#define WDIOC_GETTEMP   _IOR(WATCHDOG_IOCTL_BASE, 3, int) 
#define WDIOC_SETOPTIONS  _IOR(WATCHDOG_IOCTL_BASE, 4, int) 
#define WDIOC_KEEPALIVE   _IOR(WATCHDOG_IOCTL_BASE, 5, int) 
#define WDIOC_SETTIMEOUT  _IOWR(WATCHDOG_IOCTL_BASE, 6, int) 
#define WDIOC_GETTIMEOUT  _IOR(WATCHDOG_IOCTL_BASE, 7, int) 
#define WDIOC_SETPRETIMEOUT  _IOWR(WATCHDOG_IOCTL_BASE, 8, int) 
#define WDIOC_GETPRETIMEOUT  _IOR(WATCHDOG_IOCTL_BASE, 9, int) 
#define WDIOC_GETTIMELEFT  _IOR(WATCHDOG_IOCTL_BASE, 10, int) 

WDIOC जाहिर वाचक "निगरानी ioctl"

आप आसानी से ले जा सकते हैं कि एक कदम आगे, आपके ड्राइवर को कुछ करने और संरचना में उस चीज़ का परिणाम रखने और इसे उपयोगकर्ता स्थान पर कॉपी करने के लिए। उदाहरण के लिए, यदि struct watchdog_info में सदस्य __u32 result_code भी था। नोट, __u32 सिर्फ कर्नेल का संस्करण uint32_t है।

ioctl() के साथ, उपयोगकर्ता किसी ऑब्जेक्ट का पता पास करता है, चाहे वह कर्नेल को जो भी कर्नेल को एक समान ऑब्जेक्ट में अपना उत्तर लिखने की उम्मीद हो और परिणाम प्रदान किए गए पते पर कॉपी करें ।

दूसरी चीज़ जो आपको करने की आवश्यकता है, यह सुनिश्चित कर लें कि आपका डिवाइस जानता है कि कोई खुलता है, इसे पढ़ता है, इसे लिखता है, या ioctl() जैसे हुक का उपयोग करता है, जिसे आप आसानी से देख सकते हैं सॉफ्टडॉग का अध्ययन

रुचि का

है:

static const struct file_operations softdog_fops = { 
     .owner   = THIS_MODULE, 
     .llseek   = no_llseek, 
     .write   = softdog_write, 
     .unlocked_ioctl = softdog_ioctl, 
     .open   = softdog_open, 
     .release  = softdog_release, 
}; 

आप unlocked_ioctl हैंडलर के लिए जा कहां देख ... आपने सही अनुमान लगाया, softdog_ioctl()।

मुझे लगता है कि आप जटिलता की एक परत को जोड़ना चाहते हैं जो वास्तव में ioctl() से निपटने पर मौजूद नहीं है, यह वास्तव में इतना आसान है। इसी कारण से, नए ioctl इंटरफ़ेस पर फंसे अधिकांश कर्नेल डेवलपर्स को तब तक जोड़ा जा रहा है जब तक कि वे बिल्कुल जरूरी न हों। इस प्रकार के ट्रैक को खोना बहुत आसान है कि ioctl() आपके द्वारा उपयोग किए जाने वाले जादू को भरने जा रहा है, जो प्राथमिक कारण है कि copy_to_user() अक्सर विफल रहता है जिसके परिणामस्वरूप कर्नेल उपयोगकर्ता की प्रक्रियाओं की संख्याओं के साथ घुमाता है डिस्क नींद

टाइमर के लिए, मैं सहमत हूं, ioctl() सैनिटी का सबसे छोटा रास्ता है।

+0

मैंने वास्तव में उस पर ध्यान दिया, लेकिन इसे समझ में नहीं आया ... मैंने फ़ंक्शन स्थिर लंबे softdog_ioctl (स्ट्रक्चर फ़ाइल * फ़ाइल, हस्ताक्षरित int cmd, हस्ताक्षरित लंबे तर्क) लेकिन यह समझ में नहीं आया कि इसमें क्या है .. क्या यह एकमात्र ioctl कार्य है? – hahuang65

+1

बहुत बढ़िया, ऐसा लगता है कि आपने अपनी पोस्ट में इंटरफेस को समझाते हुए एक अच्छी नौकरी की है :) धन्यवाद। – hahuang65

+0

हालांकि यह उत्तर अब 5 साल से अधिक पुराना है, मेरे पास एक सवाल था। यदि 'ioctl' के आगे कार्यान्वयन पर फंसे हुए हैं, तो पसंदीदा विकल्प क्या है? – sherrellbc

8

आप समारोह निर्दिष्ट करने के लिए अपने file_operations संरचना में एक .open समारोह सूचक याद कर रहे हैं जब एक प्रक्रिया उपकरण फ़ाइल को खोलने का प्रयास करता है कहा जाता है। आपको अपने ioctl फ़ंक्शन के लिए .ioctl फ़ंक्शन पॉइंटर भी निर्दिष्ट करना होगा।

The Linux Kernel Module Programming Guide, विशेष रूप से अध्याय 4 (वर्ण डिवाइस फ़ाइलें) और 7 (डिवाइस फ़ाइलों से बात करने) के माध्यम से पढ़ने का प्रयास करें।

Chapter 4file_operations संरचना है, जो कि इस तरह के open या ioctl के रूप में विभिन्न कार्यों का प्रदर्शन मॉड्यूल/चालक द्वारा परिभाषित कार्यों के लिए संकेत रखती परिचय देता है।

Chapter 7 आईओक्टल्स के माध्यम से मॉड्यूल/ड्राइव के साथ संचार करने की जानकारी प्रदान करता है।

Linux Device Drivers, Third Edition एक और अच्छा संसाधन है।

+0

लिंक के लिए धन्यवाद, वे वास्तव में उपयोगी है। :) – hahuang65

+0

* लिनक्स कर्नेल मॉड्यूल प्रोग्रामिंग गाइड * में कुछ उदाहरण हैं जो आपको सही दिशा में इंगित करना चाहिए। – jschmier

0

मिनिमल runnable उदाहरण

एक पूरी तरह से प्रतिलिपि प्रस्तुत करने योग्य QEMU + Buildroot वातावरण में परीक्षण किया गया है, तो मदद कर सकता है दूसरों को उनके ioctl काम कर रहे हो। गिटहब अपस्ट्रीम: kernel module | shared header | userland

सबसे कष्टप्रद हिस्सा यह समझ रहा था कि कुछ कम आईडी को अपहृत कर दिया गया है: ioctl is not called if cmd = 2, आपको _IOx मैक्रोज़ का उपयोग करना होगा।

कर्नेल मॉड्यूल:

#include <asm/uaccess.h> /* copy_from_user, copy_to_user */ 
#include <linux/debugfs.h> 
#include <linux/module.h> 
#include <linux/printk.h> /* printk */ 

#include "ioctl.h" 

MODULE_LICENSE("GPL"); 

static struct dentry *dir; 

static long unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long argp) 
{ 
    void __user *arg_user; 
    union { 
     int i; 
     lkmc_ioctl_struct s; 
    } arg_kernel; 

    arg_user = (void __user *)argp; 
    pr_info("cmd = %x\n", cmd); 
    switch (cmd) { 
     case LKMC_IOCTL_INC: 
      if (copy_from_user(&arg_kernel.i, arg_user, sizeof(arg_kernel.i))) { 
       return -EFAULT; 
      } 
      pr_info("0 arg = %d\n", arg_kernel.i); 
      arg_kernel.i += 1; 
      if (copy_to_user(arg_user, &arg_kernel.i, sizeof(arg_kernel.i))) { 
       return -EFAULT; 
      } 
     break; 
     case LKMC_IOCTL_INC_DEC: 
      if (copy_from_user(&arg_kernel.s, arg_user, sizeof(arg_kernel.s))) { 
       return -EFAULT; 
      } 
      pr_info("1 arg = %d %d\n", arg_kernel.s.i, arg_kernel.s.j); 
      arg_kernel.s.i += 1; 
      arg_kernel.s.j -= 1; 
      if (copy_to_user(arg_user, &arg_kernel.s, sizeof(arg_kernel.s))) { 
       return -EFAULT; 
      } 
     break; 
     default: 
      return -EINVAL; 
     break; 
    } 
    return 0; 
} 

static const struct file_operations fops = { 
    .owner = THIS_MODULE, 
    .unlocked_ioctl = unlocked_ioctl 
}; 

static int myinit(void) 
{ 
    dir = debugfs_create_dir("lkmc_ioctl", 0); 
    /* ioctl permissions are not automatically restricted by rwx as for read/write, 
    * but we could of course implement that ourselves: 
    * https://stackoverflow.com/questions/29891803/user-permission-check-on-ioctl-command */ 
    debugfs_create_file("f", 0, dir, NULL, &fops); 
    return 0; 
} 

static void myexit(void) 
{ 
    debugfs_remove_recursive(dir); 
} 

module_init(myinit) 
module_exit(myexit) 

साझा हैडर:

#ifndef IOCTL_H 
#define IOCTL_H 

#include <linux/ioctl.h> 

typedef struct { 
    int i; 
    int j; 
} lkmc_ioctl_struct; 
#define LKMC_IOCTL_MAGIC 0x33 
#define LKMC_IOCTL_INC  _IOWR(LKMC_IOCTL_MAGIC, 0, int) 
#define LKMC_IOCTL_INC_DEC _IOWR(LKMC_IOCTL_MAGIC, 1, lkmc_ioctl_struct) 

#endif 

userland:

#define _GNU_SOURCE 
#include <errno.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <sys/ioctl.h> 
#include <sys/stat.h> 
#include <sys/types.h> 
#include <unistd.h> 

#include "../ioctl.h" 

int main(int argc, char **argv) 
{ 
    int fd, arg_int, ret; 
    lkmc_ioctl_struct arg_struct; 

    if (argc < 2) { 
     puts("Usage: ./prog <ioctl-file>"); 
     return EXIT_FAILURE; 
    } 
    fd = open(argv[1], O_RDONLY); 
    if (fd == -1) { 
     perror("open"); 
     return EXIT_FAILURE; 
    } 
    /* 0 */ 
    { 
     arg_int = 1; 
     ret = ioctl(fd, LKMC_IOCTL_INC, &arg_int); 
     if (ret == -1) { 
      perror("ioctl"); 
      return EXIT_FAILURE; 
     } 
     printf("arg = %d\n", arg_int); 
     printf("ret = %d\n", ret); 
     printf("errno = %d\n", errno); 
    } 
    puts(""); 
    /* 1 */ 
    { 
     arg_struct.i = 1; 
     arg_struct.j = 1; 
     ret = ioctl(fd, LKMC_IOCTL_INC_DEC, &arg_struct); 
     if (ret == -1) { 
      perror("ioctl"); 
      return EXIT_FAILURE; 
     } 
     printf("arg = %d %d\n", arg_struct.i, arg_struct.j); 
     printf("ret = %d\n", ret); 
     printf("errno = %d\n", errno); 
    } 
    close(fd); 
    return EXIT_SUCCESS; 
} 
संबंधित मुद्दे