/* * Implement the hello, world character device driver. * Sad, but true. * Create the device with: * * mknod /dev/hw c 42 0 * * - Jon. Tombs Dec '93 * * TODO: * o- Ioctl to change the return string? * o- Better error treatment. * o- Support of minor numbers. * * Bjorn Ekwall added ugly typecast to avoid the dreaded "__moddi3" message... */ /* Kernel includes */ #include #include #include #include #include #include #include #include /* the magic return string */ static char hw_reply[] = "Hello World\n"; /* nice and high, but it is tunable: insmod drv_hello major=your_selection */ static int major = 42; /* * The driver. */ /* * Read requests on the hello world device. * The magic string is copied byte by byte to user space. * Who cares about speed? */ static int hw_read(struct inode * node,struct file * file,char * buf,int count) { int left; int hw_pos = ((int)file->f_pos) % (sizeof(hw_reply) - 1); /* ^^^^^ Sorry (bj0rn faked this, but it works for f_pos < 2^32) */ for (left = count; left > 0; left--) { put_fs_byte(hw_reply[hw_pos++],buf); buf++; if (hw_pos == (sizeof(hw_reply) - 1)) hw_pos = 0; } file->f_pos+=count; return count; } /* * support seeks on the device */ static int hw_lseek(struct inode * inode, struct file * file, off_t offset, int orig) { switch (orig) { case 0: file->f_pos = offset; return file->f_pos; case 1: file->f_pos += offset; return file->f_pos; default: /* how does the device have an end? */ return -EINVAL; } } /* * Our special open code. * MOD_INC_USE_COUNT make sure that the driver memory is not freed * while the device is in use. */ static int hw_open( struct inode* ino, struct file* filep) { MOD_INC_USE_COUNT; return 0; } /* * Now decrement the use count. */ static void hw_close( struct inode* ino, struct file* filep) { MOD_DEC_USE_COUNT; } static struct file_operations hw_fops = { hw_lseek, hw_read, NULL, NULL, /* hw_readdir */ NULL, /* hw_select */ NULL, /* hw_ioctl */ NULL, hw_open, hw_close, NULL /* fsync */ }; /* * And now the modules code and kernel interface. */ #ifdef __cplusplus extern "C" { #endif extern int printk(const char* fmt, ...); int init_module( void) { printk( "drv_hello.c: init_module called\n"); if (register_chrdev(major, "hw", &hw_fops)) { printk("register_chrdev failed: goodbye world :-(\n"); return -EIO; } else printk("Hello, world\n"); return 0; } void cleanup_module(void) { printk("drv_hello.c: cleanup_module called\n"); if (unregister_chrdev(major, "hw") != 0) printk("cleanup_module failed\n"); else printk("cleanup_module succeeded\n"); } #ifdef __cplusplus } #endif