数据无法从用户空间程序写入设备文件

Data cannot be written to device file from userspace program

我正在为自定义设备开发一个内核模块,实际上是一个连接到 ISA 总线的 4*8 位 i-o 端口,地址为 0x0120 - 0x0123。该驱动程序基于 Alessandro Rubini 和 Jonathan Corbet 的 "scull"。我的 OS 是 Ubuntu 10.04,内核是 2.6.32-74 generic,我使用内置的面向控制台的编译器 gcc。 现在模块加载卸载成功,读写功能实现。从设备文件读取我是这样实现的:

gboolean DataRead (GtkWidget *widget, gpointer data)
{
GtkWidget *statusbar = GTK_WIDGET(data);
g_assert(statusbar != NULL);
gchar *StatusText = "Reading data from ADC F-4226";
gtk_statusbar_remove (GTK_STATUSBAR(statusbar), StatusBarContext, MessageId);
StatusBarContext = gtk_statusbar_get_context_id (GTK_STATUSBAR(statusbar), "ET3201-read");
MessageId = gtk_statusbar_push (GTK_STATUSBAR(statusbar), StatusBarContext, StatusText);
ERR = NULL; 
gchar *contents;
gsize *length = NULL;
gboolean ReadOK = FALSE;

ReadOK = g_file_get_contents (DevFile, &contents, length, &ERR);
if (ReadOK) StatusText = contents;
    else 
    {
        g_warning ("Can't open ET3201: %s", ERR->message);
        StatusText = g_strdup_printf("Error!!! %s: %d, %s", g_quark_to_string (ERR->domain), ERR->code, ERR->message);
        g_error_free(ERR);
    }
    gtk_statusbar_remove (GTK_STATUSBAR(statusbar), StatusBarContext, MessageId);
    StatusBarContext = gtk_statusbar_get_context_id (GTK_STATUSBAR(statusbar), "ET3201-read");
    MessageId = gtk_statusbar_push (GTK_STATUSBAR(statusbar), StatusBarContext, StatusText);
    g_free(contents);
}
return ReadOK;

}

-就像 ET3201 == NULL 一样。此时内核模块已加载并且可以从中读取。调试后我发现内核模块中的 "Write" 函数从未被调用,因为它不会在内核日志中打印相应的 "printk" 消息。无奈之下,我尝试这样做:

GError * on_BnStart_clicked (GtkButton *button, gpointer data)
{
    gchar *contents;
    gssize length = 0;
    ERR = NULL;
    GtkWidget *label = GTK_WIDGET(data);
    g_assert(label != NULL);
    if (! Started ) Started = TRUE; 
    gchar *LabelText = "RUN";
    gtk_label_set_text(GTK_LABEL(label), LabelText);

    contents = g_strdup_printf("/255");   /*FOR TESTING PURPOSES!!!*/

    length = sizeof(contents);

    g_file_set_contents (DevFile, contents, length, &ERR);

    return ERR; 
}

我在状态栏中收到一条错误消息: 错误:g-file-error-quark: 2,无法创建文件 '/dev/ET32010.****8X':权限被拒绝 我认为那是因为 g_file_set_contents 写入一个临时文件,然后尝试将其重命名为设备文件 "Permission denied"。这可能是写设备文件的错误方式,请帮我找到正确的...

我的问题:为什么我的函数 on_BnStop_clicked 不能正常工作?如何从用户空间程序正确写入字符设备文件?

我已经检查了设备访问权限...

master@master-desktop:~$ ls -l /dev/ET3201*
lrwxrwxrwx 1 root root       7 2015-11-23 14:34 /dev/ET3201 -> ET32010
crw-rw-r-- 1 root staff 250, 0 2015-11-23 14:34 /dev/ET32010
crw-rw-r-- 1 root staff 250, 1 2015-11-23 14:34 /dev/ET32011
crw-rw-r-- 1 root staff 250, 2 2015-11-23 14:34 /dev/ET32012
crw-rw-r-- 1 root staff 250, 3 2015-11-23 14:34 /dev/ET32013

然后将内核模块初始化脚本中的模式更改为 666

lrwxrwxrwx 1 root root       7 2015-11-23 22:27 /dev/ET3201 -> ET32010
crw-rw-rw- 1 root staff 250, 0 2015-11-23 22:27 /dev/ET32010
crw-rw-rw- 1 root staff 250, 1 2015-11-23 22:27 /dev/ET32011
crw-rw-rw- 1 root staff 250, 2 2015-11-23 22:27 /dev/ET32012
crw-rw-rw- 1 root staff 250, 3 2015-11-23 22:27 /dev/ET32013

和on_BnStart_clicked函数像以前一样返回"Permission denied",但是on_BnStop_clicked已经调用了内核模块的"Write"方法,然后成功完成并返回ERR ==无效的。毕竟错误报告功能已经崩溃 "Segmentation fault"(报告 ERR == NULL)但我已经修复了这个错误。

g_file_set_contents 的文档说:

This write is atomic in the sense that it is first written to a temporary file which is then renamed to the final name.

因此,文件 /dev/ET32010.****8X 实际上是 时间 。而且,因为 /dev 下创建 文件通常只允许 root,临时文件的创建失败 "Permission denied".

即使允许写入 /devg_file_set_contents 也会 替换 device 文件 普通一个,不是你想要的

您需要使用较低级别的方式写入设备文件。例如,使用 fopen + fwrite.