2012-08-16 30 views
11

Lưu ý: Tôi đang liệt kê vấn đề này như hiện nay, tôi là không phản đối việc thay đổi việc triển khai (di chuyển lớp học thành một khu vực chung). Tôi chỉ không chắc chắn làm thế nào để làm điều đó. : Lưu ý cuốiTrong Linux, bạn sử dụng device_create trong lớp hiện tại như thế nào?

Tôi có hai mô-đun hạt nhân Linux và tôi đang cố cập nhật các mục nhập/sys cho chúng. Tìm kiếm xung quanh trên google và các nguồn khác, tôi đã nhìn thấy rất nhiều mã dọc theo dòng:

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); 
    .... 

Và tôi đã xác minh cho mô-đun đầu tiên của tôi mã này hoạt động, và nó một cách chính xác tạo ra một:

/sys/class/chardrv/<MODULE_NAME> 

mục nhập. Những gì tôi muốn biết là làm thế nào để bạn tạo một thiết bị trong một lớp học hiện có. Nói cách khác, một trong các mô-đun của tôi đã tạo lớp chardrv mới này, bây giờ tôi muốn mô-đun khác của tôi có thể đăng ký các thiết bị của nó trong cùng một lớp.

tôi không thể gọi class_create() một lần nữa (trong module thứ hai), bởi vì đó lớp "chardrv" đã tồn tại ...

Vì vậy, tôi có thể chạy một kiểm tra để xem nếu/sys/lớp/chardrv tồn tại và điều này có thể giúp tôi quyết định xem tôi có cần gọi class_create() hay không, đó không phải là vấn đề. Cho phép đặt một số mã giả tại đây để làm rõ:

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, ...) 

Vì vậy, theo ví dụ này, nếu lớp học của tôi đã tồn tại, và tôi chỉ muốn thêm thiết bị mới của tôi vào nó từ một mô-đun thứ hai Tôi giả sử tôi cần để tạo cấu trúc lớp học và bằng cách nào đó, hãy điền nó với thuộc tính "lớp chardrv" chính xác, sau đó gọi device_create như trước, nhưng tôi không chắc chắn cách thực hiện điều đó.

Trả lời

-1

Nhân Linux sẽ không cho phép thực hiện điều đó. Đây là ERROR bạn sẽ nhận được.

**[ 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

Tôi không chắc chắn bạn đang rõ ràng khi tôi đang cố gắng làm ở đây ... ít nhất là lỗi đó không có ý nghĩa đối với câu hỏi của tôi. Ví dụ, tôi muốn tạo một lớp "chardrv", sau đó có một mô-đun hạt nhân đăng ký một thiết bị vào đó. Nói "device1". Sau đó, một mô-đun hạt nhân thứ hai sẽ đăng ký một thiết bị thứ hai vào cùng một lớp "device2". Vì vậy, bây giờ chạy một lệnh danh sách trên/sys/class/chardrv sẽ hiển thị cả hai thiết bị. Bạn có nói rằng không có cách nào để làm điều đó trong Linux? Dường như không đúng với tôi ... – Mike

3

Để thực hiện theo mã ví dụ của bạn, bạn chỉ đơn giản là sẽ gọi device_create() một lần nữa, đi qua các lớp tương tự, ví dụ:

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"); 

Bạn nên chắc chắn không cần phải kiểm tra đường dẫn để xác định xem các lớp đã được tạo. Bạn đang tạo mã trong mã của mình, vì vậy, chỉ cần kiểm tra c1 == NULL hoặc sử dụng cờ nếu bạn cần.

+0

Đối với trường hợp sử dụng đơn giản này, có, điều đó sẽ hoạt động. Điều gì về khi tôi có một thiết bị hạt nhân thứ hai? Khi tôi tinh chỉnh câu hỏi của mình, tôi đã đề cập rằng một mô-đun hạt nhân _second_ cũng sẽ muốn tạo một thiết bị vào cùng một/sys/class/chardrv directroy. Rõ ràng là không cần phải gọi 'class_create()' ở cả hai nơi. Nhưng nếu tôi không gọi phương thức này, làm cách nào để truy cập vào lớp chardrv của tôi cần cho tham số 1 của 'device_create()'. Một lần nữa: ** Mô-đun 1 ** gọi 'class_create()/device_create()'. ** Module 2 ** chỉ muốn gọi 'device_create()', nhưng yêu cầu tham chiếu lớp. – Mike

+0

Vì vậy, bạn cần thêm một API để truy xuất lớp. Tùy chọn đơn giản nhất là đặt hạt nhân vào đúng (không phải mô-đun) và có các mô-đun gọi vào đó. – mpe

+0

Và tôi ổn với điều đó, việc triển khai rất linh hoạt. Tuy nhiên tôi vẫn không chắc chắn như thế nào. Khi tôi gọi 'class_create()' parameter1 là 'THIS_MODULE'. Di chuyển việc tạo lớp tới kernel đúng, tôi giả sử 'THIS_MODULE' sẽ không hoạt động nữa. Hàm def của hàm class_create nói P1 là: "_owner: pointer trỏ tới mô-đun để sở hữu cấu trúc này class_". Điều này ngụ ý chủ sở hữu phải là một mô-đun. – Mike

6

Để sử dụng chức năng device_create với cùng một lớp, chỉ cần chuyển cho nó một con trỏ đến cùng một lớp.

Vì bạn muốn gọi device_create trong một mô-đun khác với mô-đun mà bạn tạo lớp, bạn sẽ cần xuất biểu tượng cho con trỏ đến lớp. Bạn có thể sử dụng macro EXPORT_SYMBOL để thực hiện việc này.


Ví dụ:

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.c

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"); 
     .... 
} 

Lưu ý: Bạn sẽ cần phải chèn module1 trước module2 kể từ khi con trỏ lớp được định nghĩa và xuất khẩu trong module1.

Điều đó sẽ tạo ra các thư mục bạn đang mong đợi:

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

Bằng cách này, nếu bạn đang nhận được một lỗi Invalid parameters khi bạn cố gắng để tải mô đun thứ hai, bạn có thể phải add a KBUILD_EXTRA_SYMBOLS line to your Makefile.

0

Chỉ cần tạo lớp trong hàm init mô đun của mô-đun đầu tiên của bạn, xuất biểu tượng lớp toàn cầu với EXPORT_SYMBOL và sử dụng nó từ mô-đun khác.

Vì chủ sở hữu của lớp là mô-đun đầu tiên của bạn, mỗi khi bạn thêm thiết bị vào lớp đó, bộ đếm tham chiếu của mô-đun đầu tiên sẽ tăng lên: bạn không thể tải nó trong khi bất kỳ ai đang sử dụng nó.