कैरेक्टर डिवाइस या कैरेक्टर स्पेशल फाइल्स कैसे काम करती हैं?


22

मैं चरित्र विशेष फ़ाइलों को समझने की कोशिश कर रहा हूं। से विकिपीडिया , मैं समझता हूँ कि इन फ़ाइलों को उपकरणों के लिए "एक इंटरफेस प्रदान" है कि एक समय में संचारित डेटा एक चरित्र। मेरी समझ यह है कि सिस्टम किसी तरह से सीधे डिवाइस ड्राइवर को कॉल करने के बजाय चरित्र डिवाइस को कॉल करता है। लेकिन फ़ाइल इस इंटरफ़ेस को कैसे प्रदान करती है? क्या यह एक निष्पादन योग्य है जो सिस्टम कॉल का अनुवाद करता है? क्या कोई समझा सकता है कि क्या हो रहा है।

जवाबों:


19

वे वास्तव में बस यही हैं - इंटरफेस। एक "प्रमुख" और "माइनर" संख्या से एन्कोडेड वे कर्नेल को एक हुक प्रदान करते हैं।

वे दो स्वादों (अच्छी तरह से, तीन, लेकिन नाम वाले पाइप अब के लिए इस स्पष्टीकरण के दायरे से बाहर हैं) में आते हैं: चरित्र उपकरण और ब्लॉक डिवाइस।

ब्लॉक डिवाइसेस में स्टोरेज डिवाइस होते हैं, जो आउटपुट को बफ़र करने में सक्षम होते हैं और बाद में पुनः प्राप्ति के लिए डेटा को स्टोर करते हैं।

कैरेक्टर डिवाइसेज ऑडियो या ग्राफिक्स कार्ड, या कीबोर्ड और माउस जैसे इनपुट डिवाइस हैं।

प्रत्येक मामले में, जब कर्नेल सही ड्राइवर को लोड करता है (या तो बूट समय पर, या udev जैसे कार्यक्रमों के माध्यम से ) तो यह देखने के लिए विभिन्न बसों को स्कैन करता है कि क्या उस चालक द्वारा नियंत्रित कोई उपकरण वास्तव में सिस्टम पर मौजूद हैं। यदि ऐसा है, तो यह एक उपकरण सेट करता है जो उचित प्रमुख / मामूली संख्या पर 'सुनता है'।

(उदाहरण के लिए, आपके सिस्टम द्वारा पाए गए पहले ऑडियो कार्ड के डिजिटल सिग्नल प्रोसेसर को 14/3 की प्रमुख / मामूली संख्या जोड़ी मिलती है; दूसरा 14,35 मिलता है, आदि)

यह एक चरित्र डिवाइस के रूप में /devनाम में प्रवेश करने के लिए udev तक है dspप्रमुख 14 नाबालिग 3 चिह्नित।

(लिनक्स के महत्वपूर्ण रूप से पुराने या न्यूनतम-फ़ुटप्रिंट संस्करणों में, /dev/गतिशील रूप से लोड नहीं किया जा सकता है लेकिन बस सभी संभव डिवाइस फ़ाइलों को सांख्यिकीय रूप से समाहित किया जाता है।)

फिर, जब कोई उपयोगकर्ता प्रोग्राम एक ऐसी फ़ाइल तक पहुँचने की कोशिश करता है, जिसे उपयुक्त प्रमुख / लघु संख्या (उदाहरण के लिए, डिजिटल ऑडियो भेजने की कोशिश करने वाला आपका ऑडियो प्लेयर) के साथ 'वर्ण विशेष फ़ाइल' के रूप में चिह्नित किया जाता है /dev/dsp, तो कर्नेल को पता होता है कि इस डेटा की आवश्यकता है चालक के माध्यम से प्रेषित किया जाना चाहिए कि प्रमुख / मामूली संख्या से जुड़ी हुई है; संभवतया कहा जाता है कि चालक जानता है कि बदले में इसके साथ क्या करना है।


1
1. इतनी बड़ी / छोटी संख्याएँ बंदरगाहों के अनुरूप हैं?
bernie2436

2. इसलिए जब प्रोग्राम किसी भी फ़ाइल तक पहुंचते हैं, तो कर्नेल इन विशेष इंटरफेसों को पढ़ने के लिए सीखता है कि क्या प्रोग्राम को किसी विशेष डिवाइस से हस्तक्षेप करना चाहिए? Ex: यदि कोई प्रोग्राम शब्द फ़ाइल खोलता है, तो यह कीबोर्ड इनपुट के लिए प्रोग्राम को जवाब देने के लिए कैरेक्टर डिवाइस विशेष फ़ाइल को पढ़ता है?
bernie2436

1) कुछ हद तक । यह एक गरीब आदमी की उपमा है, लेकिन यह करूँगा।
शादुर

2
2) आप अमूर्त की तीन या चार परतों के बारे में याद कर रहे हैं। प्रोग्राम जिसे आप एक टेक्स्ट फ़ाइल खोलते हैं, न तो जानता है और न ही परवाह करता है कि कीबोर्ड डिवाइस क्या है। अंतर्निहित हार्डवेयर के साथ संचार टर्मिनल एमुलेटर (यदि आप कंसोल मोड में हैं) या एक्स इवेंट लेयर (यदि आप ग्राफिक्स मोड में हैं) के माध्यम से होता है, जिसमें से कोई भी कीबोर्ड और अन्य ड्राइव को सुनेगा और निर्णय करेगा कि क्या , अगर कुछ भी हो, तो प्रोग्राम को पास करना है। मैं यहाँ एक काफी जटिल बहुपरत प्रणाली का सार प्रस्तुत कर रहा हूँ; आप सामान्य रूप से X विंडो सिस्टम पर पढ़ने के लिए अच्छा कर सकते हैं।
शादुर

1
यह भी ध्यान दें कि, UN * X के कुछ फ्लेवर पर, स्टोरेज डिवाइस के लिए कैरेक्टर स्पेशल फाइल्स हैं; विशेष फाइल के लिए एक रीड या राइट एक रीडिंग में बदल जाता है या डिवाइस पर ब्लॉक के अनुक्रम में लिखता है। (FreeBSD के हाल के संस्करणों में, भंडारण उपकरणों के लिए केवल विशेष फाइलें हैं ; कोई ब्लॉक विशेष फाइलें नहीं हैं।)

10

प्रत्येक फ़ाइल, डिवाइस या अन्यथा, VFS के भीतर 6 बुनियादी कार्यों का समर्थन करता है:

  1. खुला
  2. बंद करे
  3. पढ़ें
  4. लिखो
  5. मांगना
  6. कहना

इसके अतिरिक्त, डिवाइस फ़ाइलें I / O नियंत्रण का समर्थन करती हैं, जो अन्य विविध कार्यों को पहले 6 द्वारा कवर नहीं करने की अनुमति देती है।

एक चरित्र विशेष के मामले में, तलाश और बताना लागू नहीं होता है क्योंकि वे एक स्ट्रीमिंग इंटरफ़ेस का समर्थन करते हैं । यह है कि पढ़ने या लिखने के रूप में सीधे खोल में पुनर्निर्देशन के साथ किया जाता है:

echo 'foo' > /dev/some/char
sed ... < /dev/some/char

6

न्यूनतम रननीय file_operationsउदाहरण

एक बार जब आप एक न्यूनतम उदाहरण देखते हैं, तो यह सब स्पष्ट हो जाता है।

प्रमुख विचार हैं:

  • file_operations प्रत्येक फ़ाइल से संबंधित syscall के लिए कॉलबैक शामिल हैं
  • mknod <path> c <major> <minor> एक चरित्र उपकरण बनाता है जो उन का उपयोग करता है file_operations
  • चरित्र उपकरणों के लिए जो गतिशील रूप से डिवाइस नंबर (संघर्ष से बचने के लिए आदर्श) आवंटित करते हैं, के साथ संख्या का पता लगाएं cat /proc/devices

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

#include <asm/uaccess.h> /* copy_from_user, copy_to_user */
#include <linux/errno.h> /* EFAULT */
#include <linux/fs.h> /* register_chrdev, unregister_chrdev */
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/printk.h> /* printk */
#include <uapi/linux/stat.h> /* S_IRUSR */

#define NAME "lkmc_character_device"

MODULE_LICENSE("GPL");

static int major;

static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
    size_t ret;
    char kbuf[] = {'a', 'b', 'c', 'd'};

    ret = 0;
    if (*off == 0) {
        if (copy_to_user(buf, kbuf, sizeof(kbuf))) {
            ret = -EFAULT;
        } else {
            ret = sizeof(kbuf);
            *off = 1;
        }
    }
    return ret;
}

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

static int myinit(void)
{
    major = register_chrdev(0, NAME, &fops);
    return 0;
}

static void myexit(void)
{
    unregister_chrdev(major, NAME);
}

module_init(myinit)
module_exit(myexit)

उपयोगकर्ता परीक्षण कार्यक्रम:

insmod /character_device.ko
dev="lkmc_character_device"
major="$(grep "$dev" /proc/devices | cut -d ' ' -f 1)"
mknod "/dev/$dev" c "$major" 0
cat /dev/lkmc_character_device
# => abcd
rm /dev/lkmc_character_device
rmmod character_device

वास्तव में इसे चलाने के लिए बायलरप्लेट के साथ GitHub QEMU + बिल्डरोस्ट अपस्ट्रीम:

अधिक जटिल उदाहरण:


यह सुपर उपयोगी था धन्यवाद! बस एक सवाल, यह वास्तव में क्या करता है *off = 1;, और इसे क्यों सेट किया गया है 1?
सिल्वरस्लैश

1
@SilverSlash जो मान readएक ही open(फाइल डिस्क्रिप्टर को कई कॉल्स में पार कर जाता है । ड्राइवर इसके साथ जो चाहे कर सकता है। सामान्य शब्दार्थ, बाइट की संख्या को पढ़ने के लिए है। इस उदाहरण में, हमारे पास बस एक सरल शब्दार्थ है: 0पहले पढ़ने के लिए, पहले पढ़ने के 1बाद। इसे चलाने का प्रयास करें और एक प्रिंटक या GDB चरण इसे डालें।
सिरो सेंटिल्ली 新疆 改造 iro 六四 事件

4

"एक समय पर चरित्र" एक मिथ्या नाम है (जैसा कि यह विचार है कि चरित्र उपकरण आवश्यक रूप से तलाश और बताने का समर्थन नहीं करते हैं)। वास्तव में, "एक समय में ब्लॉक करें" (यानी सख्ती से रिकॉर्ड-उन्मुख, जैसे कि टेप ड्राइव *) उपकरणों में चरित्र उपकरण होना चाहिए। तो यह विचार है कि एक चरित्र उपकरण आवश्यक रूप से अचूक होना चाहिए - चरित्र डिवाइस ड्राइवर एक पूर्ण file_operationsसंरचना को परिभाषित करते हैं जो कि llseek को परिभाषित करने के लिए स्वतंत्र है या नहीं इसके अनुसार डिवाइस ऑपरेशन का समर्थन करता है। अधिकांश लोगों को लगता है कि चरित्र उपकरण उदाहरण के रूप में अशक्त हैं, उर्जित हैं, TTY डिवाइस, साउंड कार्ड, माउस, आदि ... जो उन उपकरणों की बारीकियों के कारण सभी अचूक हैं, लेकिन / dev / vcs, / dev / fb0 , और / देव / किमीम भी चरित्र उपकरण हैं और वे सभी खोजी हैं।

जैसा कि मैंने उल्लेख किया है, एक वर्ण डिवाइस ड्राइवर एक file_operations संरचना को परिभाषित करता है जिसमें सभी कार्यों के लिए फ़ंक्शन पॉइंटर्स हैं जो कोई व्यक्ति किसी फ़ाइल पर कॉल करना चाहता है - तलाश, पढ़, लिख, ioctl, आदि - और ये प्रत्येक एक बार कॉल किए जाते हैं जब संबंधित फोन कॉल होता है। इस डिवाइस फ़ाइल के साथ निष्पादित किया जाता है। और पढ़ और लिख सकते हैं इसलिए जो कुछ भी अपने तर्कों के साथ चाहता है - वह एक ऐसे लेखन को स्वीकार करने से इनकार कर सकता है जो बहुत बड़ा है या केवल वही लिखता है जो फिट बैठता है; यह बाइट्स की संपूर्ण अनुरोधित संख्या के बजाय केवल एक रिकॉर्ड के अनुरूप डेटा पढ़ सकता है।

तो, ब्लॉक डिवाइस क्या है? असल में, ब्लॉक डिवाइस डिस्क ड्राइव हैं। कोई अन्य प्रकार का डिवाइस ( वर्चुअल डिस्क ड्राइव को छोड़कर , जैसे रैमडिस्क और लूपबैक) एक ब्लॉक डिवाइस है। वे I / O अनुरोध प्रणाली, फाइलसिस्टम लेयर, बफर / कैश सिस्टम और वर्चुअल मेमोरी सिस्टम में इस तरह से एकीकृत होते हैं कि कैरेक्टर डिवाइस नहीं हैं, तब भी जब आप उपयोगकर्ता प्रक्रिया से उदाहरण के लिए / dev / sda एक्सेस कर रहे हैं । यहां तक ​​कि अपवाद के रूप में "कच्चे उपकरणों" का उल्लेख है कि चरित्र उपकरण हैं

* कुछ यूनिक्स प्रणालियों को लागू किया जाता है, जिसे अब "फिक्स्ड-ब्लॉक मोड" कहा जाता है - जो कर्नेल समूह को विभाजित करता है और कॉन्फ़िगर किए गए ब्लॉक की सीमाओं को कम या ज्यादा करने के लिए अनुरोध करता है, जैसा कि डिस्क ड्राइव के लिए किया जाता है - एक ब्लॉक के रूप में डिवाइस। "वैरिएबल-ब्लॉक मोड" के लिए एक कैरेक्टर डिवाइस की जरूरत होती है, जो यूजर प्रोग्राम से ब्लॉक बाउंड्रीज़ को सिंगल राइट (2) कॉल को एक ब्लॉक और सिंगल रीड (2) कॉल रिटर्न को एक ब्लॉक लिखता है। चूंकि मोड स्विचिंग को एक अलग डिवाइस फ़ाइल के बजाय एक ioctl के रूप में लागू किया गया है, इसलिए एक चरित्र डिवाइस का उपयोग किया जाता है। वैरिएबल-रिकॉर्ड टेप ड्राइव ज्यादातर "गैर-खोजी" हैं क्योंकि मांग में कई बाइट्स के बजाय कई रिकॉर्ड गिनना शामिल है, और देशी की तलाश ऑपरेशन को एक ioctl के रूप में लागू किया गया है।


1

चरित्र उपकरण कर्नेल मॉड्यूल (या कर्नेल स्वयं) द्वारा बनाए जा सकते हैं। जब कोई डिवाइस बनाया जाता है, तो निर्माता उन फ़ंक्शन को पॉइंटर्स प्रदान करता है जो ओपन, रीड, आदि जैसे हैंडल स्टैंडर्ड कॉल को लागू करते हैं। फिर लिनक्स कर्नेल उन फ़ंक्शन को कैरेक्टर डिवाइस के साथ जोड़ देता है, इसलिए उदाहरण के लिए जब उपयोगकर्ता-मोड एप्लिकेशन रीड () को कॉल करता है। एक चरित्र डिवाइस फ़ाइल पर कार्य, यह एक syscall में परिणाम होगा और फिर कर्नेल इस कॉल को ड्राइवर को बनाते समय निर्दिष्ट एक रीड फ़ंक्शन को रूट करेगा। यहां एक कैरेक्टर डिवाइस बनाने पर एक स्टेप-बाय-स्टेप ट्यूटोरियल है , आप एक डिबगर का उपयोग करके एक नमूना प्रोजेक्ट और इसके माध्यम से स्टेप बना सकते हैं कि यह समझने के लिए कि डिवाइस ऑब्जेक्ट कैसे बनाया जाता है और हैंडलर कब लागू होते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.