カスタム デバイス用のカーネル モジュールを開発しています。実際には、アドレス 0x0120 ~ 0x0123 の ISA バスに 4*8 ビットの io ポートが接続されています。このドライバーは、Alessandro Rubini と Jonathan Corbet による「スカル」に基づいています。私のOSは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 のように常に。この時点でカーネル モジュールがロードされ、そこからの読み取りは問題ありません。デバッグ後、カーネル ログに対応する「printk」メッセージが出力されないため、カーネル モジュールの「Write」関数が呼び出されないことがわかりました。必死になって、私はこのようにしようとしました:
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;
}
ステータスバーにエラーメッセージが表示されます: Error: g-file-error-quark: 2, Failed to create file '/dev/ET32010.****8X': Permission denied 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
次に、カーネルモジュールのinitスクリプトでモードを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 関数は以前と同様に「許可が拒否されました」を返しましたが、on_BnStop_clicked はカーネル モジュールの「書き込み」メソッドを呼び出し、ERR == NULL で正常に完了しました。結局、エラー報告機能は「セグメンテーション違反」(reporting ERR == NULL) でクラッシュしましたが、私はすでにこのバグを修正しました。