/************************************************************************************** * File: drv_mp3.h, a driver of mp3 encoder/decoder IC chip * Author: Wenxy, wen_kernel@163.com, 20080710, a.m. * Fix history: * * Note: hardware support function: * MP3 encode: 44.1KHz, 128bps. * MP3 decode: 44.1KHz, 32KHz, 48KHz, 32~448Kbps, stereo, joint stereo, mono, two-track. * **************************************************************************************/ #ifndef _DRV_MP3_H #define _DRV_MP3_H #include <stdio.h> #include <stdlib.h> #include <string.h> #include <memory.h> /* #include "../../public/pub_emmi.h" #include "../../frame/frm_hd_device.h" #include "../../kernel/kern_irq.h" */ #include "../driver_test/public/pub_emmi.h" #include "../driver_test/frame/frm_hd_device.h" #include "../driver_test/kernel/kern_irq.h" extern void kern_disable_irq(D_INT32 irq); extern void kern_enable_irq(D_INT32 irq); extern D_INT32 kern_request_irq(D_INT32 irq, D_INT32 func, void *dev_id, D_UINT32 flags); extern D_UINT8 mp3_dc_device_flag; /* mp3 decoder state */ extern D_UINT8 mp3_ec_device_flag; /* mp3 encoder state */ #define MAX_DELAY_COUNT 5000 /* maximal delay conuter */ #define MAX_BUFFER_LEN ((1024*2)*10) /* mp3 buffer length, 2KB multiples */ #define MAX_DC_BUFFER_LEN (MAX_BUFFER_LEN) /* decoder buffer length */ /****************************************************************************** * define some macroes ******************************************************************************/ /* MP3±àÂëÒÑÈ«²¿Ð޸ģ¬¼û<<¶àýÌåÈíÓ²¼þ½Ó¿Ú.doc>> */ /* MP3 encode, 128kbps, 44.1KHz, stereo track */ /* #define MP3_BIT_RATE_128 (0x1 << 0) #define MP3_BIT_RATE_64 (0x1 << 1) #define MP3_BIT_RATE_168 (0x1 << 2) #define MP3_BIT_RATE_192 (0x1 << 3) #define MP3_BIT_SAMPLE_441 (0x1 << 0) #define MP3_BIT_SAMPLE_32 (0x1 << 1) #define MP3_BIT_SAMPLE_96 (0x1 << 2) #define MP3_BIT_SAMPLE_192 (0x1 << 3) #define MP3_TRACK_EVEN (0x1 << 0) #define MP3_TRACK_LEFT (0x1 << 1) #define MP3_TRACK_RIGHT (0x1 << 2) */ /* mp3 device state */ #define MP3_EC_CLOSE 0x0 /* mp3 encoder was closed */ #define MP3_EC_INIT_ERR 0x1 /* mp3 encoder init error */ #define MP3_EC_INIT 0x2 /* mp3 encoder init OK */ #define MP3_EC_OPEN 0x3 /* mp3 encoder was opened */ #define MP3_DC_CLOSE 0x0 /* mp3 decoder was closed */ #define MP3_DC_INIT_ERR 0x1 /* mp3 decoder init error */ #define MP3_DC_INIT 0x2 /* mp3 decoder init OK */ #define MP3_DC_OPEN 0x3 /* mp3 decoder was opened */ /* error code number */ #define MP3_OK 0 /* OK */ #define MP3_ERROR 1 /* error */ #define MP3_MALLOC_ERROR 2 /* malloc memory was failed */ #define MP3_DELETE_ERROR 3 /* delete memory was failed */ #define MP3_DC_ERROR_POINTER -1 /* empty pointer */ #define MP3_DC_ERROR_SIZE -2 /* size error */ #define MP3_DC_ERROR_FORMAT -3 /* unknown mp3 format */ /****************************************************************************** * I2S bus(Inter-IC sound bus) * I2S bus chip has some registers. It is use to reciver sound data and * send PCM data to sound card. * Note: mp3 encode use I2S Reciver operation mode, * mp3 decode use I2S Trasmitter operation mode. ******************************************************************************/ #define I2S_BASE_ADDR 0x81002000 /* I2S bus base address */ /* Reciver */ #define I2S_RX_VERSION (*(volatile unsigned *)(I2S_BASE_ADDR + 0x00)) /* Version register, read only */ #define I2S_RX_CONFIG (*(volatile unsigned *)(I2S_BASE_ADDR + 0x04)) /* Configurature register */ #define I2S_RX_INIT_MASK (*(volatile unsigned *)(I2S_BASE_ADDR + 0x08)) /* Interrupt mask register */ #define I2S_RX_INIT_STAT (*(volatile unsigned *)(I2S_BASE_ADDR + 0x0c)) /* Interrupt status register */ /* Transmitter */ #define I2S_TX_VERSION (*(volatile unsigned *)(I2S_BASE_ADDR + 0x00)) /* Version register, read only */ #define I2S_TX_CONFIG (*(volatile unsigned *)(I2S_BASE_ADDR + 0x04)) /* configure register */ #define I2S_TX_INIT_MASK (*(volatile unsigned *)(I2S_BASE_ADDR + 0x08)) /* Interrupt mask register */ #define I2S_TX_INIT_STAT (*(volatile unsigned *)(I2S_BASE_ADDR + 0x0c)) /* Interrupt status register */ /****************************************************************************** * AVI module * AVI module has 14 registers ******************************************************************************/ #define AVI_BASE_ADDR 0xFFFC3300 /* AVI module base address */ #define AVI_CTRL (*(volatile unsigned *)(AVI_BASE_ADDR + 0x00)) /* AVI control register, width=6 bits */ /* * Note: AVI_CTRL register has 6 bytes(32 bits) * * AVI_CTRL[0] = 1, AVI working * AVI_CTRL[1] = 0, AVI restart, equal to 1 if AVI working * AVI_CTRL[2-5] = 0100 -- MP3 decode, 0010 -- MP3 encode * AVI_CTRL[6-31] = ?, reserved bits * */ #define AVI_BUFFER_0_ADDR (*(volatile unsigned *)(AVI_BASE_ADDR + 0x04)) #define AVI_BUFFER_0_LEN (*(volatile unsigned *)(AVI_BASE_ADDR + 0x08)) #define AVI_BUFFER_1_ADDR (*(volatile unsigned *)(AVI_BASE_ADDR + 0x0c)) #define AVI_BUFFER_1_LEN (*(volatile unsigned *)(AVI_BASE_ADDR + 0x10)) #define AVI_BUFFER_2_ADDR (*(volatile unsigned *)(AVI_BASE_ADDR + 0x14)) #define AVI_BUFFER_2_LEN (*(volatile unsigned *)(AVI_BASE_ADDR + 0x18)) #define AVI_MP3_DC_INFO (*(volatile unsigned *)(AVI_BASE_ADDR + 0x30)) /* mp3 encode frame length, read only, width=9 bits */ #define AVI_STATE (*(volatile unsigned *)(AVI_BASE_ADDR + 0x34)) /* AVI state register, width=3 bits */ /****************************************************************************** * mp3 decode * mp3 decode chip has 9 registers ******************************************************************************/ #define MP3_DC_IRQ 0x0C /* mp3 IRQ */ /* #define MP3_DC_BASE (AVI_BASE_ADDR + 0x34 +4) #define MP3_DC_CONTRL (*(volatile unsigned *)(MP3_DC_BASE + 0x0000)) #define MP3_DC_STATUS (*(volatile unsigned *)(MP3_DC_BASE + 0x0004)) #define MP3_DC_MP3_ADDR (*(volatile unsigned *)(MP3_DC_BASE + 0x0008)) #define MP3_DC_BITRATE (*(volatile unsigned *)(MP3_DC_BASE + 0x000C)) #define MP3_DC_FREQUENCY (*(volatile unsigned *)(MP3_DC_BASE + 0x0010)) #define MP3_DC_TRACK (*(volatile unsigned *)(MP3_DC_BASE + 0x0014)) #define MP3_DC_FRAME_START (*(volatile unsigned *)(MP3_DC_BASE + 0x0018)) #define MP3_DC_FRAME_END (*(volatile unsigned *)(MP3_DC_BASE + 0x001c)) #define MP3_DC_CRC (*(volatile unsigned *)(MP3_DC_BASE + 0x0020)) */ /************************************************************************************** * Function: initialization mp3 chip * In: device-- MMI platform device structure * Out: * Return: return 0 if OK, otherwise return greater than 0 **************************************************************************************/ extern D_BOOL drv_mp3_dc_init(struct d_hd_device *device); /************************************************************************************** * function: open AVI module, make sure it is working for MP3 encode * In: null * Out: null * Return: return 0 if OK! * * Warning: please free the heap memory if the program exit, * must call drv_mp3_ec_exit() * **************************************************************************************/ extern D_UINT8 drv_mp3_dc_open(void); /************************************************************************************** * Function: copy mp3 data to AVI module * In: buf--a mp3 buffer pointer, size--data length * Out: null * Return: return data length of write data, happened a error if -1 **************************************************************************************/ extern D_UINT16 drv_mp3_dc_write(const void *buf, D_UINT32 size); /************************************************************************************** * function: control mp3 decoder * In: cmd-- command, param-- unknown untill ... * Out: * Return: return 0 if OK! happened error if -1 * Note: command and param table * -------+------+-----------------------+---------------------------------+ * cmd comment param * ------------------------------------------------------------------------+ * 0 pause N/A * 1 continue decode N/A * 2 fast progress¿ì½ø ? * 3 fast forward¿ìÍË ? **************************************************************************************/ extern D_UINT8 drv_mp3_dc_ioctl(D_INT32 cmd, void *param); /* close mp3 decoder */ extern void drv_mp3_dc_close(void); /* exit */ extern void drv_mp3_dc_exit(void); /* play mp3 sound, control structure */ typedef struct MP3_DC_CONTRL_STRUCT { D_UINT32 u_second; /* FF or FW second */ D_UINT32 u_spend; /* FF 0r FW spend */ /* mp3 data buffer structure */ struct MP3_DATA_STRUCT { D_UINT32 *p; D_UINT32 u_len; }mp3_buff; }mp3_dc_ctr; /****************************************************************************** * mp3 encode * mp3 encode chip has 10 registers ******************************************************************************/ #define MP3_EC_IRQ 0x0C /* MP3±àÂëÒÑÈ«²¿Ð޸ģ¬¼û<<¶àýÌåÈíÓ²¼þ½Ó¿Ú.doc>> */ /* #define MP3_EC_BASE (AVI_BASE_ADDR + 0x34 +4) #define MP3_EC_CONTRL (*(volatile unsigned *)(MP3_EC_BASE + 0x0000)) #define MP3_EC_STATUS (*(volatile unsigned *)(MP3_EC_BASE + 0x0004)) #define MP3_EC_BITRATE (*(volatile unsigned *)(MP3_EC_BASE + 0x000C)) #define MP3_EC_FREQUENCY (*(volatile unsigned *)(MP3_EC_BASE + 0x0010)) #define MP3_EC_TRACK (*(volatile unsigned *)(MP3_EC_BASE + 0x0014)) #define MP3_EC_CRC (*(volatile unsigned *)(MP3_EC_BASE + 0x0018)) #define MP3_EC_FRAME_START (*(volatile unsigned *)(MP3_EC_BASE + 0x001C)) #define MP3_EC_FRAME_END (*(volatile unsigned *)(MP3_EC_BASE + 0x0020)) #define MP3_EC_FRAME_SIZE (*(volatile unsigned *)(MP3_EC_BASE + 0x0024)) */ /************************************************************************************** * function: open AVI module, make sure it is working for MP3 encode * In: null * Out: null * Return: return 0 if OK! * * Warning: please free the heap memory if the program exit, * must call drv_mp3_ec_exit() * **************************************************************************************/ extern D_UINT8 drv_mp3_ec_open(void); /************************************************************************************** * Function: initialization mp3 chip * In: device-- MMI platform device structure * Out: * Return: return 0 if OK, otherwise return greater than 0 **************************************************************************************/ extern D_BOOL drv_mp3_ec_init(struct d_hd_device *device); /************************************************************************************** * function: copy mp3 data from mp3 buffer to main memory * In: buf--main memory buffer pointer, size--buffer length * Out: null * Return: return read data size, error happed if -1 * Note: size muest >= MAX_BUFFER_LEN, and 2KB multiples **************************************************************************************/ extern D_UINT16 drv_mp3_ec_read(D_UINT8 *buf, D_UINT32 size); /************************************************************************************** * function: control mp3 encoder * In: cmd-- command, param-- unknown untill ... * Out: * Return: return 0 if OK! * Note: command and param table * -------+------+-----------------------+---------------------------------+ * cmd comment param * ------------------------------------------------------------------------+ * 0 pause N/A * 1 continue encode ? * 2 stop encode ? * 3 begin encode ? **************************************************************************************/ extern D_UINT8 drv_mp3_ec_ioctl(D_UINT32 cmd, void *param); /* disabled AVI module for mp3 encode */ extern void drv_mp3_ec_close(void); /* exit */ extern void drv_mp3_ec_exit(void); /************************************************************* ENCODER: For example, invoke encoder mp3 driver program. Fake code: D_BOOl stop_flag = FALSE; void main(int argc, char *argv[]) { drv_mp3_ec_init(); drv_mp3_ec_open(); // Note: // A new thread that user control MP3 recoder! // This thread change stop_flag value to TRUE // and invoke drv_mp3_ec_ioctl() for do something. // srv_dfile_create(...); while(stop_flag == TRUE) { drv_mp3_ec_read(buffer, ...); // write mp3 data(saved in buffer) to SD card // srv_dfile_write(...); // ... } drv_mp3_ec_close(); drv_mp3_ec_exit(); // ... } ***************************************************************/ /************************************************************** DECODER: For example, invoke decoder mp3 driver program. Fake code: D_BOOl stop_flag = FALSE; void main(int argc, char *argv[]) { drv_mp3_dc_init(); drv_mp3_dc_open(); // Note: // A new thread that user control MP3 play! // This thread change stop_flag value to TRUE // and invoke drv_mp3_dc_ioctl() for do something. // srv_dfile_open(...); while(stop_flag == TRUE) { // read mp3 data from a MP3 file, this file was saved in SD card // srv_dfile_read(...); drv_mp3_dc_write(buff_pointer, mp3_data_length); // ... } drv_mp3_dc_close(); drv_mp3_dc_exit(); // ... } **************************************************************/ #endif /* end of _DRV_MP3_H */ /************************************************************************************** * File: drv_ec_mp3.c, a driver of mp3 encoder IC chip. * Author: Wenxy, wen_kernel@163.com, 20080702, a.m. * * Note: Don't touch the source code untill you have see the mp3 IC chip's datasheet. * * Fix history: * **************************************************************************************/ #include "drv_mp3.h" D_UINT8 drv_mp3_ec_handler(D_UINT32 irq, void *devid, void *dd); static void config_ec_i2s_bus(); static D_UINT8 *buf = NULL; D_UINT8 mp3_ec_device_flag = 0x0; static pthread_mutex_t ec_mutex; static pthread_cond_t ec_cond; static D_UINT32 g_read_size; /* memory buffer for save produce MP3 data */ typedef struct STRUCT_MP3_BUFF { D_UINT32 *p1; /* buffer 1 pointer */ D_UINT32 u_len1; /* data length of buffer 1 */ }MP3_BUFF; static MP3_BUFF g_mp3_buff; /************************************************************************************** * Function: free some heap memory * In: p--a pointer that is a heap memory buffer first address * Out: null * Return: return 0 if OK, otherwise return 1 **************************************************************************************/ static D_UINT32 free_mp3_buff(void **p) { if(*p != NULL) { free(*p); *p = NULL; } return 0; } /************************************************************************************** * Function: malloc heap memory for save mp3 data buffer * In: buff-- mp3 data buffer, uLen-- buffer length * Out: null * Return: return 0 if OK, otherwise return 1 * Waning: please free the heap memory if the program exit **************************************************************************************/ static D_UINT32 malloc_mp3_buff(void **p, D_UINT32 uLen) { if(NULL != *p) { free(*p); *p = NULL; *p = (D_UINT8 *)malloc(uLen); if(*p == NULL) { return 1; /* malloc memory was failed */ } memset(*p, 0, uLen); } return 0; } static void delay(D_UINT32 second) { D_UINT32 i, j; for (i=0; i<second; i++) { for (j=0; j<10; j++); } } /************************************************************************************** * Function: initialization mp3 chip * In: device-- MMI platform device structure * Out: * Return: return 0 if OK, otherwise return greater than 0 **************************************************************************************/ D_BOOL drv_mp3_ec_init(struct d_hd_device *device) { if (device == NULL) { mp3_ec_device_flag = (D_UINT8)MP3_EC_INIT_ERR; return FALSE; } /* malloc mp3 data buffer */ if(0 != malloc_mp3_buff(g_mp3_buff.p1, MAX_BUFFER_LEN)) { goto INIT_ERROR; } g_mp3_buff.u_len1 = MAX_BUFFER_LEN; g_read_size &= 0x0; /* configure I2S bus */ config_ec_i2s_bus(); AVI_BUFFER_0_ADDR = g_mp3_buff.p1; AVI_BUFFER_0_LEN = g_mp3_buff.u_len1; AVI_BUFFER_2_LEN = 0x0; /* mp3 data length when interrupt happed, MP3 encoder write AVI_BUFFER_0_ADDR */ delay(MAX_DELAY_COUNT); kern_disable_irq(MP3_EC_IRQ); if ( kern_request_irq(MP3_EC_IRQ, drv_mp3_ec_handler, NULL, 0)) { goto INIT_ERROR; } kern_enable_irq(MP3_EC_IRQ); AVI_CTRL = 0x0; /* reset AVI module */ AVI_CTRL = 0xb; /* enable AVI module, low 6 bits=00 1011 */ delay(MAX_DELAY_COUNT); mp3_ec_device_flag = MP3_EC_INIT; return TRUE; /* error process */ INIT_ERROR: free_mp3_buff(g_mp3_buff.p1); mp3_ec_device_flag = MP3_EC_INIT_ERR; return FALSE; } /* exit */ void drv_mp3_ec_exit(void) { free_mp3_buff(g_mp3_buff.p1); pthread_cond_destroy(&ec_cond); pthread_mutex_destroy(&ec_mutex); } /************************************************************************************** * Function: copy mp3 data from buffer to main memory * In: buf--MP3 buffer pointer, size--buffer length * Out: null * Return: return read data size, error happed if -1. * WARNING: * AVI mp3 module send a interrupt when make 2KB mp3 data. Maybe CPU cannot feel the * MP3 interrupt(e.g. cpu disabled mp3 interrupt), so we depend on two AVI regester: * AVI_ADDR2_LEN and AVI_STATE. * AVI_ADDR2_LEN: record all of mp3 length (<= max mp3 buffer length). * AVI_STATE: you have to clear when finished read mp3 data (:-), yes, I do it). * **************************************************************************************/ D_UINT16 drv_mp3_ec_read(D_UINT8 *buf, D_UINT32 size) { D_UINT32 current_size; current_size &= 0; /* buffer one is full */ if(NULL == buf || size < MAX_BUFFER_LEN) { return -1; } /* suspend and wait for condition untill received the condition */ pthread_mutex_lock(&ec_mutex); pthread_cond_wait(&ec_cond, &ec_mutex); pthread_mutex_unlock(&ec_mutex); if(AVI_STATE & 0x1) { current_size = AVI_BUFFER_2_LEN - g_read_size; /* we muest copy mp3 data length */ memcpy(buf, AVI_BUFFER_0_ADDR + g_read_size, current_size); } if((AVI_BUFFER_2_LEN % MAX_BUFFER_LEN) == 0) /* cycle mp3 buffer */ { g_read_size &= 0x0; } else { g_read_size = (D_UINT32)(AVI_BUFFER_2_LEN % MAX_BUFFER_LEN); /* for next reading */ } AVI_STATE &= 0xfffffffe; /* low 1 bit = ???0 */ return (D_UINT16)current_size; } /************************************************************************************** * function: IRQ process function * In: irq--IRQ number, devid--device pointer, dd--unknown * Out: * Return: return 0 if OK! **************************************************************************************/ D_UINT8 drv_mp3_ec_handler(D_UINT32 irq, void *devid, void *dd) { #ifdef EMMI_SPARC kern_disable_irq(MP3_EC_IRQ); #endif /* buffer was full of MP3 data */ if(AVI_STATE & 0x1) { /* set resume signal */ /* resume read(), copy the mp3 data from mp3 buffer to main memory */ pthread_mutex_lock(&ec_mutex); pthread_cond_signal(&ec_cond); pthread_mutex_unlock(&ec_mutex); } #ifdef EMMI_SPARC kern_enable_irq(MP3_EC_IRQ); #endif return 0; } /************************************************************************************** * function: control mp3 encoder * In: cmd-- command, param-- unknown untill ... * Out: * Return: return 0 if OK! * Note: command and param table * -------+------+-----------------------+---------------------------------+ * cmd comment param * ------------------------------------------------------------------------+ * 0 pause N/A * 1 continue encode ? * 2 stop encode ? * 3 begin encode ? **************************************************************************************/ D_UINT8 drv_mp3_ec_ioctl(D_UINT32 cmd, void *param) { switch(cmd) { case 0: AVI_CTRL &= 0xfffffffc; /* pause encode and disabled IRQ */ break; case 1: AVI_CTRL |= 0x00000003; /* continue encode and usable IRQ */ break; case 2: AVI_CTRL &= 0xfffffffc; /* stop encode and disabled IRQ */ if(0 != free_mp3_buff(g_mp3_buff.p1)) /* failed when free mp3 data heap memory */ { return (D_UINT8)1; } break; case 3: AVI_CTRL |= 0x3; /* begin encode and useable IRQ */ if(0 != free_mp3_buff(g_mp3_buff.p1)) /* failed when malloc mp3 data buffer */ { return (D_UINT8)2; } break; default: ; } return (D_UINT8)0; } /* wenxy: edit mark */ /* configure I2S bus */ static void config_ec_i2s_bus() { /* encode MP3 */ I2S_RX_VERSION = 0x2; I2S_RX_CONFIG = 0x00100200; I2S_RX_INIT_MASK = 0x3; I2S_RX_INIT_STAT = 0x00100203; } /************************************************************************************** * function: open AVI module, make sure it is working for MP3 encode * In: null * Out: null * Return: return 0 if OK! * * Warning: please free the heap memory if the program exit, * must call drv_mp3_ec_exit() * **************************************************************************************/ D_UINT8 drv_mp3_ec_open(void) { if( mp3_ec_device_flag != MP3_EC_INIT) { return -1; } mp3_ec_device_flag = (D_UINT8)MP3_EC_OPEN; /* MP3 chip initializtion OK */ /* set suspend signal */ pthread_cond_init(&ec_cond, NULL); pthread_mutex_init(&ec_mutex, NULL); return (D_UINT8)MP3_OK; } /* disabled AVI module for mp3 encode */ void drv_mp3_ec_close(void) { AVI_CTRL &= 0xfffffff8; /* disabled MP3 encoder chip */ #ifdef EMMI_SPARC kern_disable_irq(MP3_EC_IRQ); /* close IRQ number */ #endif delay(MAX_DELAY_COUNT); mp3_ec_device_flag = (D_UINT8)MP3_EC_CLOSE; /* MP3 chip was closed */ } d_device mp3_en_device = {0xf, 0, drv_mp3_ec_init, drv_mp3_ec_exit,/ drv_mp3_ec_read, NULL, drv_mp3_ec_ioctl,/ drv_mp3_ec_open, drv_mp3_ec_close, 0}; /************************************************************************************** * File: drv_dc_mp3.c, a driver of mp3 ecoder IC chip. * Author: Wenxy, wen_kernel@163.com, 20080711, a.m. * * Note: Don't touch the source code untill you have see the mp3 IC chip's datasheet. * * Fix history: * **************************************************************************************/ #include "drv_mp3.h" D_UINT8 drv_mp3_dc_handler(D_INT32 irq, void *devid, void *dd); static void config_dc_i2s_bus(); mp3_dc_ctr g_dc_ctr; static pthread_mutex_t dc_mutex; static pthread_cond_t dc_cond; static D_INT32 g_dc_info; /* mp3 decoder information */ static D_UINT8 g_begin_flag; /* write mp3 data to mp3 device, first and second */ /* use low 9 bits: g_dc_info[0,1] -- track, 00=stereo, 01=joint Stereo, 10=two track, 11=Mono. g_dc_info[2,5] -- bit rate, 0000 ~ 1111. reference <<¶àýÌåÈí¼þÓ²½Ó¿Ú.doc>>. g_dc_info[6,7] -- sampling frequency, 00=44.1KHz, 01=32KHz, 10=48KHz, 11=reserved. g_dc_info[8] -- 1=file error, data format is unknow(not mp3 format). g_dc_info[9, 31] -- reserved. */ /* define data buffer pointer */ typedef struct STRUCT_BYTE_BUFF { D_UINT8 *p1; D_UINT8 *p2; D_UINT32 u_len1; /* mp3 data length of p1 buffer */ D_UINT32 u_len2; /* mp3 data length of p2 buffer */ }struct_byte_buff; static struct_byte_buff g_mp3_buff; D_UINT8 mp3_dc_device_flag = 0; /* control structure object */ /* configure I2S bus */ static void config_dc_i2s_bus() { /* decode MP3 */ I2S_TX_VERSION = 0x00000002; /* 16-bit, (12.288/1.536)/2 - 2 = 2(0x2) */ I2S_TX_CONFIG = 0x00100200; /* 16-bit, (12.288/1.536)/2 - 2 = 2(0x2) */ I2S_TX_INIT_MASK = 0x00000003; I2S_TX_INIT_STAT = 0x00100203; } static void delay(D_UINT32 second) { D_UINT32 i, j; for (i=0; i<second; i++) { for (j=0; j<10; j++); } } /************************************************************************************** * Function: get some heap memory * In: uLen-- buffer length * Out: p--a buffer pointer * Return: return 0 if OK, otherwise return 1 or 2 * * Warning: please free the heap memory if the program exit * **************************************************************************************/ static D_UINT32 malloc_mp3_buff(void **p, unsigned int uLen) { if(NULL != *p) { free(*p); *p = NULL; *p = (D_UINT8 *)malloc(uLen); if(*p == NULL) { return 1; /* malloc memory was failed */ } memset(*p, 0, uLen); } return 0; } /************************************************************************************** * Function: free some heap memory * In: p--a pointer that is a heap memory buffer first address * Out: null * Return: return 0 if OK, otherwise return 1 **************************************************************************************/ static D_UINT32 free_mp3_buff(void **p) { if(*p != NULL) { free(*p); *p = NULL; } return 0; } /************************************************************************************** * Function: initialization mp3 chip * In: device-- MMI platform device structure * Out: * Return: return 0 if OK, otherwise return greater than 0 **************************************************************************************/ D_BOOL drv_mp3_dc_init(struct d_hd_device *device) { if (device == NULL) { mp3_dc_device_flag = MP3_DC_INIT_ERR; return FALSE; } /* malloc mp3 data buffer */ if(0 != malloc_mp3_buff(&g_mp3_buff.p1, MAX_DC_BUFFER_LEN) || / 0 != malloc_mp3_buff(&g_mp3_buff.p2, MAX_DC_BUFFER_LEN) ) { goto INIT_ERROR; } g_mp3_buff.u_len1 = 0; g_mp3_buff.u_len2 = 0; g_begin_flag = 0; /* write mp3 data to mp3 device, first and second */ /* configure I2S bus */ config_dc_i2s_bus(); delay(MAX_DELAY_COUNT); /* config AVI module */ AVI_BUFFER_0_ADDR = g_mp3_buff.p1; AVI_BUFFER_2_ADDR = g_mp3_buff.p2; AVI_BUFFER_0_LEN = g_mp3_buff.u_len1; AVI_BUFFER_2_LEN = g_mp3_buff.u_len2; kern_disable_irq(MP3_DC_IRQ); if ( kern_request_irq(MP3_DC_IRQ, drv_mp3_dc_handler, NULL, 0)) { goto INIT_ERROR; } kern_enable_irq(MP3_DC_IRQ); AVI_CTRL = 0x10; /* reset AVI module, low 6 bits: 01 0000 */ AVI_CTRL = 0x13; /* enabled AVI module, low 6 bits: 01 0011 */ delay(MAX_DELAY_COUNT); mp3_ec_device_flag = MP3_DC_INIT; return TRUE; /* error process */ INIT_ERROR: free_mp3_buff(g_mp3_buff.p1); free_mp3_buff(g_mp3_buff.p2); mp3_ec_device_flag = (D_UINT8)MP3_EC_INIT_ERR; return FALSE; } /************************************************************************************** * function: open AVI module, make sure it is working for MP3 encode * In: null * Out: null * Return: return 0 if OK! * * Warning: please free the heap memory if the program exit, * must call drv_mp3_dc_exit() * **************************************************************************************/ D_UINT8 drv_mp3_dc_open(void) { if( mp3_dc_device_flag != MP3_DC_INIT) { return -1; } mp3_dc_device_flag = (D_UINT8)MP3_DC_OPEN; /* MP3 chip initializtion OK */ /* set suspend signal */ pthread_cond_init(&dc_cond, NULL); pthread_mutex_init(&dc_mutex, NULL); return 0; } /************************************************************************************** * function: IRQ process function * In: irq--IRQ number, devid--device pointer, dd--unknown * Out: * Return: return 0 if OK! **************************************************************************************/ D_UINT8 drv_mp3_dc_handler(D_INT32 irq, void *devid, void *dd) { #ifdef EMMI_SPARC kern_disable_irq(MP3_DC_IRQ); #endif g_dc_info = AVI_MP3_DC_INFO; /* save the decoder state */ /* check AVI mp3 decoder state, data is not mp3 format ? */ if(AVI_MP3_DC_INFO &0x100) /* low 9 bits: 0 ???? ???? */ { /* set resume signal */ /* resume write(), error */ pthread_mutex_lock(&dc_mutex); pthread_cond_signal(&dc_cond); pthread_mutex_unlock(&dc_mutex); } else if(AVI_STATE & 0x3) /* AVI_BUFFER_0_ADDR or AVI_BUFFER_1_ADDR is empty */ { pthread_mutex_lock(&dc_mutex); pthread_cond_signal(&dc_cond); pthread_mutex_unlock(&dc_mutex); } #ifdef EMMI_SPARC kern_enable_irq(MP3_DC_IRQ); #endif return 0; } /************************************************************************************** * Function: copy mp3 data to AVI module * In: buf--pointer of a mp3 data buffer, size--data length * Out: null * Return: return data length of write data, happened a error if -1 **************************************************************************************/ D_UINT16 drv_mp3_dc_write(const void *buf, D_UINT32 size) { if(NULL == buf ) { return MP3_DC_ERROR_POINTER; } if(size > MAX_BUFFER_LEN || size <= 0) { return MP3_DC_ERROR_SIZE ; } /* suspend and wait for condition untill received the condition */ if(g_begin_flag > 2) { pthread_mutex_lock(&dc_mutex); pthread_cond_wait(&dc_cond, &dc_mutex); pthread_mutex_unlock(&dc_mutex); } else { g_begin_flag++; /* not more than 2 */ } if(g_dc_info & 0x100) /* data isn't mp3 format */ { return MP3_DC_ERROR_FORMAT; } /* AVI_BUFFER_0_ADDR is empty */ if(AVI_STATE & 0x1) { memcpy(AVI_BUFFER_0_ADDR, buf, size); AVI_BUFFER_0_LEN = size; AVI_STATE = 0x0; } else if(AVI_STATE & 0x2) /* AVI_BUFFER_1_ADDR is empty */ { memcpy(AVI_BUFFER_1_ADDR, buf, size); AVI_BUFFER_2_LEN = size; AVI_STATE = 0x0; } return size; } /************************************************************************************** * function: control mp3 decoder * In: cmd-- command, param-- unknown untill ... * Out: * Return: return 0 if OK! happened error if -1 * Note: command and param table * -------+------+-----------------------+---------------------------------+ * cmd comment param * ------------------------------------------------------------------------+ * 0 pause N/A * 1 continue decode N/A * 2 fast progress¿ì½ø ? * 3 fast forward¿ìÍË ? **************************************************************************************/ D_UINT8 drv_mp3_dc_ioctl(D_INT32 cmd, void *param) { mp3_dc_ctr *p = (mp3_dc_ctr *)param; D_UINT32 u_second = 0; switch(cmd) { case 0: AVI_CTRL &= 0xfffffffc; /* pause decode and disabled IRQ */ break; case 1: AVI_CTRL |= 0x3; /* continue decode and usable IRQ */ break; case 2: u_second = p->u_second * p->u_spend; /* Positive, > 0 */ drv_mp3_dc_write(NULL, 0); /* stop decode and disabled IRQ */ break; case 3: u_second = p->u_second * p->u_spend; /* negative, < 0 */ drv_mp3_dc_write(NULL, 0); /* begin decode and useable IRQ */ break; default: ; } return (D_UINT8)0; } /* close mp3 decoder */ void drv_mp3_dc_close(void) { AVI_CTRL &= 0x0; /* disabled MP3 encoder chip */ delay(MAX_DELAY_COUNT); kern_disable_irq(MP3_DC_IRQ); /* close IRQ number */ mp3_dc_device_flag = (D_UINT8)MP3_DC_CLOSE; /* MP3 chip was closed */ g_begin_flag = 0; } /* exit */ void drv_mp3_dc_exit(void) { /* free audio data buff*/ if(0 != free_mp3_buff(&g_mp3_buff.p1) || 0 != free_mp3_buff(&g_mp3_buff.p2)) { ; } } d_device mp3_dc_device = {0xf,0,drv_mp3_dc_init, drv_mp3_dc_exit,/ NULL, drv_mp3_dc_write, drv_mp3_dc_ioctl,/ drv_mp3_dc_open, drv_mp3_dc_close, 0};