2 * a.lp_mp3 - VS1011B driver for Fonera
3 * Copyright (c) 2007 phrozen.org - John Crispin <john@phrozen.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19 * Feedback, Bugs... john@phrozen.org
24 #include <linux/module.h>
25 #include <linux/errno.h>
26 #include <linux/ioport.h>
27 #include <linux/init.h>
28 #include <asm/uaccess.h>
30 #include <linux/timer.h>
31 #include <linux/init.h>
32 #include <linux/genhd.h>
33 #include <linux/device.h>
35 // do we want debuging info ?
42 #define MP3_CHUNK_SIZE 4096
43 #define MP3_BUFFERING 0
45 #define MP3_BUFFER_FINISHED 2
46 #define MP3_PLAY_FINISHED 3
47 typedef struct _MP3_DATA{
48 unsigned char mp3[MP3_CHUNK_SIZE];
52 #define IOCTL_MP3_INIT 0x01
53 #define IOCTL_MP3_RESET 0x02
54 #define IOCTL_MP3_SETVOLUME 0x03
55 #define IOCTL_MP3_GETVOLUME 0x04
57 typedef struct _AUDIO_DATA{
59 unsigned int sample_rate;
60 unsigned char is_stereo;
62 #define IOCTL_MP3_GETAUDIODATA 0x05
63 #define IOCTL_MP3_CLEARBUFFER 0x06
64 #define IOCTL_MP3_PLAY 0x07
66 typedef struct _MP3_BEEP{
70 #define IOCTL_MP3_BEEP 0x08
71 #define IOCTL_MP3_END_REACHED 0x09
72 #define IOCTL_MP3_BASS 0x10
74 #define CRYSTAL12288 0x9800
75 #define CRYSTAL24576 0x0
77 #define DEV_NAME "mp3"
79 #define MAX_MP3_COUNT 1
81 typedef struct _mp3_inf{
82 unsigned char is_open;
84 static mp3_inf mp3_info[MAX_MP3_COUNT];
86 #define MP3_BUFFER_SIZE (128 * 1024)
87 unsigned char mp3_buffer[MP3_BUFFER_SIZE];
89 static unsigned long int mp3_buffer_offset_write = 0;
90 static unsigned long int mp3_buffer_offset_read = 0;
91 static unsigned char mp3_buffering_status = MP3_BUFFERING;
92 static unsigned long int mp3_data_in_buffer = 0;
93 static int mp3_thread = 0;
94 unsigned int crystal_freq;
98 static wait_queue_head_t wq;
99 static DECLARE_COMPLETION(mp3_exit);
101 static int mp3_playback_thread(void *data){
103 unsigned long timeout;
104 unsigned char empty = 0;
105 printk("started kthread\n");
107 while(mp3_buffering_status != MP3_PLAY_FINISHED){
108 if((mp3_buffering_status == MP3_PLAYING) || (mp3_buffering_status == MP3_BUFFER_FINISHED)){
109 while((VS1011_NEEDS_DATA) && (!empty)){
110 if(mp3_buffer_offset_read == MP3_BUFFER_SIZE){
111 mp3_buffer_offset_read = 0;
114 if(mp3_data_in_buffer == 0){
115 if(mp3_buffering_status == MP3_BUFFER_FINISHED){
116 printk("mp3_drv.ko : finished playing\n");
117 mp3_buffering_status = MP3_PLAY_FINISHED;
120 printk("mp3_drv.ko : buffer empty ?\n");
121 if(mp3_buffering_status != MP3_PLAY_FINISHED){
125 for(j = 0; j < 32; j++){
126 VS1011_send_SDI(mp3_buffer[mp3_buffer_offset_read + j]);
128 mp3_buffer_offset_read += 32;
129 mp3_data_in_buffer -= 32;
135 timeout = wait_event_interruptible_timeout(wq, (timeout==0), timeout);
137 complete_and_exit(&mp3_exit, 0);
140 static ssize_t module_write(struct file * file, const char * buffer, size_t count, loff_t *offset){
143 copy_from_user((char*) &mp3_data, buffer, sizeof(MP3_DATA));
145 if(mp3_data.state == MP3_BUFFER_FINISHED){
146 mp3_buffering_status = MP3_BUFFER_FINISHED;
147 DBG(printk("mp3_drv.ko : file end reached\n"));
151 if(mp3_data.state == MP3_PLAY_FINISHED){
152 mp3_buffering_status = MP3_PLAY_FINISHED;
153 mp3_data_in_buffer = 0;
154 DBG(printk("mp3_drv.ko : stop playing\n"));
158 if(mp3_data_in_buffer + MP3_CHUNK_SIZE >= MP3_BUFFER_SIZE){
159 DBG(printk("mp3_drv.ko : buffer is full? %ld\n", mp3_data_in_buffer);)
163 if(mp3_buffer_offset_write == MP3_BUFFER_SIZE){
164 mp3_buffer_offset_write = 0;
167 memcpy(&mp3_buffer[mp3_buffer_offset_write], mp3_data.mp3, MP3_CHUNK_SIZE);
168 mp3_buffer_offset_write += MP3_CHUNK_SIZE;
169 mp3_buffering_status = mp3_data.state;
170 mp3_data_in_buffer += MP3_CHUNK_SIZE;
174 static int module_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg){
175 unsigned int retval = 0;
176 AUDIO_DATA audio_data;
178 DBG(printk("mp3_drv.ko : Ioctl Called (cmd=%d)\n", cmd );)
182 VS1011_init(crystal_freq, 1);
183 VS1011_print_registers();
186 case IOCTL_MP3_RESET:
187 DBG(printk("mp3_drv.ko : doing a sw reset\n");)
188 VS1011_init(crystal_freq, 0);
189 VS1011_print_registers();
190 VS1011_send_zeros(0x20);
193 case IOCTL_MP3_SETVOLUME:
194 DBG(printk("mp3_drv.ko : setting volume to : %lu\n", arg&0xffff);)
195 VS1011_set_volume(arg);
198 case IOCTL_MP3_GETVOLUME:
199 retval = VS1011_get_volume();
200 DBG(printk("mp3_drv.ko : read volume : %d\n", retval);)
203 case IOCTL_MP3_GETAUDIODATA:
204 DBG(printk("mp3_drv.ko : read audio data\n");)
205 VS1011_get_audio_data(&audio_data);
206 copy_to_user((char*)arg, (char*)&audio_data, sizeof(AUDIO_DATA));
209 case IOCTL_MP3_CLEARBUFFER:
210 DBG(printk("mp3_drv.ko : clearing buffer\n");)
211 mp3_buffer_offset_read = 0;
212 mp3_buffer_offset_write = 0;
213 mp3_buffering_status = MP3_PLAY_FINISHED;
214 mp3_data_in_buffer = 0;
218 mp3_thread = kernel_thread(mp3_playback_thread, NULL, CLONE_KERNEL);
222 copy_from_user((char*)&mp3_beep, (char*)arg, sizeof(MP3_BEEP));
223 VS1011_sine(1,mp3_beep.freq);
224 msDelay(mp3_beep.ms);
228 case IOCTL_MP3_END_REACHED:
229 if(mp3_buffering_status == MP3_PLAY_FINISHED){
235 VS1011_set_bass(arg);
239 printk("mp3_drv.ko : unknown ioctl\n");
246 static int module_open(struct inode *inode, struct file *file){
247 unsigned int dev_minor = MINOR(inode->i_rdev);
249 printk("mp3_drv.ko : trying to access unknown minor device -> %d\n", dev_minor);
252 if(mp3_info[dev_minor].is_open) {
253 printk("mp3_drv.ko : Device with minor ID %d already in use\n", dev_minor);
256 mp3_info[dev_minor].is_open = 1;
258 mp3_buffering_status = MP3_PLAY_FINISHED;
259 printk("mp3_drv.ko : Minor %d has been opened\n", dev_minor);
263 static int module_close(struct inode * inode, struct file * file){
264 unsigned int dev_minor = MINOR(inode->i_rdev);
265 mp3_info[dev_minor].is_open = 0;
266 printk("mp3_drv.ko : Minor %d has been closed\n", dev_minor);
267 mp3_buffering_status = MP3_PLAY_FINISHED;
271 struct file_operations modulemp3_fops = {
275 release: module_close
278 static struct class *mp3_class;
280 static int __init mod_init(void){
281 printk("mp3_drv.ko : VS1011b Driver\n");
282 printk("mp3_drv.ko : Made by John '2B|!2B' Crispin (john@phrozen.org)\n");
283 printk("mp3_drv.ko : Starting ...\n");
285 if(register_chrdev(DEV_MAJOR, DEV_NAME, &modulemp3_fops)) {
286 printk( "mp3_drv.ko : Error whilst opening %s (%d)\n", DEV_NAME, DEV_MAJOR);
290 printk("mp3_drv.ko : using sysfs to create device nodes\n");
291 mp3_class = class_create(THIS_MODULE, DEV_NAME);
292 class_device_create(mp3_class, NULL,
296 mp3_info[0].is_open = 0;
297 printk("mp3_drv.ko : Device %s registered for major ID %d\n", DEV_NAME, DEV_MAJOR);
298 crystal_freq = CRYSTAL12288;
299 VS1011_init(crystal_freq, 1);
300 VS1011_print_registers();
301 printk("end of init\n");
302 init_waitqueue_head(&wq);
303 printk("wait queue started\n");
307 static void __exit mod_exit(void){
308 printk( "mp3_drv.ko : Cleanup\n" );
309 unregister_chrdev(DEV_MAJOR, DEV_NAME);
312 module_init (mod_init);
313 module_exit (mod_exit);
315 MODULE_LICENSE("GPL");
316 MODULE_AUTHOR("K. John '2B|!2B' Crispin");
317 MODULE_DESCRIPTION("vs1011 Driver for Fox Board");