#include #include #include #include #include #include #include #include #include static char *name= "parsp"; static int major=203; //200 to 210 are free. Feel free to change it! static int loop = 4000; //Adjust this value to change speed of playback static long data_buffer, data_ptr,canplay,buffer_length; void sync(void); static ssize_t parsp_read(struct file *file, char *buf,size_t count,loff_t *ppos); static ssize_t parsp_write(struct file *file, char *buf,size_t count,loff_t *ppos); static int parsp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); static int parsp_open(struct inode *inode, struct file *file); static int parsp_close(struct inode *inode, struct file *file); struct file_operations parsp_fops = { NULL, read: parsp_read, write: parsp_write, NULL, NULL, ioctl: parsp_ioctl, NULL, open: parsp_open, release:parsp_close, }; static ssize_t parsp_read(struct file *file,char *buf,size_t count,loff_t *ppos) { printk("Speaker read\n"); return -EINVAL; } static ssize_t parsp_write(struct file *file,char *buf,size_t count, loff_t *ppos) { static int b,v,i; if(count<0) return -EINVAL; if(!count) { sync(); return 0; } while(canplay){ sync(); } if(!canplay) { count= (count <44100 ? count : 44100); if(copy_from_user((void *)data_buffer,buf,count)) return -EFAULT; canplay =1; /*********************The core of the code *********************/ for(v=0;vf_flags |= O_NONBLOCK; return 0; break; case SNDCTL_DSP_GETCAPS: return 0; break; case SOUND_PCM_WRITE_RATE: return put_user(44100, (int *)arg); break; case SOUND_PCM_READ_RATE: return -EINVAL; break; case SOUND_PCM_WRITE_CHANNELS: return put_user(0, (int *)arg); break; case SOUND_PCM_READ_CHANNELS: return put_user(2, (int *)arg); break; case SOUND_PCM_READ_BITS: return put_user(8, (int *)arg); break; case SNDCTL_DSP_SETDUPLEX: return -EINVAL; break; case SNDCTL_DSP_PROFILE: return -EINVAL; break; case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; val = (data_buffer ==data_ptr) ? 1 : 0; return put_user(5, (int *)arg); //changes break; case SNDCTL_DSP_GETIPTR: return -EINVAL; break; case SNDCTL_DSP_GETBLKSIZE: return put_user(44100 , (int *)arg); break; default: return val; } return put_user(val, (int *)arg); } static int parsp_open(struct inode *inode,struct file *file) { outb(0,0x378); //To make the port virgin printk("The parallel port speaker opened\n"); return 0; } static int parsp_close(struct inode *inode, struct file *file) { outb(0,0x378); //Cleans up the whole mess printk("The parallel port speaker closed\n"); sync(); return 0; } int init_module(void) { major=register_chrdev(major,name,&parsp_fops); if(major == 0) printk("The module successfully initialized \n"); else printk("Try with another major number\n"); data_buffer= (long) kmalloc(44100, GFP_KERNEL); //allocates mem canplay=0; return 0; } void sync(void) { canplay=0; data_ptr=data_buffer; buffer_length=0; } void cleanup_module(void) { printk("The module was successfully removed from kernel\n"); kfree((void *)data_buffer); unregister_chrdev(major,name); }