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>
34 #include <asm-mips/mach-atheros/reset.h>
36 // do we want debuging info ?
43 #define MP3_CHUNK_SIZE 4096
44 #define MP3_BUFFERING 0
46 #define MP3_BUFFER_FINISHED 2
47 #define MP3_PLAY_FINISHED 3
48 typedef struct _MP3_DATA
{
49 unsigned char mp3
[MP3_CHUNK_SIZE
];
53 #define IOCTL_MP3_INIT 0x01
54 #define IOCTL_MP3_RESET 0x02
55 #define IOCTL_MP3_SETVOLUME 0x03
56 #define IOCTL_MP3_GETVOLUME 0x04
58 typedef struct _AUDIO_DATA
{
60 unsigned int sample_rate
;
61 unsigned char is_stereo
;
63 #define IOCTL_MP3_GETAUDIODATA 0x05
64 #define IOCTL_MP3_CLEARBUFFER 0x06
65 #define IOCTL_MP3_PLAY 0x07
67 typedef struct _MP3_BEEP
{
71 #define IOCTL_MP3_BEEP 0x08
72 #define IOCTL_MP3_END_REACHED 0x09
73 #define IOCTL_MP3_BASS 0x10
75 #define CRYSTAL12288 0x9800
76 #define CRYSTAL24576 0x0
78 #define DEV_NAME "mp3"
80 #define MAX_MP3_COUNT 1
82 typedef struct _mp3_inf
{
83 unsigned char is_open
;
85 static mp3_inf mp3_info
[MAX_MP3_COUNT
];
87 #define MP3_BUFFER_SIZE (128 * 1024)
88 unsigned char mp3_buffer
[MP3_BUFFER_SIZE
];
90 static unsigned long int mp3_buffer_offset_write
= 0;
91 static unsigned long int mp3_buffer_offset_read
= 0;
92 static unsigned char mp3_buffering_status
= MP3_BUFFERING
;
93 static unsigned long int mp3_data_in_buffer
= 0;
94 static int mp3_thread
= 0;
95 unsigned int crystal_freq
;
99 static wait_queue_head_t wq
;
100 static DECLARE_COMPLETION(mp3_exit
);
102 static int mp3_playback_thread(void *data
){
104 unsigned long timeout
;
105 unsigned char empty
= 0;
106 printk("started kthread\n");
108 while(mp3_buffering_status
!= MP3_PLAY_FINISHED
){
109 if((mp3_buffering_status
== MP3_PLAYING
) || (mp3_buffering_status
== MP3_BUFFER_FINISHED
)){
110 while((VS1011_NEEDS_DATA
) && (!empty
)){
111 if(mp3_buffer_offset_read
== MP3_BUFFER_SIZE
){
112 mp3_buffer_offset_read
= 0;
115 if(mp3_data_in_buffer
== 0){
116 if(mp3_buffering_status
== MP3_BUFFER_FINISHED
){
117 printk("mp3_drv.ko : finished playing\n");
118 mp3_buffering_status
= MP3_PLAY_FINISHED
;
121 printk("mp3_drv.ko : buffer empty ?\n");
122 if(mp3_buffering_status
!= MP3_PLAY_FINISHED
){
126 for(j
= 0; j
< 32; j
++){
127 VS1011_send_SDI(mp3_buffer
[mp3_buffer_offset_read
+ j
]);
129 mp3_buffer_offset_read
+= 32;
130 mp3_data_in_buffer
-= 32;
136 timeout
= wait_event_interruptible_timeout(wq
, (timeout
==0), timeout
);
138 complete_and_exit(&mp3_exit
, 0);
141 static ssize_t
module_write(struct file
* file
, const char * buffer
, size_t count
, loff_t
*offset
){
144 copy_from_user((char*) &mp3_data
, buffer
, sizeof(MP3_DATA
));
146 if(mp3_data
.state
== MP3_BUFFER_FINISHED
){
147 mp3_buffering_status
= MP3_BUFFER_FINISHED
;
148 DBG(printk("mp3_drv.ko : file end reached\n"));
152 if(mp3_data
.state
== MP3_PLAY_FINISHED
){
153 mp3_buffering_status
= MP3_PLAY_FINISHED
;
154 mp3_data_in_buffer
= 0;
155 DBG(printk("mp3_drv.ko : stop playing\n"));
159 if(mp3_data_in_buffer
+ MP3_CHUNK_SIZE
>= MP3_BUFFER_SIZE
){
160 DBG(printk("mp3_drv.ko : buffer is full? %ld\n", mp3_data_in_buffer
);)
164 if(mp3_buffer_offset_write
== MP3_BUFFER_SIZE
){
165 mp3_buffer_offset_write
= 0;
168 memcpy(&mp3_buffer
[mp3_buffer_offset_write
], mp3_data
.mp3
, MP3_CHUNK_SIZE
);
169 mp3_buffer_offset_write
+= MP3_CHUNK_SIZE
;
170 mp3_buffering_status
= mp3_data
.state
;
171 mp3_data_in_buffer
+= MP3_CHUNK_SIZE
;
175 static int module_ioctl(struct inode
* inode
, struct file
* file
, unsigned int cmd
, unsigned long arg
){
176 unsigned int retval
= 0;
177 AUDIO_DATA audio_data
;
179 DBG(printk("mp3_drv.ko : Ioctl Called (cmd=%d)\n", cmd
);)
183 VS1011_init(crystal_freq
, 1);
184 VS1011_print_registers();
187 case IOCTL_MP3_RESET
:
188 DBG(printk("mp3_drv.ko : doing a sw reset\n");)
189 VS1011_init(crystal_freq
, 0);
190 VS1011_print_registers();
191 VS1011_send_zeros(0x20);
194 case IOCTL_MP3_SETVOLUME
:
195 DBG(printk("mp3_drv.ko : setting volume to : %lu\n", arg
&0xffff);)
196 VS1011_set_volume(arg
);
199 case IOCTL_MP3_GETVOLUME
:
200 retval
= VS1011_get_volume();
201 DBG(printk("mp3_drv.ko : read volume : %d\n", retval
);)
204 case IOCTL_MP3_GETAUDIODATA
:
205 DBG(printk("mp3_drv.ko : read audio data\n");)
206 VS1011_get_audio_data(&audio_data
);
207 copy_to_user((char*)arg
, (char*)&audio_data
, sizeof(AUDIO_DATA
));
210 case IOCTL_MP3_CLEARBUFFER
:
211 DBG(printk("mp3_drv.ko : clearing buffer\n");)
212 mp3_buffer_offset_read
= 0;
213 mp3_buffer_offset_write
= 0;
214 mp3_buffering_status
= MP3_PLAY_FINISHED
;
215 mp3_data_in_buffer
= 0;
219 mp3_thread
= kernel_thread(mp3_playback_thread
, NULL
, CLONE_KERNEL
);
223 copy_from_user((char*)&mp3_beep
, (char*)arg
, sizeof(MP3_BEEP
));
224 VS1011_sine(1,mp3_beep
.freq
);
225 msDelay(mp3_beep
.ms
);
229 case IOCTL_MP3_END_REACHED
:
230 if(mp3_buffering_status
== MP3_PLAY_FINISHED
){
236 VS1011_set_bass(arg
);
240 printk("mp3_drv.ko : unknown ioctl\n");
247 static int module_open(struct inode
*inode
, struct file
*file
){
248 unsigned int dev_minor
= MINOR(inode
->i_rdev
);
250 printk("mp3_drv.ko : trying to access unknown minor device -> %d\n", dev_minor
);
253 if(mp3_info
[dev_minor
].is_open
) {
254 printk("mp3_drv.ko : Device with minor ID %d already in use\n", dev_minor
);
257 mp3_info
[dev_minor
].is_open
= 1;
259 mp3_buffering_status
= MP3_PLAY_FINISHED
;
260 printk("mp3_drv.ko : Minor %d has been opened\n", dev_minor
);
264 static int module_close(struct inode
* inode
, struct file
* file
){
265 unsigned int dev_minor
= MINOR(inode
->i_rdev
);
266 mp3_info
[dev_minor
].is_open
= 0;
267 printk("mp3_drv.ko : Minor %d has been closed\n", dev_minor
);
268 mp3_buffering_status
= MP3_PLAY_FINISHED
;
272 struct file_operations modulemp3_fops
= {
276 release
: module_close
279 static struct class *mp3_class
;
281 static int __init
mod_init(void){
282 printk("mp3_drv.ko : VS1011b Driver\n");
283 printk("mp3_drv.ko : Made by John '2B|!2B' Crispin (john@phrozen.org)\n");
284 printk("mp3_drv.ko : Starting ...\n");
286 printk("disabling atheros reset button irq\n");
288 ar531x_disable_reset_button();
290 if(register_chrdev(DEV_MAJOR
, DEV_NAME
, &modulemp3_fops
)) {
291 printk( "mp3_drv.ko : Error whilst opening %s (%d)\n", DEV_NAME
, DEV_MAJOR
);
295 printk("mp3_drv.ko : using sysfs to create device nodes\n");
296 mp3_class
= class_create(THIS_MODULE
, DEV_NAME
);
297 class_device_create(mp3_class
, NULL
,
301 mp3_info
[0].is_open
= 0;
302 printk("mp3_drv.ko : Device %s registered for major ID %d\n", DEV_NAME
, DEV_MAJOR
);
303 crystal_freq
= CRYSTAL12288
;
304 VS1011_init(crystal_freq
, 1);
305 VS1011_print_registers();
306 printk("end of init\n");
307 init_waitqueue_head(&wq
);
308 printk("wait queue started\n");
312 static void __exit
mod_exit(void){
313 printk( "mp3_drv.ko : Cleanup\n" );
314 unregister_chrdev(DEV_MAJOR
, DEV_NAME
);
317 module_init (mod_init
);
318 module_exit (mod_exit
);
320 MODULE_LICENSE("GPL");
321 MODULE_AUTHOR("K. John '2B|!2B' Crispin");
322 MODULE_DESCRIPTION("vs1011 Driver for Fox Board");