/*必要なヘッダファイルをインクルードしています。*/ #include/* copy_from_user, copy_to_user */ #include #include /* inode, file, file_operations */ #include /* printk */ #include #include ... /*今回はメジャー番号を242番とします。*/ static int devmajor = 242; ... /*ユーザプロセスから書き込まれたデータを保存し、ユーザプロセスから読み込 める*/ /*様にするための内部バッファ32バイトを宣言しています。*/ #define MAXBUF 32 static unsigned char devbuf[ MAXBUF ]; static int buf_pos; ... /* * open() * 1ユーザプロセスのみがデバイスファイルの open に成功します。 * * ユーザプロセスからのopenに対応する関数です。linux/fs.h内の * struct file_operations のメンバであるopen関数ポインタの形式で * 定義する必要があります。成功時には0を、何らかのエラー終了時 * にはlinux/errno.h内の適切なエラー番号を選び、負の数値に変換して * 返却しています。 */ static int chardev_open( struct inode* inode, struct file* filp ) { printk( KERN_INFO "%s : open() called\n", msg ); spin_lock( chardev_spin_lock ); if ( access_num ) { spin_unlock( chardev_spin_lock ); return -EBUSY; } access_num ++; spin_unlock( chardev_spin_lock ); return 0; } /* * release() * 使用ユーザプロセス数をクリアします。 * *ユーザプロセスとデバイスドライバの関連付けが解放される際に *に実行されます。一般的にはユーザプロセスがcloseを実行した際 * に実行されますが、ユーザプロセスがエラー終了してしまった際 * などにも実行されることで、資源が解放されます. */ static int chardev_release( struct inode* inode, struct file* filp ) { printk( KERN_INFO "%s : close() called\n", msg ); spin_lock( chardev_spin_lock ); access_num --; spin_unlock( chardev_spin_lock ); return 0; } /* * read() * ユーザプロセスに対して内部バッファの内容を転送します。 * 転送した内容は内部バッファから消えます。 */ static ssize_t chardev_read( struct file* filp, char* buf, size_t count, loff_t* pos ) { int copy_len; int i; printk( KERN_INFO "%s : read() called\n", msg ); if ( count > buf_pos ) copy_len = buf_pos; else copy_len = count; /*bufにコピー先アドレス、devbufにコピー元アドレスが指定されています。*/ /*戻り値はコピーされていないバイト数であるため、正常に終了した場合は0*/ /*が帰ります.*/ if ( copy_to_user( buf, devbuf, copy_len ) ) { printk( KERN_INFO "%s : copy_to_user failed\n", msg ); return -EFAULT; } /*コピーした後は、コピーしたデータ長に応じて内部バッファ内の*/ /*データを先頭につめています。*/ *pos += copy_len; for ( i = copy_len; i < buf_pos; i ++ ) devbuf[ i - copy_len ] = devbuf[i]; buf_pos -= copy_len; printk( KERN_INFO "%s : buf_pos = %d\n", msg, buf_pos ); return copy_len; } /* * write() * ユーザプロセスから転送された内容を内部バッファに書き込みます。 */ static ssize_t chardev_write( struct file* filp, const char* buf, size_t count, loff_t* pos ) { int copy_len; printk( KERN_INFO "%s : write() called\n", msg ); if ( buf_pos == MAXBUF ) { printk( KERN_INFO "%s : no space left\n", msg ); return -ENOSPC; } if ( count > ( MAXBUF - buf_pos ) ) copy_len = MAXBUF - buf_pos; else copy_len = count; /*ここでは、単にbufからコピーするわけには行きませんので、 */ /*copy_from_userという関数を使います。 */ /*devbuf + buf_posにコピー先アドレス、bufにコピー元アドレスを */ /*指定します。また、copy_lenにコピーするバイト数を指定します。*/ if ( copy_from_user( devbuf + buf_pos, buf, copy_len ) ) { printk( KERN_INFO "%s : copy_from_user failed\n", msg ); return -EFAULT; } *pos += copy_len; buf_pos += copy_len; printk( KERN_INFO "%s : buf_pos = %d\n", msg, buf_pos ); return copy_len; } /*モジュール内の各関数とユーザプロセスからの操作を関連づけています。*/ /*今回は、readとwrite、open、releaseの4つを使っていますので4つ関連付け*/ /*をしています。*/ static struct file_operations chardev_fops = { owner : THIS_MODULE, read : chardev_read, write : chardev_write, open : chardev_open, release : chardev_release, }; ... ... /* End of chardev.c */
884:struct file_operations { 885- struct module *owner; 886- loff_t (*llseek) (struct file *, loff_t, int); 887- ssize_t (*read) (struct file *, char *, size_t, loff_t *); 888- ssize_t (*write) (struct file *, const char *, size_t, loff_t *); 889- int (*readdir) (struct file *, void *, filldir_t); 890- unsigned int (*poll) (struct file *, struct poll_table_struct *); 891- int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); 892- int (*mmap) (struct file *, struct vm_area_struct *); 893- int (*open) (struct inode *, struct file *); 894- int (*flush) (struct file *); 895- int (*release) (struct inode *, struct file *); 896- int (*fsync) (struct file *, struct dentry *, int datasync); 897- int (*fasync) (int, struct file *, int); 898- int (*lock) (struct file *, int, struct file_lock *); 899- ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); 900- ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); 901- ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); 902- unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); 903-};追加方法はLevel6で書きましたので省略します。
[root@pw022 j03018]% cat /proc/devices Character devices: 1 mem 2 pty 3 ttyp 4 ttyS 5 cua 7 vcs 10 misc 14 sound 128 ptm 136 pts 162 raw 180 usb 226 drm 241 newnull2 242 chardev Block devices: 2 fd 3 ide0 22 ide1となっています。
[root@pw022 ~]% echo "HELLO WORLD" > /dev/chardevとして、次にchardevを見ると、
[root@pw022 ~]% cat /dev/chardev HELLO WORLD
となります。なお、この/dev/chardevは、同時に一つのユーザプロセスしか 使えない様になっています。
最後に、Level6とLevelXは、新しく構築したLinux-2.7.27でのみ動きます。
よって、実験が終了次第元のバージョンを元に戻しましたので、新しく追加した
キャラクタデバイスは今のpw022では使えません。
今回のキャラクタデバイスは、同時アクセス可能プロセス数を1にしています。
これを複数にすると、同時にアクセスされると内部バッファの内容に不整合が生じる
と思われます。
そうならないためには、内部バッファ操作の前後でロックを取得/解放する
必要があると思われます。