ไดรเวอร์อุปกรณ์ IOCTL Linux [ปิด]


126

ใครช่วยอธิบายฉันที

  1. คืออะไรIOCTL?
  2. ใช้ทำอะไร?
  3. ฉันจะใช้มันได้อย่างไร?
  4. ทำไมฉันจึงไม่สามารถกำหนดฟังก์ชั่นใหม่ที่ทำงานเช่นเดียวกับIOCTL?

คำตอบ:


99

An ioctlซึ่งหมายถึง "การควบคุมอินพุต - เอาต์พุต" เป็นการเรียกระบบเฉพาะอุปกรณ์ มีการเรียกระบบเพียงไม่กี่สายใน Linux (300-400) ซึ่งไม่เพียงพอที่จะแสดงฟังก์ชันเฉพาะทั้งหมดที่อุปกรณ์อาจมี ดังนั้นผู้ขับขี่สามารถกำหนด ioctl ซึ่งอนุญาตให้แอปพลิเคชัน userspace ส่งคำสั่งได้ อย่างไรก็ตาม ioctls ไม่ค่อยมีความยืดหยุ่นและมีแนวโน้มที่จะเกะกะเล็กน้อย ("เลขวิเศษ" หลายสิบตัวซึ่งใช้ได้ผล ... หรือไม่) และอาจไม่ปลอดภัยเนื่องจากคุณส่งบัฟเฟอร์เข้าไปในเคอร์เนล - การจัดการที่ไม่ดีอาจแตกได้ สิ่งต่างๆได้อย่างง่ายดาย

อีกทางเลือกหนึ่งคือsysfsอินเทอร์เฟซที่คุณตั้งค่าไฟล์ภายใต้/sys/และอ่าน / เขียนเพื่อรับข้อมูลจากและไปยังไดรเวอร์ ตัวอย่างวิธีการตั้งค่า:

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

และระหว่างการตั้งค่าไดรเวอร์:

device_create_file(dev, &dev_attr_version);

จากนั้นคุณจะมีไฟล์สำหรับอุปกรณ์ของคุณ/sys/ตัวอย่างเช่น/sys/block/myblk/versionสำหรับไดรเวอร์บล็อก

อีกวิธีหนึ่งสำหรับการใช้งานที่หนักกว่าคือ netlink ซึ่งเป็นวิธี IPC (การสื่อสารระหว่างกระบวนการ) เพื่อพูดคุยกับคนขับของคุณผ่านอินเทอร์เฟซซ็อกเก็ต BSD สิ่งนี้ถูกใช้โดยไดรเวอร์ WiFi จากนั้นคุณจะสื่อสารกับมันจาก userspace โดยใช้libnlหรือlibnl3ไลบรารี


3
คำตอบนี้ 'ตอบ' คำถามบางส่วน
Vishal Sahu

163

ioctlฟังก์ชั่นจะเป็นประโยชน์สำหรับการใช้ไดรเวอร์อุปกรณ์ที่จะตั้งกำหนดค่าบนอุปกรณ์ เช่นเครื่องพิมพ์ที่มีตัวเลือกการกำหนดค่าเพื่อตรวจสอบและตั้งค่าตระกูลฟอนต์ขนาดฟอนต์ ฯลฯioctlสามารถใช้เพื่อรับฟอนต์ปัจจุบันรวมทั้งตั้งฟอนต์เป็นฟอนต์ใหม่ แอปพลิเคชันผู้ใช้ใช้ioctlเพื่อส่งรหัสไปยังเครื่องพิมพ์เพื่อบอกให้ส่งคืนแบบอักษรปัจจุบันหรือตั้งค่าแบบอักษรเป็นแบบใหม่

int ioctl(int fd, int request, ...)
  1. fdคือ file descriptor ซึ่งส่งคืนโดยopen;
  2. requestคือรหัสคำขอ เช่นGETFONTจะได้รับแบบอักษรปัจจุบันจากเครื่องพิมพ์SETFONTจะตั้งค่าแบบอักษรบนเครื่องพิมพ์
  3. void *อาร์กิวเมนต์ที่สามคือ ขึ้นอยู่กับอาร์กิวเมนต์ที่สองอาร์กิวเมนต์ที่สามอาจมีหรือไม่มีก็ได้เช่นหากอาร์กิวเมนต์ที่สองเป็นอาร์กิวเมนต์SETFONTที่สามอาจเป็นชื่อฟอนต์เช่น"Arial";

int requestไม่ใช่แค่มาโคร จำเป็นต้องมีแอปพลิเคชันผู้ใช้เพื่อสร้างรหัสคำขอและโมดูลไดรเวอร์อุปกรณ์เพื่อกำหนดว่าจะต้องเล่นกับการกำหนดค่าใดบนอุปกรณ์ แอปพลิเคชันจะส่งรหัสคำขอโดยใช้ioctlแล้วใช้รหัสคำขอในโมดูลไดรเวอร์อุปกรณ์เพื่อพิจารณาว่าจะดำเนินการใด

รหัสคำขอมี 4 ส่วนหลัก

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

หากรหัสคำขอคือSETFONTการตั้งค่าแบบอักษรบนเครื่องพิมพ์ทิศทางในการถ่ายโอนข้อมูลจะเป็นจากแอปพลิเคชันผู้ใช้ไปยังโมดูลไดรเวอร์อุปกรณ์ (แอปพลิเคชันผู้ใช้จะส่งชื่อแบบอักษร"Arial"ไปยังเครื่องพิมพ์) หากรหัสคำขอคือGETFONTทิศทางจากเครื่องพิมพ์ไปยังแอปพลิเคชันผู้ใช้

ในการสร้างรหัสคำขอ Linux จะมีมาโครที่เหมือนฟังก์ชันที่กำหนดไว้ล่วงหน้า

1. _IO(MAGIC, SEQ_NO)ทั้งสองคือ 8 บิต 0 ถึง 255 เช่นให้เราบอกว่าเราต้องการหยุดเครื่องพิมพ์ชั่วคราว ไม่จำเป็นต้องมีการถ่ายโอนข้อมูล ดังนั้นเราจะสร้างรหัสคำขอดังต่อไปนี้

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

และตอนนี้ใช้ioctlเป็น

ret_val = ioctl(fd, PAUSE_PRIN);

การเรียกระบบที่เกี่ยวข้องในโมดูลไดรเวอร์จะรับรหัสและหยุดเครื่องพิมพ์ชั่วคราว

  1. __IOW(MAGIC, SEQ_NO, TYPE) MAGICและSEQ_NOเป็นเช่นเดียวกับข้างต้นและTYPEทำให้ประเภทของการโต้แย้งต่อไปจำอาร์กิวเมนต์ที่สามของการมีioctl void *W in __IOWแสดงว่ากระแสข้อมูลมาจากแอปพลิเคชันผู้ใช้ไปยังโมดูลไดรเวอร์ "Arial"ตัวอย่างเช่นสมมติว่าเราต้องการที่จะตั้งตัวอักษรเครื่องพิมพ์เพื่อ
#define PRIN_MAGIC 'S'
#define SEQ_NO 1
#define SETFONT __IOW(PRIN_MAGIC, SEQ_NO, unsigned long)

เพิ่มเติม

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

ตอนนี้fontเป็นตัวชี้ซึ่งหมายความว่าเป็นที่อยู่ที่แสดงได้ดีที่สุดunsigned longดังนั้นส่วนที่สามของการ_IOWกล่าวถึงประเภทนี้ นอกจากนี้ที่อยู่ของแบบอักษรนี้จะถูกส่งไปยังการเรียกระบบที่เกี่ยวข้องซึ่งใช้งานในโมดูลไดรเวอร์อุปกรณ์unsigned long และเราจำเป็นต้องแคสต์เป็นประเภทที่เหมาะสมก่อนที่จะใช้ พื้นที่เคอร์เนลสามารถเข้าถึงพื้นที่ผู้ใช้และด้วยเหตุนี้จึงใช้งานได้ อีกสองฟังก์ชั่นเหมือนมาโครอยู่__IOR(MAGIC, SEQ_NO, TYPE)และ__IORW(MAGIC, SEQ_NO, TYPE)ข้อมูลที่ไหลจะมาจากพื้นที่ไปยังพื้นที่เคอร์เนลของผู้ใช้และวิธีการทั้งสองตามลำดับ

โปรดแจ้งให้เราทราบหากสิ่งนี้ช่วยได้!


ฉันสงสัยว่าฟังก์ชัน __IOW, __IOR และ __IORW ข้างต้นถูกต้องหรือไม่ (ฉันหมายถึงขีดล่างสองเท่าในบางกรณีไม่ใช่ในบางกรณีฉันไม่เคยใช้เครื่องหมายขีดล่างคู่เลย) ... ขอบคุณสำหรับคำอธิบายที่ชัดเจน!
jcoppens

อธิบายได้ดีมาก .. ขอบคุณ! คุณช่วยให้ข้อมูลโค้ดด้านคนขับที่ใช้ ioctl นี้เล็กน้อยได้ไหม
Aadishri

อ้างอิงopensourceforu.com/2011/08/io-control-in-linuxเช่น
chandola

อธิบายได้ดีมาก ขอบคุณ. ฉันคิดว่า _IOWR ไม่ใช่ _IORW
Mohamed Samy

ตอบเหมือนโพสต์ในบล็อก
Fredrick Gauss
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.