W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
在 struct tty_driver 中的 ioctl 函數(shù)被 tty 核心調(diào)用當(dāng) ioctl(2) 被在設(shè)備節(jié)點(diǎn)上調(diào)用. 如果這個(gè) tty 驅(qū)動(dòng)不知道如何處理傳遞給它的 ioctl 值, 它應(yīng)當(dāng)返回 -ENOIOCTLCMD 來試圖讓 tty 核心實(shí)現(xiàn)一個(gè)通用的調(diào)用版本.
2.6 內(nèi)核定義了大約 70 個(gè)不同的 tty ioctls, 可被用來發(fā)送給一個(gè) tty 驅(qū)動(dòng). 大部分的 tty 驅(qū)動(dòng)不處理它們?nèi)? 但是只有一個(gè)小的更普通的子集. 這是一個(gè)更通用的 tty ioctls 列表, 它們的含義, 以及如何實(shí)現(xiàn)它們:
TIOCSERGETLSR
獲得這個(gè) tty 設(shè)備的線路狀態(tài)寄存器( LSR )的值.
TIOCGSERIAL
獲得串口線信息. 調(diào)用者可以潛在地從 tty 設(shè)備獲得許多串口線路信息, 在這個(gè)調(diào)用中一次全部. 一些程序( 例如 setserial 和 dip) 調(diào)用這個(gè)函數(shù)來確保波特率被正確設(shè)置, 以及來獲得通常的關(guān)于驅(qū)動(dòng)控制的設(shè)備類型信息. 調(diào)用者傳遞一個(gè)指向一個(gè)大的 serial_struct 結(jié)構(gòu)的指針, 這個(gè)結(jié)構(gòu)應(yīng)當(dāng)由 tty 驅(qū)動(dòng)填充正確的值. 這是一個(gè)如何實(shí)現(xiàn)這個(gè)的例子:
static int tiny_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
{
struct tiny_serial *tiny = tty->driver_data;
if (cmd == TIOCGSERIAL)
{
struct serial_struct tmp;
if (!arg)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
tmp.type = tiny->serial.type;
tmp.line = tiny->serial.line;
tmp.port = tiny->serial.port;
tmp.irq = tiny->serial.irq;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
tmp.xmit_fifo_size = tiny->serial.xmit_fifo_size;
tmp.baud_base = tiny->serial.baud_base;
tmp.close_delay = 5*HZ;
tmp.closing_wait = 30*HZ;
tmp.custom_divisor = tiny->serial.custom_divisor;
tmp.hub6 = tiny->serial.hub6;
tmp.io_type = tiny->serial.io_type;
if (copy_to_user((void __user *)arg, &tmp, sizeof(tmp)))
return -EFAULT;
return 0;
}
return -ENOIOCTLCMD;
}
TIOCSSERIAL
設(shè)置串口線路信息. 這是 IOCGSERIAL 的反面, 并且允許用戶一次全部設(shè)置 tty 設(shè)備的串口線狀態(tài). 一個(gè)指向 struct serial_struct 的指針被傳遞給這個(gè)調(diào)用, 填滿這個(gè) tty 設(shè)備應(yīng)當(dāng)被設(shè)置的數(shù)據(jù). 如果這個(gè) tty 驅(qū)動(dòng)沒有實(shí)現(xiàn)這個(gè)調(diào)用, 大部分程序仍然正確工作.
TIOCMIWAIT
等待 MSR 改變. 用戶在非尋常的情況下請求這個(gè) ioctl, 它想在內(nèi)核中睡眠直到這個(gè) tty 設(shè)備的 MSR 寄存器發(fā)生某些事情. arg 參數(shù)包含用戶在等待的事件類型. 這通常用來等待直到一個(gè)狀態(tài)線變化, 指示有更多的數(shù)據(jù)發(fā)送給設(shè)備.
當(dāng)實(shí)現(xiàn)這個(gè) ioctl 時(shí)要小心, 并且不要使用 interruptible_sleep_on 調(diào)用, 因?yàn)樗遣话踩?有很多不好的競爭條件涉及它). 相反, 一個(gè) wait_queue 應(yīng)當(dāng)用來避免這個(gè)問題. 這是一個(gè)如何實(shí)現(xiàn)這個(gè) ioctl 的例子:
static int tiny_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
{
struct tiny_serial *tiny = tty->driver_data;
if (cmd == TIOCMIWAIT)
{
DECLARE_WAITQUEUE(wait, current);
struct async_icount cnow;
struct async_icount cprev;
cprev = tiny->icount;
while (1) {
add_wait_queue(&tiny->wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
schedule();
remove_wait_queue(&tiny->wait, &wait); /* see if a signal woke us up */
if (signal_pending(current))
return -ERESTARTSYS;
cnow = tiny->icount;
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
return -EIO; /* no change => error */
if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
return 0;
}
cprev = cnow;
}
}
return -ENOIOCTLCMD;
}
在 tty 驅(qū)動(dòng)的代碼中能知道 MSR 寄存器改變的某些地方, 下面的代碼行必須調(diào)用以便這個(gè)代碼能正常工作:
wake_up_interruptible(&tp->wait);
TIOCGICOUNT
獲得中斷計(jì)數(shù). 當(dāng)用戶要知道已經(jīng)產(chǎn)生多少串口線中斷時(shí)調(diào)用. 如果驅(qū)動(dòng)有一個(gè)中斷處理, 它應(yīng)當(dāng)定義一個(gè)內(nèi)部計(jì)數(shù)器結(jié)構(gòu)來跟蹤這些統(tǒng)計(jì)和遞增適當(dāng)?shù)挠?jì)數(shù)器, 每次這個(gè)函數(shù)被內(nèi)核運(yùn)行時(shí).
這個(gè) ioctl 調(diào)用傳遞內(nèi)核一個(gè)指向結(jié)構(gòu) serial_icounter_struct 的指針, 它應(yīng)當(dāng)被 tty 驅(qū)動(dòng)填充. 這個(gè)調(diào)用常常和之前的 IOCMIWAIT ioctl 調(diào)用結(jié)合使用. 如果 tty 驅(qū)動(dòng)跟蹤所有的這些中斷在驅(qū)動(dòng)操作時(shí), 實(shí)現(xiàn)這個(gè)調(diào)用的代碼會(huì)非常簡單:
static int tiny_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
{
struct tiny_serial *tiny = tty->driver_data;
if (cmd == TIOCGICOUNT)
{
struct async_icount cnow = tiny->icount;
struct serial_icounter_struct icount;
icount.cts = cnow.cts;
icount.dsr = cnow.dsr;
icount.rng = cnow.rng;
icount.dcd = cnow.dcd;
icount.rx = cnow.rx;
icount.tx = cnow.tx;
icount.frame = cnow.frame;
icount.overrun = cnow.overrun;
icount.parity = cnow.parity;
icount.brk = cnow.brk;
icount.buf_overrun = cnow.buf_overrun;
if (copy_to_user((void __user *)arg, &icount, sizeof(icount)))
return -EFAULT;
return 0;
}
return -ENOIOCTLCMD;
}
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: