Trình điều khiển thiết bị IOCTL Linux [đã đóng]


126

Ai có thể giải thích cho tôi

  1. IOCTL
  2. Cái này được dùng để làm gì?
  3. Làm thế nào tôi có thể sử dụng nó?
  4. Tại sao tôi không thể xác định chức năng mới hoạt động tương tự IOCTL?

Câu trả lời:


99

Một ioctl, có nghĩa là "điều khiển đầu vào-đầu ra" là một loại cuộc gọi hệ thống dành riêng cho thiết bị. Chỉ có một vài cuộc gọi hệ thống trong Linux (300-400), không đủ để thể hiện tất cả các chức năng duy nhất mà thiết bị có thể có. Vì vậy, trình điều khiển có thể định nghĩa một ioctl cho phép ứng dụng không gian người dùng gửi đơn đặt hàng. Tuy nhiên, ioctls không linh hoạt và có xu hướng hơi lộn xộn (hàng tá "số ma thuật" chỉ hoạt động ... hoặc không), và cũng có thể không an toàn, khi bạn chuyển một bộ đệm vào kernel - xử lý xấu có thể phá vỡ mọi thứ dễ dàng

Một thay thế là sysfsgiao diện, nơi bạn thiết lập một tệp bên dưới /sys/và đọc / ghi nó để lấy thông tin từ và đến trình điều khiển. Một ví dụ về cách thiết lập điều này:

static ssize_t mydrvr_version_show(struct device *dev,
        struct device_attribute *attr, char *buf)
{
    return sprintf(buf, "%s\n", DRIVER_RELEASE);
}

static DEVICE_ATTR(version, S_IRUGO, mydrvr_version_show, NULL);

Và trong quá trình thiết lập trình điều khiển:

device_create_file(dev, &dev_attr_version);

Sau đó, bạn sẽ có một tệp cho thiết bị của mình /sys/, ví dụ, /sys/block/myblk/versioncho trình điều khiển khối.

Một phương pháp khác để sử dụng nặng hơn là netlink, đó là phương pháp IPC (giao tiếp giữa các quá trình) để nói chuyện với trình điều khiển của bạn qua giao diện ổ cắm BSD. Điều này được sử dụng, ví dụ, bởi các trình điều khiển WiFi. Sau đó, bạn giao tiếp với nó từ không gian người dùng bằng cách sử dụng libnlhoặc libnl3thư viện.


3
Câu trả lời này 'trả lời' câu hỏi một phần.
Vishal Sahu

163

Các ioctlchức năng rất hữu ích cho việc thực hiện một trình điều khiển thiết bị để thiết lập cấu hình trên thiết bị. ví dụ: một máy in có các tùy chọn cấu hình để kiểm tra và đặt họ phông chữ, cỡ chữ, v.v. ioctlcó thể được sử dụng để lấy phông chữ hiện tại cũng như đặt phông chữ thành một phông chữ mới. Một ứng dụng người dùng sử dụng ioctlđể gửi mã đến một máy in yêu cầu nó trả lại phông chữ hiện tại hoặc đặt phông chữ thành một phông chữ mới.

int ioctl(int fd, int request, ...)
  1. fdlà mô tả tập tin, cái được trả về bởi open;
  2. requestlà mã yêu cầu. vd: GETFONTsẽ lấy phông chữ hiện tại từ máy in, SETFONTsẽ đặt phông chữ trên máy in;
  3. đối số thứ ba là void *. Tùy thuộc vào đối số thứ hai, đối số thứ ba có thể có hoặc không có mặt, ví dụ: nếu đối số thứ hai là SETFONT, đối số thứ ba có thể là tên phông chữ như "Arial";

int requestkhông chỉ là một vĩ mô. Cần có ứng dụng người dùng để tạo mã yêu cầu và mô-đun trình điều khiển thiết bị để xác định cấu hình nào trên thiết bị phải được phát. Ứng dụng sẽ gửi mã yêu cầu bằng cách sử dụng ioctlvà sau đó sử dụng mã yêu cầu trong mô-đun trình điều khiển thiết bị để xác định hành động nào sẽ thực hiện.

Mã yêu cầu có 4 phần chính

    1. A Magic number - 8 bits
    2. A sequence number - 8 bits
    3. Argument type (typically 14 bits), if any.
    4. Direction of data transfer (2 bits).  

Nếu mã yêu cầu là SETFONTđặt phông chữ trên máy in, hướng truyền dữ liệu sẽ là từ ứng dụng người dùng đến mô-đun trình điều khiển thiết bị (Ứng dụng người dùng sẽ gửi tên phông chữ "Arial"cho máy in). Nếu mã yêu cầu là GETFONT, hướng từ máy in đến ứng dụng người dùng.

Để tạo mã yêu cầu, Linux cung cấp một số macro giống như chức năng được xác định trước.

1. _IO(MAGIC, SEQ_NO)cả hai đều là 8 bit, 0 đến 255, ví dụ: giả sử chúng tôi muốn tạm dừng máy in. Điều này không yêu cầu chuyển dữ liệu. Vì vậy, chúng tôi sẽ tạo mã yêu cầu như dưới đây

#define PRIN_MAGIC 'P'
#define NUM 0
#define PAUSE_PRIN __IO(PRIN_MAGIC, NUM) 

và bây giờ sử dụng ioctlnhư

ret_val = ioctl(fd, PAUSE_PRIN);

Cuộc gọi hệ thống tương ứng trong mô-đun trình điều khiển sẽ nhận mã và tạm dừng máy in.

  1. __IOW(MAGIC, SEQ_NO, TYPE) MAGICSEQ_NOgiống như trên và TYPEđưa ra loại đối số tiếp theo, nhớ lại đối số thứ ba ioctlvoid *. W in __IOWchỉ ra rằng luồng dữ liệu là từ ứng dụng người dùng đến mô-đun trình điều khiển. Ví dụ: giả sử chúng tôi muốn đặt phông chữ máy in thành "Arial".
#define PRIN_MAGIC 'S'
#define SEQ_NO 1
#define SETFONT __IOW(PRIN_MAGIC, SEQ_NO, unsigned long)

thêm nữa,

char *font = "Arial";
ret_val = ioctl(fd, SETFONT, font); 

Bây giờ fontlà một con trỏ, có nghĩa là nó là một địa chỉ được thể hiện tốt nhất unsigned long, do đó phần thứ ba của _IOWloại đề cập như vậy. Ngoài ra, địa chỉ phông chữ này được chuyển đến cuộc gọi hệ thống tương ứng được triển khai trong mô-đun trình điều khiển thiết bị unsigned long và chúng ta cần chuyển nó thành loại thích hợp trước khi sử dụng nó. Không gian hạt nhân có thể truy cập không gian người dùng và do đó điều này hoạt động. hai macro giống như hàm khác là __IOR(MAGIC, SEQ_NO, TYPE)__IORW(MAGIC, SEQ_NO, TYPE)nơi luồng dữ liệu sẽ từ không gian nhân đến không gian người dùng và cả hai cách tương ứng.

Xin vui lòng cho tôi biết nếu điều này giúp!


Tôi tự hỏi liệu các hàm __IOW, __IOR và __IORW ở trên có chính xác không (ý tôi là dấu gạch dưới kép trong một số trường hợp, trong một số trường hợp thì không. Tôi chưa bao giờ sử dụng dấu gạch dưới kép) ... Cảm ơn vì đã giải thích rõ ràng!
jcoppens

Giải thích rất tốt .. Cảm ơn! Bạn có thể vui lòng cung cấp một đoạn mã nhỏ của phía trình điều khiển sử dụng ioctl này không?
Aadishri


Giải thích rất tốt. Cảm ơn bạn. Tôi nghĩ đó là _IOWR chứ không phải _IORW
Mohamed Samy

Trả lời như một bài viết trên blog.
Fredrick Gauss
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.