我正在为自定义设备开发一个内核模块,实际上,它是一个连接到 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),但我已经修复了这个错误。