Guest User

Untitled

a guest
Jan 5th, 2018
61
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.02 KB | None | 0 0
  1. /*
  2. * MMM soundcard
  3. * Copyright (c) by Jon Pry <[email protected]>
  4. *
  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.
  9. *
  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.
  14. *
  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, MA 02111-1307 USA
  18. *
  19. */
  20.  
  21. #include <linux/init.h>
  22. #include <linux/err.h>
  23. #include <linux/platform_device.h>
  24. #include <linux/jiffies.h>
  25. #include <linux/slab.h>
  26. #include <linux/time.h>
  27. #include <linux/wait.h>
  28. #include <linux/hrtimer.h>
  29. #include <linux/math64.h>
  30. #include <linux/moduleparam.h>
  31. #include <linux/gpio.h>
  32. #include <sound/core.h>
  33. #include <sound/control.h>
  34. #include <sound/tlv.h>
  35. #include <sound/pcm.h>
  36. #include <sound/rawmidi.h>
  37. #include <sound/info.h>
  38. #include <sound/initval.h>
  39.  
  40. #define SND_MMM_DRIVER "snd_mmm"
  41.  
  42. struct mmm_snd {
  43. struct snd_card *card;
  44. struct snd_pcm *pcm;
  45. struct snd_pcm_substream *substream;
  46. volatile unsigned int current_ptr;
  47. volatile unsigned int running;
  48. spinlock_t lock;
  49. };
  50.  
  51. static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
  52. static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
  53.  
  54. /* hardware definition */
  55. static struct snd_pcm_hardware snd_mmm_playback_hw = {
  56. .info = (SNDRV_PCM_INFO_INTERLEAVED |
  57. SNDRV_PCM_INFO_BLOCK_TRANSFER),
  58. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  59. .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
  60. .rate_min = 44100,
  61. .rate_max = 48000,
  62. .channels_min = 2,
  63. .channels_max = 2,
  64. .buffer_bytes_max = 16384,
  65. .period_bytes_min = 8096,
  66. .period_bytes_max = 8096,
  67. .periods_min = 2,
  68. .periods_max = 2,
  69. };
  70.  
  71. /* hardware definition */
  72. static struct snd_pcm_hardware snd_mmm_capture_hw = {
  73. .info = (SNDRV_PCM_INFO_MMAP |
  74. SNDRV_PCM_INFO_INTERLEAVED |
  75. SNDRV_PCM_INFO_BLOCK_TRANSFER |
  76. SNDRV_PCM_INFO_MMAP_VALID),
  77. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  78. .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100,
  79. .rate_min = 44100,
  80. .rate_max = 48000,
  81. .channels_min = 2,
  82. .channels_max = 2,
  83. .buffer_bytes_max = 16384,
  84. .period_bytes_min = 8096,
  85. .period_bytes_max = 8096,
  86. .periods_min = 2,
  87. .periods_max = 2,
  88. };
  89.  
  90. /* open callback */
  91. static int snd_mmm_playback_open(struct snd_pcm_substream *substream)
  92. {
  93. struct mmm_snd *chip = snd_pcm_substream_chip(substream);
  94. struct snd_pcm_runtime *runtime = substream->runtime;
  95. chip->substream = substream;
  96. chip->current_ptr = 0;
  97. chip->running = 0;
  98. runtime->hw = snd_mmm_playback_hw;
  99. /* more hardware-initialization will be done here */
  100. //....
  101.  
  102. printk("%s\n",__func__);
  103. return 0;
  104. }
  105.  
  106. /* close callback */
  107. static int snd_mmm_playback_close(struct snd_pcm_substream *substream)
  108. {
  109. struct mmm_snd *chip = snd_pcm_substream_chip(substream);
  110. /* the hardware-specific codes will be here */
  111. //....
  112. printk("%s\n",__func__);
  113. chip->running = 0;
  114. chip->substream = 0;
  115.  
  116. return 0;
  117. }
  118.  
  119. /* open callback */
  120. static int snd_mmm_capture_open(struct snd_pcm_substream *substream)
  121. {
  122. struct mmm_snd *chip = snd_pcm_substream_chip(substream);
  123. struct snd_pcm_runtime *runtime = substream->runtime;
  124. int ret=0;
  125.  
  126. printk("%s\n",__func__);
  127.  
  128. runtime->hw = snd_mmm_capture_hw;
  129. /* more hardware-initialization will be done here */
  130. //....
  131.  
  132. ret = snd_pcm_hw_constraint_integer(runtime,
  133. SNDRV_PCM_HW_PARAM_PERIODS);
  134. if(ret < 0)
  135. return ret;
  136. ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
  137.  
  138. return ret;
  139. }
  140.  
  141. /* close callback */
  142. static int snd_mmm_capture_close(struct snd_pcm_substream *substream)
  143. {
  144. struct mmm_snd *chip = snd_pcm_substream_chip(substream);
  145. /* the hardware-specific codes will be here */
  146. //....
  147. printk("%s\n",__func__);
  148.  
  149. return 0;
  150. }
  151.  
  152. /* hw_params callback */
  153. static int snd_mmm_pcm_hw_params(struct snd_pcm_substream *substream,
  154. struct snd_pcm_hw_params *hw_params)
  155. {
  156. printk("%s\n",__func__);
  157. return snd_pcm_lib_malloc_pages(substream,
  158. params_buffer_bytes(hw_params));
  159. }
  160.  
  161. /* hw_free callback */
  162. static int snd_mmm_pcm_hw_free(struct snd_pcm_substream *substream)
  163. {
  164. printk("%s\n",__func__);
  165. return snd_pcm_lib_free_pages(substream);
  166. }
  167.  
  168. /* prepare callback */
  169. static int snd_mmm_pcm_prepare(struct snd_pcm_substream *substream)
  170. {
  171. struct mmm_snd *chip = snd_pcm_substream_chip(substream);
  172. struct snd_pcm_runtime *runtime = substream->runtime;
  173.  
  174. chip->current_ptr = 0;
  175.  
  176. printk("%s\n",__func__);
  177. return 0;
  178. }
  179.  
  180. /* trigger callback */
  181. static int snd_mmm_pcm_trigger(struct snd_pcm_substream *substream,
  182. int cmd)
  183. {
  184. struct mmm_snd *chip = snd_pcm_substream_chip(substream);
  185. switch (cmd) {
  186. case SNDRV_PCM_TRIGGER_START:
  187. /* do something to start the PCM engine */
  188. //....
  189. chip->running = 1;
  190. printk("%s PCM Trigger start\n", __func__);
  191. break;
  192. case SNDRV_PCM_TRIGGER_STOP:
  193. chip->running = 0;
  194. printk("%s PCM Trigger stop\n", __func__);
  195. /* do something to stop the PCM engine */
  196. //....
  197. break;
  198. default:
  199. printk("Unknown pcm trigger\n");
  200. return -EINVAL;
  201. }
  202. return 0;
  203. }
  204.  
  205. /* pointer callback */
  206. static snd_pcm_uframes_t
  207. snd_mmm_pcm_pointer(struct snd_pcm_substream *substream)
  208. {
  209. struct mmm_snd *chip = snd_pcm_substream_chip(substream);
  210. unsigned int current_ptr;
  211. printk("%s\n", __func__);
  212.  
  213. /* get the current hardware pointer */
  214. current_ptr = chip->current_ptr*1024;
  215. return current_ptr;
  216. }
  217.  
  218. /* operators */
  219. static struct snd_pcm_ops snd_mmm_playback_ops = {
  220. .open = snd_mmm_playback_open,
  221. .close = snd_mmm_playback_close,
  222. .ioctl = snd_pcm_lib_ioctl,
  223. .hw_params = snd_mmm_pcm_hw_params,
  224. .hw_free = snd_mmm_pcm_hw_free,
  225. .prepare = snd_mmm_pcm_prepare,
  226. .trigger = snd_mmm_pcm_trigger,
  227. .pointer = snd_mmm_pcm_pointer,
  228. };
  229.  
  230. /* operators */
  231. static struct snd_pcm_ops snd_mmm_capture_ops = {
  232. .open = snd_mmm_capture_open,
  233. .close = snd_mmm_capture_close,
  234. .ioctl = snd_pcm_lib_ioctl,
  235. .hw_params = snd_mmm_pcm_hw_params,
  236. .hw_free = snd_mmm_pcm_hw_free,
  237. .prepare = snd_mmm_pcm_prepare,
  238. .trigger = snd_mmm_pcm_trigger,
  239. .pointer = snd_mmm_pcm_pointer,
  240. };
  241.  
  242. /*
  243. * definitions of capture are omitted here...
  244. */
  245.  
  246. static irqreturn_t snd_mmm_interrupt(int irq, void *dev_id)
  247. {
  248. struct mmm_snd *chip = dev_id;
  249. spin_lock(&chip->lock);
  250.  
  251. if (chip->running)
  252. {
  253. chip->current_ptr=!chip->current_ptr;
  254. /* call updater, unlock before it */
  255. printk("PCM period elapsed\n");
  256. spin_unlock(&chip->lock);
  257. snd_pcm_period_elapsed(chip->substream);
  258. spin_lock(&chip->lock);
  259. /* acknowledge the interrupt if necessary */
  260. }
  261.  
  262. spin_unlock(&chip->lock);
  263. return IRQ_HANDLED;
  264. }
  265.  
  266. /* create a pcm device */
  267. static int __devinit snd_mmm_new_pcm(struct mmm_snd *chip)
  268. {
  269. struct snd_pcm *pcm;
  270. int err;
  271.  
  272. err = snd_pcm_new(chip->card, "MMM PCM", 0, 1, 1, &pcm);
  273. if (err < 0)
  274. return err;
  275. pcm->private_data = chip;
  276. spin_lock_init(&chip->lock);
  277. chip->substream = 0;
  278. strcpy(pcm->name, "MMM PCM");
  279. chip->pcm = pcm;
  280. /* set operators */
  281. snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
  282. &snd_mmm_playback_ops);
  283. snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
  284. &snd_mmm_capture_ops);
  285. /* pre-allocation of buffers */
  286. /* NOTE: this may fail */
  287. //What does it do i wonder?
  288. snd_pcm_lib_preallocate_pages_for_all(pcm,
  289. SNDRV_DMA_TYPE_CONTINUOUS,
  290. snd_dma_continuous_data(GFP_KERNEL),
  291. 0, 16*1024);
  292. return 0;
  293. }
  294.  
  295. static int __devinit snd_mmm_probe(struct platform_device *devptr)
  296. {
  297. int err;
  298. struct snd_card *card;
  299. struct mmm_snd *chip;
  300.  
  301. int dev = devptr->id;
  302.  
  303. err = snd_card_create(index[dev], id[dev], THIS_MODULE,
  304. sizeof(struct mmm_snd), &card);
  305.  
  306. if (err < 0)
  307. return err;
  308.  
  309. chip = card->private_data;
  310. chip->card = card;
  311.  
  312. err = snd_mmm_new_pcm(chip);
  313. if (err < 0)
  314. goto __nodev;
  315.  
  316. strcpy(card->driver, "MMM");
  317. strcpy(card->shortname, "MMM");
  318. strcpy(card->longname, "MMM 0");
  319.  
  320. snd_card_set_dev(card, &devptr->dev);
  321.  
  322. err = snd_card_register(card);
  323. if (err<0)
  324. {
  325. printk("Failed to register sound card\n");
  326. goto __nodev;
  327. }
  328.  
  329. platform_set_drvdata(devptr, card);
  330.  
  331. err = gpio_request(96,"FPGA_DBUF");
  332. if(err < 0)
  333. {
  334. printk("Failed to get gpio FPGA_DBUF\n");
  335. goto __nodev;
  336. }
  337. gpio_direction_input(96);
  338.  
  339.  
  340. err = request_irq(gpio_to_irq(96), snd_mmm_interrupt,
  341. IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
  342. "fpga_dbuf", chip);
  343.  
  344. if(err < 0)
  345. {
  346. printk("Failed to request irq\n");
  347. goto __nodev;
  348. }
  349. return 0;
  350.  
  351. __nodev:
  352. snd_card_free(card);
  353. return err;
  354. }
  355.  
  356. static struct platform_driver snd_mmm_driver = {
  357. .probe = snd_mmm_probe,
  358. .driver = {
  359. .name = SND_MMM_DRIVER
  360. },
  361. };
  362.  
  363. static int __init alsa_card_mmm_init(void)
  364. {
  365. int err;
  366.  
  367. err = platform_driver_register(&snd_mmm_driver);
  368. if (err < 0)
  369. return err;
  370.  
  371. struct platform_device *device;
  372. device = platform_device_register_simple(SND_MMM_DRIVER,
  373. 0, NULL, 0);
  374. return 0;
  375. }
  376.  
  377. module_init(alsa_card_mmm_init)
  378.  
  379. MODULE_AUTHOR("Jon Pry <[email protected]>");
  380. MODULE_DESCRIPTION("MMM soundcard");
  381. MODULE_LICENSE("GPL");
  382. MODULE_SUPPORTED_DEVICE("{{ALSA,MMM soundcard}}");
Add Comment
Please, Sign In to add comment