1. 程式人生 > 其它 >【問題排查】error: too many arguments to function ‘tty->driver->ops->ioctl‘處理

【問題排查】error: too many arguments to function ‘tty->driver->ops->ioctl‘處理

技術標籤:Linux 日常使用與開發系統報錯及處理ttyioctllinux核心嵌入式

當前核心版本:3.18.y

原始碼對應的核心版本:2.6.37

程式碼移植過程中報錯:

...491:13: error: too many arguments to function 'tty->driver->ops->ioctl'
     error = (tty->driver->ops->ioctl)(tty, file, FIONWBUFD, (unsigned long)&d_buff);

比較兩個核心的差異。

tty->driver->ops->ioctl

最終找到差異點:
【3.18.y】
struct tty_operations {
    ...
    int  (*ioctl)(struct tty_struct *tty, unsigned int cmd, unsigned long arg);
}
【2.6.37】
struct tty_operations {
    ...
    int  (*ioctl)(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
}

解決辦法就是去掉一個file引數就行了。

為什麼會有差異?為什麼去掉了struct file引數?

struct file * file:ioctl的操作有可能是要修改檔案的屬性,或者訪問硬體。要修改檔案屬性的話,就要用到這個結構體了,所以這裡傳來了它們的指標


順便發一下,tty_operations各個成員的作用:

struct tty_operations {
        struct tty_struct * (*lookup)(struct tty_driver *driver,
                        struct inode *inode, int idx);
//返回對應的tty裝置, 若為NULL則返回ERR_PTR, 在tty_mutex函式中呼叫
 
        int  (*install)(struct tty_driver *driver, struct tty_struct *tty);
//install一個tty裝置到tty驅動的內部表,與lookup和remove法相關聯
 
        void (*remove)(struct tty_driver *driver, struct tty_struct *tty);
//從tty驅動的內部表,remove一個關閉了的tty裝置,與lookup和remove法相關聯
 
        int  (*open)(struct tty_struct * tty, struct file * filp);
//當一個特別的tty裝置open的時候,將呼叫該例程;該例程是強制性的,若該例程沒有加入operations,open tty的時候將返回ENODEV
//必須使用的方法
        void (*close)(struct tty_struct * tty, struct file * filp);
//當tty裝置關閉時呼叫
//必須使用的方法
        void (*shutdown)(struct tty_struct *tty);
//在tty在關閉時,若仍持有一個帶鎖的特殊裝置,需要呼叫該例程,想想我們經常使用的sudo shutdown -r/h/... now就明白了
//它執行在tty裝置釋放資源之前,所以可能執行在另一個tty裝置持有kref的時候
        void (*cleanup)(struct tty_struct *tty);
//當一個tty裝置在最後一次被關閉和釋放資源時,非同步地呼叫該例程,這個例程可以看成shutdown的可休眠的第二部分
        int  (*write)(struct tty_struct * tty,
                      const unsigned char *buf, int count);
//寫函式,不多說
//可選使用:在需要寫的裝置中
        int  (*put_char)(struct tty_struct *tty, unsigned char ch);
//當核心想寫單個字元到tty裝置時,呼叫該例程(其實也可以呼叫write例程,呼叫時置count為1即可)
//可選使用:若裝置在呼叫時未提供將使用write法
//注意:不要直接呼叫該例程,而應呼叫tty_put_char
        void (*flush_chars)(struct tty_struct *tty);
//這個例程呼叫在tty使用put_char輸出很多個字元後
//可選
//注意:不要直接呼叫,呼叫tty_driver_flush_chars
        int  (*write_room)(struct tty_struct *tty);
//這個例程返回tty裝置將被寫入的字元佇列長度
//這個數字受輸出緩衝區和輸出流的變化影響
//當有write函式時需要
//注意:不要直接呼叫,呼叫tty_write_room
        int  (*chars_in_buffer)(struct tty_struct *tty);
//在buffer區中的字元
        int  (*ioctl)(struct tty_struct *tty,
                    unsigned int cmd, unsigned long arg);
//該例程允許tty裝置實施裝置特殊的ioctl,若ioctl的數值在cmd中未被裝置檢測到,將返回ENOIOCTLCMD
//可選
        long (*compat_ioctl)(struct tty_struct *tty,
                             unsigned int cmd, unsigned long arg);
//在64位系統中執行32位的ioctl的例程
//可選
        void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
//該例程在裝置的termios設定改變時通知驅動
//可選:在持termios lock的時候呼叫
        void (*throttle)(struct tty_struct * tty);
//當執行緒規劃快滿的時候提醒驅動程式,提示不要再輸入字元到tty中
//可選:通常在tty_throttle()函式中獲得termios lock時呼叫
void (*unthrottle)(struct tty_struct * tty);
//提醒驅動程式,可以輸入字元到tty中,因為執行緒規劃空間夠用
//可選:通常在tty_unthrottle()函式中,獲得termios lock時呼叫
        void (*stop)(struct tty_struct *tty);
//提醒驅動,停止輸出字元
//可選,注意:不是呼叫stop_tty
        void (*start)(struct tty_struct *tty);
//提醒驅動,接著輸入字元
//可選,助於:不是呼叫start_tty
        void (*hangup)(struct tty_struct *tty);
//掛起tty,可選
        int (*break_ctl)(struct tty_struct *tty, int state);
//開啟或關閉RS-232口,state為-1則開啟,state為0則關閉
//若該函式執行,則高一級的tty將處理四種ioctls:TCSBRK, TCSBRKP, TIOCSBRK, TIOCCBRK
//如果驅動程式設定了TTY_DRIVER_HARDWARE_BREAK,接著介面將被稱作實際時間,而硬體延遲工作
//可選:需要收到TCSBRK/BRKP/etc
        void (*flush_buffer)(struct tty_struct *tty);
//在使用put_char()寫入一串字元後,該函式被核心呼叫
//可選
//注意:呼叫是應為tty_driver_flush_buffer
        void (*set_ldisc)(struct tty_struct *tty);
//該例程在裝置的termios設定改變時通知驅動
//可選:有BKL (currently)時呼叫
        void (*wait_until_sent)(struct tty_struct *tty, int timeout);
//該例程等待裝置將其所有字元寫入傳輸FIFO中
//可選:若裝置有FIFO則需要
//注意:通常使用為tty_wait_until_sent
        void (*send_xchar)(struct tty_struct *tty, char ch);
//該例程傳送一個大端的XON/XOFF給驅動程式
//可選:如果不提供,之後寫函式將被原子鎖呼叫來保持它的序列性
        int (*tiocmget)(struct tty_struct *tty);
//獲得tty的線路設定
        int (*tiocmset)(struct tty_struct *tty,
                        unsigned int set, unsigned int clear);
//設定tty的線路設定
        int (*resize)(struct tty_struct *tty, struct winsize *ws);
//當一個termios的請求將改變 請求終端幾何(requested terminal geometry)時呼叫
//可選:預設行為是 無錯誤地更新termios structure......
        int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
//當收到一個termiox基於ioctl的訊號時呼叫,將使用者空間的請求向下傳遞
//這個函式只有當tty包含tty->termiox指標的時候才會執行
//可選:持有termios lock的時候呼叫
        int (*get_icount)(struct tty_struct *tty,
                                struct serial_icounter_struct *icount);
//當裝置收到一個TIOCGICOUNT的訊號時呼叫,將一個核心結構傳入使其完成。
//這個函式只有在提供的時候呼叫,否則將返回EINVAL
#ifdef CONFIG_CONSOLE_POLL
        int (*poll_init)(struct tty_driver *driver, int line, char *options);
        int (*poll_get_char)(struct tty_driver *driver, int line);
        void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
#endif
        const struct file_operations *proc_fops;
};