0

我正在为自定义设备开发一个内核模块,实际上,它是一个连接到 ISA 总线的 4*8 位 io 端口,地址为 0x0120 - 0x0123。该驱动程序基于 Alessandro Rubini 和 Jonathan Corbet 的“scull”。我的操作系统是 Ubuntu 10.04,内核是 2.6.32-74 通用的,我使用内置的面向控制台的编译器 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;

}

  • 一切正常,状态栏显示从设备读取的字符串。但是当我尝试写入设备文件时 - 问题出现了。我写设备文件的函数总是报错。

    GError * on_BnStop_clicked (GtkButton *button, gpointer data)
    {
    char Data = 255;
    FILE * ET3201 = NULL;
    char buf;
    ERR = NULL;
    GtkWidget *label = GTK_WIDGET(data);
    g_assert(label != NULL);
    if ( Started ) Started = FALSE; 
    if ( ! Started ) Data = 0;              /* FOR TESTING ONLY!!!*/
    gchar *LabelText = "STOP";
    gtk_label_set_text(GTK_LABEL(label), LabelText);
    errno = 0;
    ET3201=fopen(DevFile,"w");/* Opening the device ET3201 */
    ErrorCode = errno;
    if (ET3201 == NULL)
    {
        ERR = g_error_new ( G_FILE_ERROR, G_FILE_ERROR_NXIO, "Can't
    open port ET3201!" );
        goto fail;
    }   
    setvbuf(ET3201,&buf,_IONBF,1); /* We remove the buffer from the
    file i/o */
    fwrite(&Data,1,1,ET3201);       /* Writing to device*/
    sleep(1);
    fclose(ET3201);    
    /* g_free(&buf);  - leading to "Program aborted" */
    fail: 
    return ERR; 
    }
    

- 就像 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 写入临时文件然后尝试将其重命名为“权限被拒绝”的设备文件。这可能是编写设备文件的错误方法,请帮助我找到正确的方法...

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

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

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 == NULL 成功完成。毕竟,错误报告功能因“分段错误”而崩溃(报告 ERR == NULL),但我已经修复了这个错误。

4

1 回答 1

0

g_file_set_contents的文档说:

这种写入是原子的,因为它首先写入一个临时文件,然后将其重命名为最终名称。

所以, file/dev/ET32010.****8X实际上是temporal。而且,由于通常只允许 root 用户在下创建文件,因此临时文件的创建失败并显示“权限被拒绝”。/dev

即使/dev允许写入,g_file_set_contents也会 设备文件替换为常规文件,这不是您想要的。

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

于 2015-11-24T10:11:01.270 回答