数据无法从用户空间程序写入设备文件
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;
}
一切正常,状态栏显示从设备读取的字符串。
但是当我尝试写入设备文件时 - 问题出现了。我写设备文件的函数总是报错。
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 写入一个临时文件,然后尝试将其重命名为设备文件 "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".
即使允许写入 /dev
,g_file_set_contents
也会 替换 device 文件 普通一个,不是你想要的
您需要使用较低级别的方式写入设备文件。例如,使用 fopen
+ fwrite
.
我正在为自定义设备开发一个内核模块,实际上是一个连接到 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;
}
一切正常,状态栏显示从设备读取的字符串。 但是当我尝试写入设备文件时 - 问题出现了。我写设备文件的函数总是报错。
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 写入一个临时文件,然后尝试将其重命名为设备文件 "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".
即使允许写入 /dev
,g_file_set_contents
也会 替换 device 文件 普通一个,不是你想要的
您需要使用较低级别的方式写入设备文件。例如,使用 fopen
+ fwrite
.