#if defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS) #include #define MODVERSIONS #endif #include #include #include #include int init_module(void); void cleanup_module(void); static int virtual_device_open(struct inode *, struct file *); static int virtual_device_close(struct inode *, struct file *); static ssize_t virtual_device_read(struct file *, char *, size_t, loff_t *); static ssize_t virtual_device_write(struct file *, const char *, size_t, loff_t *); #define SUCCESS 0 #define DEVICE_NAME "virtual_device" /* Device name as it appears in /proc/devices */ #define BUF_LEN 80 /* Max length of the message from the device */ /* Global variables are declared as static, so are global within the file. */ static int Major; /* Major number assigned to our device driver */ static int Device_Open = 0; /* Is device open? Used to prevent multiple access to the device */ static char msg[BUF_LEN]; /* The msg the device will give when asked */ static char device_path[80]; /* path of the device special file in /dev */ static char *msg_Ptr; static int times=0; /** * Old way of declaring driver operations * * static struct file_operations virtual_device_operations ={ * NULL, // lseek * virtual_device_read, // read * virtual_device_write, // write * NULL, // readdir * NULL, // poll * NULL, // ioctl * NULL, // mmap * virtual_device_open, // open * NULL, // flush * virtual_device_close, // release * NULL, // sync * NULL, // async * NULL, // check media change * NULL, // revalidate * NULL, // lock * }; * **/ /** * * New way of declaring driver operatins * **/ static struct file_operations virtual_device_operations = { .read = virtual_device_read, .write = virtual_device_write, .open = virtual_device_open, .release = virtual_device_close }; /** * * Called when the module is installed using "insmod" * **/ int init_module(void){ int ret; char major_num[10]; static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; strcpy(device_path,"/dev/"); strcat(device_path,DEVICE_NAME); /* Register the device */ Major = register_chrdev(0, DEVICE_NAME, &virtual_device_operations); sprintf(major_num,"%d",Major); char *argv[] = {"/bin/mknod",device_path, "c", major_num, "0", NULL }; if (Major < 0){ printk ("Registering device [%s] failed with %d\n", DEVICE_NAME,Major); return Major; }else{ ret=call_usermodehelper("/bin/mknod", argv, envp); if (ret<0) { printk(KERN_ERR "failed to exec MKNOD\n"); } printk("Success registering device [%s]\n", DEVICE_NAME); } return 0; } /** * * Called when the module is un-installed using "rmmod" * **/ void cleanup_module(void){ int ret; static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; static char *argv[] = {"/bin/rm","-f", device_path, NULL }; ret=call_usermodehelper("/bin/rm", argv, envp); if (ret<0) { printk(KERN_ERR "failed to exec RMDIR\n"); } /* Unregister the device */ ret = unregister_chrdev(Major, DEVICE_NAME); if (ret < 0) printk("Error in unregistering device [%s] : %d\n", ret,DEVICE_NAME); else printk("Successfully unregistered device [%s]\n", DEVICE_NAME); } /** * * Called when the Device is open * **/ static int virtual_device_open(struct inode *inode, struct file *file){ if (Device_Open) return -EBUSY; Device_Open++; /* Device is now open */ MOD_INC_USE_COUNT; return SUCCESS; } /** * * Called when the Device is closed * **/ static int virtual_device_close(struct inode *inode, struct file *file) { Device_Open --; /* We're now ready for our next caller */ /* Decrement the usage count, or else once you opened the file, you'll never get get rid of the module. */ MOD_DEC_USE_COUNT; return 0; } /** * * Called when a process, which already opened the dev file, attempts to read from it. * **/ static ssize_t virtual_device_read(struct file *filp, char *buffer, /* The buffer to fill with data */ size_t length, /* The length of the buffer */ loff_t *offset) /* Our offset in the file */ { static int counter=0; /* Number of bytes actually written to the buffer */ int bytes_read = 0; sprintf(msg,"Device [%s] says hello %dth time!\n", DEVICE_NAME,counter++); msg_Ptr = msg; /* Actually put the data into the buffer */ while (length && *msg_Ptr) { /* The buffer is in the user data segment, not the kernel segment; * assignment won't work. We have to use put_user which copies data from * the kernel data segment to the user data segment. */ put_user(*(msg_Ptr++), buffer++); length--; bytes_read++; } /* Most read functions return the number of bytes put into the buffer */ return bytes_read; } /** * * Called when a process writes to write into the device * **/ static ssize_t virtual_device_write(struct file *filp, const char *buff, size_t len, loff_t *off) { printk ("Device [%s] Dont support this operation !!\n",DEVICE_NAME); return -EINVAL; }