dsp_microcode.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #include <linux/version.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/types.h>
  5. #include <linux/string.h>
  6. #include <linux/io.h>
  7. #include <linux/fs.h>
  8. #include <linux/slab.h>
  9. #include <linux/uaccess.h>
  10. //#include <asm/dsp/audiodsp_control.h>
  11. #include "audiodsp_control.h"
  12. #include <linux/firmware.h>
  13. #include <linux/major.h>
  14. #include <linux/device.h>
  15. #include "audiodsp_module.h"
  16. #include "dsp_control.h"
  17. #include "dsp_microcode.h"
  18. #include <linux/dma-mapping.h>
  19. static int audiodsp_microcode_insert(struct audiodsp_priv*priv,struct audiodsp_microcode *pmcode)
  20. {
  21. unsigned long flags;
  22. if(pmcode==NULL)
  23. return -1;
  24. spin_lock_irqsave(&priv->mcode_lock, flags);
  25. list_add_tail(&pmcode->list,&priv->mcode_list);
  26. priv->mcode_id++;
  27. pmcode->id=priv->mcode_id;
  28. spin_unlock_irqrestore(&priv->mcode_lock, flags);
  29. return priv->mcode_id;
  30. }
  31. struct audiodsp_microcode * audiodsp_find_supoort_mcode(struct audiodsp_priv*priv,int fmt)
  32. {
  33. struct audiodsp_microcode *pmcode=NULL;
  34. struct audiodsp_microcode *p=NULL;
  35. unsigned long flags;
  36. spin_lock_irqsave(&priv->mcode_lock, flags);
  37. list_for_each_entry(p,&priv->mcode_list,list)
  38. {
  39. if(p->fmt & fmt)
  40. {
  41. pmcode=p;
  42. break;
  43. }
  44. }
  45. spin_unlock_irqrestore(&priv->mcode_lock, flags);
  46. return pmcode;
  47. }
  48. static struct audiodsp_microcode * audiodsp_find_mcode_by_name(struct audiodsp_priv*priv,char *name)
  49. {
  50. struct audiodsp_microcode *pmcode=NULL;
  51. struct audiodsp_microcode *p=NULL;
  52. unsigned long flags;
  53. spin_lock_irqsave(&priv->mcode_lock, flags);
  54. list_for_each_entry(p,&priv->mcode_list,list)
  55. {
  56. if(memcmp(p->file_name,name,strlen(name))==0)
  57. {
  58. pmcode=p;
  59. break;
  60. }
  61. }
  62. spin_unlock_irqrestore(&priv->mcode_lock, flags);
  63. return pmcode;
  64. }
  65. int audiodsp_microcode_load(struct audiodsp_priv*priv,struct audiodsp_microcode *pmcode)
  66. {
  67. const struct firmware *firmware;
  68. int err=0;
  69. unsigned dsp_code_text_start = 0;
  70. priv->micro_dev = device_create(priv->class,
  71. NULL, MKDEV(AUDIODSP_MAJOR, 1),
  72. NULL, "audiodsp1");
  73. if(priv->micro_dev ==NULL)
  74. return -1;
  75. if((err=request_firmware(&firmware,pmcode->file_name, priv->micro_dev))<0)
  76. {
  77. DSP_PRNT("can't load the %s,err=%d\n",pmcode->file_name,err);
  78. goto error1;
  79. }
  80. if(firmware->size>priv->code_mem_size)
  81. {
  82. DSP_PRNT("not enough memory size for audiodsp code\n");
  83. err=ENOMEM;
  84. goto release;
  85. }
  86. if(priv->dsp_is_started)
  87. #ifndef AUDIODSP_RESET
  88. dsp_code_text_start = 0x800;//after dsp is running,only load from the text section of the microcode.
  89. #else
  90. dsp_code_text_start = 0;
  91. #endif /* AUDIODSP_RESET */
  92. memcpy((char *)((unsigned)priv->dsp_code_start +dsp_code_text_start), \
  93. (char*)firmware->data+dsp_code_text_start,firmware->size-dsp_code_text_start);
  94. mb();
  95. pmcode->code_size=firmware->size;
  96. DSP_PRNT("load mcode size=%d\n,load addr 0x%lx mcode name %s",firmware->size,pmcode->code_start_addr,pmcode->file_name);
  97. release:
  98. release_firmware(firmware);
  99. error1:
  100. device_destroy(priv->class, MKDEV(AUDIODSP_MAJOR, 1));
  101. return err;
  102. }
  103. int audiodsp_microcode_register(struct audiodsp_priv*priv,int fmt,char *filename)
  104. {
  105. struct audiodsp_microcode *pmcode;
  106. int len;
  107. pmcode=audiodsp_find_mcode_by_name(priv,filename);
  108. if(pmcode!=NULL)
  109. {
  110. DSP_PRNT("Have register the firmware code before=%s\n",filename);
  111. DSP_PRNT("Refresh the firmware settings now\n");
  112. pmcode->fmt=fmt;
  113. pmcode->code_start_addr=priv->dsp_code_start;
  114. len=min(64,(int)strlen(filename));
  115. memcpy(pmcode->file_name,filename,len);
  116. pmcode->file_name[len]='\0';
  117. return pmcode->id;
  118. }
  119. else
  120. {
  121. pmcode=kmalloc(sizeof(struct audiodsp_microcode ),GFP_KERNEL);
  122. if(pmcode==NULL)
  123. return -ENOMEM;
  124. pmcode->fmt=fmt;
  125. pmcode->code_start_addr=priv->dsp_code_start;
  126. len=min(64,(int)strlen(filename));
  127. memcpy(pmcode->file_name,filename,len);
  128. pmcode->file_name[len]='\0';
  129. pmcode->id=audiodsp_microcode_insert(priv,pmcode);
  130. if(pmcode->id<0)
  131. {
  132. kfree(pmcode);
  133. return -EIO;
  134. }
  135. }
  136. return 0;
  137. }
  138. int audiodsp_microcode_free(struct audiodsp_priv*priv)
  139. {
  140. unsigned long flags;
  141. struct audiodsp_microcode *pmcode;
  142. struct list_head *list,*head;
  143. local_irq_save(flags);
  144. head=&priv->mcode_list;
  145. while(!list_empty(head))
  146. {
  147. list=head->prev;
  148. pmcode=list_entry(list, struct audiodsp_microcode, list);
  149. list_del(list);
  150. kfree(pmcode);
  151. }
  152. local_irq_restore(flags);
  153. return 0;
  154. }