2012-08-16 8 views
11

नोट: मैं इस समस्या को आज सूचीबद्ध कर रहा हूं जैसा कि आज है, मैं कार्यान्वयन को बदलने के लिए विरोध नहीं कर रहा हूं (उदाहरण के लिए कक्षा के निर्माण को सामान्य क्षेत्र में ले जाना) यदि यह चीजों को आसान बनाता है ... मुझे यकीन नहीं है कि यह कैसे करें। : एंड नोटलिनक्स में, आप मौजूदा वर्ग के भीतर device_create का उपयोग कैसे करते हैं?

मेरे पास दो लिनक्स कर्नेल मॉड्यूल हैं और मैं उनके लिए/sys प्रविष्टियों को अपडेट करने का प्रयास कर रहा हूं। गूगल और अन्य स्रोतों पर चारों ओर सर्च कर रहे हैं, मैं की तर्ज पर कोड के बहुत सारे देखा है:

static dev_t MyDev; 
static struct class *c1; 

static int __init start_func(void) 
{ 
    ... 
    MyDev = MKDEV(nMajor, MINOR_VERSION); 
    register_chrdev_region(MyDev, 1, MODULE_NAME); 
    c1 = class_create(THIS_MODULE, "chardrv"); 
    device_create(c1, NULL, MyDev, NULL, MODULE_NAME); 
    .... 

और मैं अपनी पहली मॉड्यूल इस कोड काम करता है के लिए पुष्टि कर लें, और इसे सही ढंग बनाता है कि एक:

/sys/class/chardrv/<MODULE_NAME> 

प्रविष्टि। मैं क्या जानना चाहता हूं कि आप मौजूदा वर्ग में डिवाइस कैसे बनाते हैं। दूसरे शब्दों में, मेरे मॉड्यूल में से एक ने इस नए chardrv वर्ग को बनाया, अब मैं चाहता हूं कि मेरा अन्य मॉड्यूल उसी डिवाइस के तहत अपने डिवाइस को पंजीकृत करने में सक्षम हो।

मैं class_create() फिर से (दूसरे मॉड्यूल में) कॉल कर सकते हैं नहीं है, क्योंकि वह "chardrv" वर्ग पहले से मौजूद है ...

तो मैं यह देखने के लिए एक जांच चल सकता है या/sys/कक्षा/chardrv मौजूद है, और इससे मुझे यह तय करने में मदद मिल सकती है कि मुझे class_create() को कॉल करने की आवश्यकता है या नहीं, यह कोई समस्या नहीं है।

if (path "/sys/class/chardrv" does not exist) 
    new_class = class_create("chardrv") 
else 
    new_class = some how get class "chardrv" handle, or properties, or whatever 
device_create(new_class, ...) 

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

उत्तर

-1

लिनक्स कर्नेल ऐसा करने की अनुमति नहीं देगा। यह वह त्रुटि है जिसे आप प्राप्त करेंगे।

**[ 865.687824] kobject_add_internal failed for net with -EEXIST, don't try to register things with the same name in the same directory. 
[ 865.687835] Pid: 6382, comm: insmod Tainted: P  W O 3.2.16.1JeshuLinux #1 
[ 865.687840] Call Trace: 
[ 865.687849] [<c1584382>] ? printk+0x2d/0x2f 
[ 865.687859] [<c12a5438>] kobject_add_internal+0x138/0x1d0 
[ 865.687869] [<c12a5a11>] kset_register+0x21/0x50 
[ 865.687879] [<c137b63d>] __class_register+0xcd/0x1b0 
[ 865.687888] [<f8d0a0aa>] hello_init+0x4a/0x80 [sysfs_Dev] 
[ 865.687897] [<c1003035>] do_one_initcall+0x35/0x170  
[ 865.687909] [<f8d0a060>] ? enable_show+0x40/0x40 [sysfs_Dev]  
[ 865.687919] [<c10928d0>] sys_init_module+0x2c0/0x1b50  
[ 865.687941] [<c159485f>] sysenter_do_call+0x12/0x28  
[ 865.687947] Registering Class Failed** 

If you want to understand sysfs read: [mochel.pdf](www.kernel.org/pub/linux/kernel/people/mochel/doc/papers/ols-2005/mochel.pdf) 
+1

मुझे यकीन नहीं है कि जब आप यहां करने की कोशिश कर रहे हैं तो आप स्पष्ट हैं ... कम से कम यह त्रुटि मेरे प्रश्न को समझ में नहीं आती है। उदाहरण के लिए मैं एक वर्ग "chardrv" बनाना चाहता हूं, उसके बाद एक कर्नेल मॉड्यूल उसमें एक डिवाइस पंजीकृत करता है। "डिवाइस 1" कहें। फिर एक दूसरा कर्नेल मॉड्यूल एक ही डिवाइस "डिवाइस 2" में दूसरे डिवाइस को पंजीकृत करेगा। तो अब/sys/class/chardrv पर एक सूची कमांड चलाकर दोनों डिवाइस दिखाए जाएंगे। क्या आप कह रहे हैं कि लिनक्स में ऐसा करने का कोई तरीका नहीं है? मेरे लिए सही प्रतीत नहीं होता है ... – Mike

3

एक ही कक्षा गुजर अपने उदाहरण कोड का पालन करने के लिए, आप बस device_create() फिर से कहेंगे,, जैसे:

MyDev = MKDEV(nMajor, MINOR_VERSION); 
register_chrdev_region(MyDev, 1, MODULE_NAME); 
c1 = class_create(THIS_MODULE, "chardrv"); 
device_create(c1, NULL, MyDev, NULL, MODULE_NAME); 
... 
device_create(c1, NULL, MyDev2, NULL, "mydev2"); 

आप निश्चित रूप से क्रम में पथ जांच करने की आवश्यकता नहीं होनी चाहिए वर्ग करता है, तो यह निर्धारित करने के बनाया गया है। आप इसे अपने कोड में बना रहे हैं, इसलिए बस c1 == NULL के लिए परीक्षण करें या यदि आवश्यक हो तो ध्वज का उपयोग करें।

+0

इस साधारण उपयोग के मामले के लिए, हाँ, यह काम करेगा। मेरे पास दूसरा कर्नेल डिवाइस कब होगा? जब मैंने अपने प्रश्न को परिष्कृत किया तो मैंने उल्लेख किया कि _second_ कर्नेल मॉड्यूल भी एक ही/sys/class/chardrv directroy में एक डिवाइस बनाना चाहता है। स्पष्ट रूप से दोनों जगहों पर 'class_create()' को कॉल करने की आवश्यकता नहीं है। लेकिन अगर मैं इस विधि को नहीं बुलाता, तो मैं 'device_create()' के पैरामीटर 1 के लिए आवश्यक मेरी chardrv कक्षा तक पहुंच कैसे प्राप्त करूं। एक और बार: ** मॉड्यूल 1 ** कॉल 'class_create()/device_create() '। ** मॉड्यूल 2 ** बस 'device_create()' को कॉल करना चाहता है, लेकिन कक्षा संदर्भ की आवश्यकता है। – Mike

+0

तो कक्षा को पुनर्प्राप्त करने के लिए आपको एक एपीआई जोड़ने की जरूरत है। सबसे आसान विकल्प यह है कि कर्नेल को उचित (मॉड्यूल नहीं) में रखना और मॉड्यूल को इसमें कॉल करना है। – mpe

+0

और मैं इसके साथ ठीक हूं, कार्यान्वयन लचीला है। हालांकि मुझे अभी भी यकीन नहीं है कि कैसे। जब मैं 'class_create()' पैरामीटर 1 'THIS_MODULE' कहता हूं। कक्षा के निर्माण को उचित रूप से कर्नेल में ले जाना, मुझे लगता है कि 'THIS_MODULE' अब और काम नहीं करेगा। Class_create फ़ंक्शन का डीफ़ कहता है कि पी 1 है: "_owner: मॉड्यूल के लिए पॉइंटर जो इस स्ट्रक्चर क्लास_ के मालिक है"। इसका मतलब है कि मालिक एक मॉड्यूल होना चाहिए। – Mike

6

उसी श्रेणी के साथ device_create फ़ंक्शन का उपयोग करने के लिए, बस इसे उसी कक्षा में एक पॉइंटर पास करें।

चूंकि आप कक्षा बनाने के लिए एक अलग मॉड्यूल में device_create पर कॉल करना चाहते हैं, तो आपको कक्षा में पॉइंटर के लिए प्रतीक निर्यात करना होगा। ऐसा करने के लिए आप EXPORT_SYMBOL मैक्रो का उपयोग कर सकते हैं।


उदाहरण के लिए:

module1.c:

extern struct class *c1; /* declare as extern */ 
EXPORT_SYMBOL(c1);   /* use EXPORT_SYMBOL to export c1 */ 

static dev_t mod1_dev; 
static int __init start_func(void) 
{ 
     ... 
     /* define class here */ 
     c1 = class_create(THIS_MODULE, "chardrv"); 

     /* create first device */ 
     device_create(c1, NULL, mod1_dev, NULL, "mod1_dev"); 
     .... 
} 

module2।ग

extern struct class *c1; /* declare as extern */ 

static dev_t mod2_dev; 
static int __init start_func(void) 
{ 
     ... 
     /* c1 is defined in module 1 */ 

     /* create second device */ 
     device_create(c1, NULL, mod2_dev, NULL, "mod2_dev"); 
     .... 
} 

ध्यान दें: आप के बाद से वर्ग सूचक परिभाषित और module1 में निर्यात किया जाता है module1 से पहले module2 डालना होगा।

कि निर्देशिका आप उम्मीद कर रहे हैं बनाना चाहिए: जब आप लोड करने का प्रयास

  • /sys/class/chardrv/mod1_dev
  • /sys/class/chardrv/mod2_dev

वैसे, अगर आप एक Invalid parameters त्रुटि हो रही है दूसरा मॉड्यूल, आपको add a KBUILD_EXTRA_SYMBOLS line to your Makefile होना पड़ सकता है।

0

बस अपने पहले मॉड्यूल के मॉड्यूल इनिट फ़ंक्शन में कक्षा बनाएं, EXPORT_SYMBOL के साथ वैश्विक श्रेणी का प्रतीक निर्यात करें और इसे अन्य मॉड्यूल से उपयोग करें।

चूंकि कक्षा का मालिक आपका पहला मॉड्यूल है, हर बार जब आप उस कक्षा में कोई डिवाइस जोड़ते हैं तो पहला मॉड्यूल का संदर्भ काउंटर बढ़ जाएगा: जब भी आप इसका उपयोग कर रहे हों तो आप इसे अनलोड नहीं कर सकते।

संबंधित मुद्दे