Câu trả lời:
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à sysfs
giao 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/version
cho 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 libnl
hoặc libnl3
thư viện.
Các ioctl
chứ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. ioctl
có 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, ...)
fd
là mô tả tập tin, cái được trả về bởi open
;request
là mã yêu cầu. vd: GETFONT
sẽ lấy phông chữ hiện tại từ máy in, SETFONT
sẽ đặt phông chữ trên máy in;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 request
khô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 ioctl
và 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 ioctl
như
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.
__IOW(MAGIC, SEQ_NO, TYPE)
MAGIC
và SEQ_NO
giống như trên và TYPE
đưa ra loại đối số tiếp theo, nhớ lại đối số thứ ba ioctl
là void *
. W in __IOW
chỉ 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ờ font
là 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 _IOW
loạ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)
và __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!