0013-bcm2708-alsa-sound-driver.patch 75 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735
  1. From 40fe0b17b886f30b316614830eedf0cfc755bbbd Mon Sep 17 00:00:00 2001
  2. From: popcornmix <popcornmix@gmail.com>
  3. Date: Mon, 26 Mar 2012 22:15:50 +0100
  4. Subject: [PATCH 013/114] bcm2708: alsa sound driver
  5. Signed-off-by: popcornmix <popcornmix@gmail.com>
  6. alsa: add mmap support and some cleanups to bcm2835 ALSA driver
  7. snd-bcm2835: Add support for spdif/hdmi passthrough
  8. This adds a dedicated subdevice which can be used for passthrough of non-audio
  9. formats (ie encoded a52) through the hdmi audio link. In addition to this
  10. driver extension an appropriate card config is required to make alsa-lib
  11. support the AES parameters for this device.
  12. snd-bcm2708: Add mutex, improve logging
  13. Fix for ALSA driver crash
  14. Avoids an issue when closing and opening vchiq where a message can arrive before service handle has been written
  15. alsa: reduce severity of expected warning message
  16. snd-bcm2708: Fix dmesg spam for non-error case
  17. ---
  18. arch/arm/configs/bcmrpi_defconfig | 20 +
  19. arch/arm/mach-bcm2708/bcm2708.c | 54 ++
  20. .../interface/vchiq_arm/vchiq_kern_lib.c | 7 +-
  21. .../vc04_services/interface/vchiq_arm/vchiq_shim.c | 12 +-
  22. sound/arm/Kconfig | 7 +
  23. sound/arm/Makefile | 5 +
  24. sound/arm/bcm2835-ctl.c | 323 ++++++++
  25. sound/arm/bcm2835-pcm.c | 552 +++++++++++++
  26. sound/arm/bcm2835-vchiq.c | 902 +++++++++++++++++++++
  27. sound/arm/bcm2835.c | 420 ++++++++++
  28. sound/arm/bcm2835.h | 167 ++++
  29. sound/arm/vc_vchi_audioserv_defs.h | 116 +++
  30. 12 files changed, 2578 insertions(+), 7 deletions(-)
  31. create mode 100755 sound/arm/bcm2835-ctl.c
  32. create mode 100755 sound/arm/bcm2835-pcm.c
  33. create mode 100755 sound/arm/bcm2835-vchiq.c
  34. create mode 100755 sound/arm/bcm2835.c
  35. create mode 100755 sound/arm/bcm2835.h
  36. create mode 100644 sound/arm/vc_vchi_audioserv_defs.h
  37. --- a/arch/arm/configs/bcmrpi_defconfig
  38. +++ b/arch/arm/configs/bcmrpi_defconfig
  39. @@ -202,6 +202,26 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
  40. CONFIG_LOGO=y
  41. # CONFIG_LOGO_LINUX_MONO is not set
  42. # CONFIG_LOGO_LINUX_VGA16 is not set
  43. +CONFIG_SOUND=y
  44. +CONFIG_SND=m
  45. +CONFIG_SND_SEQUENCER=m
  46. +CONFIG_SND_SEQ_DUMMY=m
  47. +CONFIG_SND_MIXER_OSS=m
  48. +CONFIG_SND_PCM_OSS=m
  49. +CONFIG_SND_SEQUENCER_OSS=y
  50. +CONFIG_SND_HRTIMER=m
  51. +CONFIG_SND_DUMMY=m
  52. +CONFIG_SND_ALOOP=m
  53. +CONFIG_SND_VIRMIDI=m
  54. +CONFIG_SND_MTPAV=m
  55. +CONFIG_SND_SERIAL_U16550=m
  56. +CONFIG_SND_MPU401=m
  57. +CONFIG_SND_BCM2835=m
  58. +CONFIG_SND_USB_AUDIO=m
  59. +CONFIG_SND_USB_UA101=m
  60. +CONFIG_SND_USB_CAIAQ=m
  61. +CONFIG_SND_USB_6FIRE=m
  62. +CONFIG_SOUND_PRIME=m
  63. CONFIG_HID_A4TECH=m
  64. CONFIG_HID_ACRUX=m
  65. CONFIG_HID_APPLE=m
  66. --- a/arch/arm/mach-bcm2708/bcm2708.c
  67. +++ b/arch/arm/mach-bcm2708/bcm2708.c
  68. @@ -403,6 +403,58 @@ struct platform_device bcm2708_powerman_
  69. .coherent_dma_mask = 0xffffffffUL},
  70. };
  71. +
  72. +static struct platform_device bcm2708_alsa_devices[] = {
  73. + [0] = {
  74. + .name = "bcm2835_AUD0",
  75. + .id = 0, /* first audio device */
  76. + .resource = 0,
  77. + .num_resources = 0,
  78. + },
  79. + [1] = {
  80. + .name = "bcm2835_AUD1",
  81. + .id = 1, /* second audio device */
  82. + .resource = 0,
  83. + .num_resources = 0,
  84. + },
  85. + [2] = {
  86. + .name = "bcm2835_AUD2",
  87. + .id = 2, /* third audio device */
  88. + .resource = 0,
  89. + .num_resources = 0,
  90. + },
  91. + [3] = {
  92. + .name = "bcm2835_AUD3",
  93. + .id = 3, /* forth audio device */
  94. + .resource = 0,
  95. + .num_resources = 0,
  96. + },
  97. + [4] = {
  98. + .name = "bcm2835_AUD4",
  99. + .id = 4, /* fifth audio device */
  100. + .resource = 0,
  101. + .num_resources = 0,
  102. + },
  103. + [5] = {
  104. + .name = "bcm2835_AUD5",
  105. + .id = 5, /* sixth audio device */
  106. + .resource = 0,
  107. + .num_resources = 0,
  108. + },
  109. + [6] = {
  110. + .name = "bcm2835_AUD6",
  111. + .id = 6, /* seventh audio device */
  112. + .resource = 0,
  113. + .num_resources = 0,
  114. + },
  115. + [7] = {
  116. + .name = "bcm2835_AUD7",
  117. + .id = 7, /* eighth audio device */
  118. + .resource = 0,
  119. + .num_resources = 0,
  120. + },
  121. +};
  122. +
  123. int __init bcm_register_device(struct platform_device *pdev)
  124. {
  125. int ret;
  126. @@ -508,6 +560,8 @@ void __init bcm2708_init(void)
  127. bcm_register_device(&bcm2708_powerman_device);
  128. bcm2708_init_led();
  129. + for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
  130. + bcm_register_device(&bcm2708_alsa_devices[i]);
  131. for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
  132. struct amba_device *d = amba_devs[i];
  133. --- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
  134. +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
  135. @@ -288,11 +288,12 @@ VCHIQ_STATUS_T vchiq_open_service(
  136. NULL);
  137. if (service) {
  138. + *phandle = service->handle;
  139. status = vchiq_open_service_internal(service, current->pid);
  140. - if (status == VCHIQ_SUCCESS)
  141. - *phandle = service->handle;
  142. - else
  143. + if (status != VCHIQ_SUCCESS) {
  144. vchiq_remove_service(service->handle);
  145. + *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
  146. + }
  147. }
  148. failed:
  149. --- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
  150. +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
  151. @@ -634,6 +634,9 @@ int32_t vchi_service_open(VCHI_INSTANCE_
  152. {
  153. VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
  154. SHIM_SERVICE_T *service = service_alloc(instance, setup);
  155. +
  156. + *handle = (VCHI_SERVICE_HANDLE_T)service;
  157. +
  158. if (service) {
  159. VCHIQ_SERVICE_PARAMS_T params;
  160. VCHIQ_STATUS_T status;
  161. @@ -650,11 +653,10 @@ int32_t vchi_service_open(VCHI_INSTANCE_
  162. if (status != VCHIQ_SUCCESS) {
  163. service_free(service);
  164. service = NULL;
  165. + *handle = NULL;
  166. }
  167. }
  168. - *handle = (VCHI_SERVICE_HANDLE_T)service;
  169. -
  170. return (service != NULL) ? 0 : -1;
  171. }
  172. EXPORT_SYMBOL(vchi_service_open);
  173. @@ -665,6 +667,9 @@ int32_t vchi_service_create(VCHI_INSTANC
  174. {
  175. VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
  176. SHIM_SERVICE_T *service = service_alloc(instance, setup);
  177. +
  178. + *handle = (VCHI_SERVICE_HANDLE_T)service;
  179. +
  180. if (service) {
  181. VCHIQ_SERVICE_PARAMS_T params;
  182. VCHIQ_STATUS_T status;
  183. @@ -680,11 +685,10 @@ int32_t vchi_service_create(VCHI_INSTANC
  184. if (status != VCHIQ_SUCCESS) {
  185. service_free(service);
  186. service = NULL;
  187. + *handle = NULL;
  188. }
  189. }
  190. - *handle = (VCHI_SERVICE_HANDLE_T)service;
  191. -
  192. return (service != NULL) ? 0 : -1;
  193. }
  194. EXPORT_SYMBOL(vchi_service_create);
  195. --- a/sound/arm/Kconfig
  196. +++ b/sound/arm/Kconfig
  197. @@ -40,5 +40,12 @@ config SND_PXA2XX_AC97
  198. Say Y or M if you want to support any AC97 codec attached to
  199. the PXA2xx AC97 interface.
  200. +config SND_BCM2835
  201. + tristate "BCM2835 ALSA driver"
  202. + depends on ARCH_BCM2708 && BCM2708_VCHIQ && SND
  203. + select SND_PCM
  204. + help
  205. + Say Y or M if you want to support BCM2835 Alsa pcm card driver
  206. +
  207. endif # SND_ARM
  208. --- a/sound/arm/Makefile
  209. +++ b/sound/arm/Makefile
  210. @@ -14,3 +14,8 @@ snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_A
  211. obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
  212. snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
  213. +
  214. +obj-$(CONFIG_SND_BCM2835) += snd-bcm2835.o
  215. +snd-bcm2835-objs := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o
  216. +
  217. +ccflags-y += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000
  218. --- /dev/null
  219. +++ b/sound/arm/bcm2835-ctl.c
  220. @@ -0,0 +1,323 @@
  221. +/*****************************************************************************
  222. +* Copyright 2011 Broadcom Corporation. All rights reserved.
  223. +*
  224. +* Unless you and Broadcom execute a separate written software license
  225. +* agreement governing use of this software, this software is licensed to you
  226. +* under the terms of the GNU General Public License version 2, available at
  227. +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
  228. +*
  229. +* Notwithstanding the above, under no circumstances may you combine this
  230. +* software in any way with any other Broadcom software provided under a
  231. +* license other than the GPL, without Broadcom's express prior written
  232. +* consent.
  233. +*****************************************************************************/
  234. +
  235. +#include <linux/platform_device.h>
  236. +#include <linux/init.h>
  237. +#include <linux/io.h>
  238. +#include <linux/jiffies.h>
  239. +#include <linux/slab.h>
  240. +#include <linux/time.h>
  241. +#include <linux/wait.h>
  242. +#include <linux/delay.h>
  243. +#include <linux/moduleparam.h>
  244. +#include <linux/sched.h>
  245. +
  246. +#include <sound/core.h>
  247. +#include <sound/control.h>
  248. +#include <sound/pcm.h>
  249. +#include <sound/pcm_params.h>
  250. +#include <sound/rawmidi.h>
  251. +#include <sound/initval.h>
  252. +#include <sound/tlv.h>
  253. +#include <sound/asoundef.h>
  254. +
  255. +#include "bcm2835.h"
  256. +
  257. +/* volume maximum and minimum in terms of 0.01dB */
  258. +#define CTRL_VOL_MAX 400
  259. +#define CTRL_VOL_MIN -10239 /* originally -10240 */
  260. +
  261. +
  262. +static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
  263. + struct snd_ctl_elem_info *uinfo)
  264. +{
  265. + audio_info(" ... IN\n");
  266. + if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
  267. + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  268. + uinfo->count = 1;
  269. + uinfo->value.integer.min = CTRL_VOL_MIN;
  270. + uinfo->value.integer.max = CTRL_VOL_MAX; /* 2303 */
  271. + } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
  272. + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
  273. + uinfo->count = 1;
  274. + uinfo->value.integer.min = 0;
  275. + uinfo->value.integer.max = 1;
  276. + } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
  277. + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  278. + uinfo->count = 1;
  279. + uinfo->value.integer.min = 0;
  280. + uinfo->value.integer.max = AUDIO_DEST_MAX-1;
  281. + }
  282. + audio_info(" ... OUT\n");
  283. + return 0;
  284. +}
  285. +
  286. +/* toggles mute on or off depending on the value of nmute, and returns
  287. + * 1 if the mute value was changed, otherwise 0
  288. + */
  289. +static int toggle_mute(struct bcm2835_chip *chip, int nmute)
  290. +{
  291. + /* if settings are ok, just return 0 */
  292. + if(chip->mute == nmute)
  293. + return 0;
  294. +
  295. + /* if the sound is muted then we need to unmute */
  296. + if(chip->mute == CTRL_VOL_MUTE)
  297. + {
  298. + chip->volume = chip->old_volume; /* copy the old volume back */
  299. + audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
  300. + }
  301. + else /* otherwise we mute */
  302. + {
  303. + chip->old_volume = chip->volume;
  304. + chip->volume = 26214; /* set volume to minimum level AKA mute */
  305. + audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
  306. + }
  307. +
  308. + chip->mute = nmute;
  309. + return 1;
  310. +}
  311. +
  312. +static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
  313. + struct snd_ctl_elem_value *ucontrol)
  314. +{
  315. + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
  316. +
  317. + BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
  318. +
  319. + if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
  320. + ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
  321. + else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
  322. + ucontrol->value.integer.value[0] = chip->mute;
  323. + else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
  324. + ucontrol->value.integer.value[0] = chip->dest;
  325. +
  326. + return 0;
  327. +}
  328. +
  329. +static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
  330. + struct snd_ctl_elem_value *ucontrol)
  331. +{
  332. + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
  333. + int changed = 0;
  334. +
  335. + if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
  336. + audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
  337. + if (chip->mute == CTRL_VOL_MUTE) {
  338. + /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
  339. + return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
  340. + }
  341. + if (changed
  342. + || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
  343. +
  344. + chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
  345. + changed = 1;
  346. + }
  347. +
  348. + } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
  349. + /* Now implemented */
  350. + audio_info(" Mute attempted\n");
  351. + changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
  352. +
  353. + } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
  354. + if (ucontrol->value.integer.value[0] != chip->dest) {
  355. + chip->dest = ucontrol->value.integer.value[0];
  356. + changed = 1;
  357. + }
  358. + }
  359. +
  360. + if (changed) {
  361. + if (bcm2835_audio_set_ctls(chip))
  362. + printk(KERN_ERR "Failed to set ALSA controls..\n");
  363. + }
  364. +
  365. + return changed;
  366. +}
  367. +
  368. +static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
  369. +
  370. +static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
  371. + {
  372. + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  373. + .name = "PCM Playback Volume",
  374. + .index = 0,
  375. + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
  376. + .private_value = PCM_PLAYBACK_VOLUME,
  377. + .info = snd_bcm2835_ctl_info,
  378. + .get = snd_bcm2835_ctl_get,
  379. + .put = snd_bcm2835_ctl_put,
  380. + .count = 1,
  381. + .tlv = {.p = snd_bcm2835_db_scale}
  382. + },
  383. + {
  384. + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  385. + .name = "PCM Playback Switch",
  386. + .index = 0,
  387. + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
  388. + .private_value = PCM_PLAYBACK_MUTE,
  389. + .info = snd_bcm2835_ctl_info,
  390. + .get = snd_bcm2835_ctl_get,
  391. + .put = snd_bcm2835_ctl_put,
  392. + .count = 1,
  393. + },
  394. + {
  395. + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  396. + .name = "PCM Playback Route",
  397. + .index = 0,
  398. + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
  399. + .private_value = PCM_PLAYBACK_DEVICE,
  400. + .info = snd_bcm2835_ctl_info,
  401. + .get = snd_bcm2835_ctl_get,
  402. + .put = snd_bcm2835_ctl_put,
  403. + .count = 1,
  404. + },
  405. +};
  406. +
  407. +static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol,
  408. + struct snd_ctl_elem_info *uinfo)
  409. +{
  410. + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
  411. + uinfo->count = 1;
  412. + return 0;
  413. +}
  414. +
  415. +static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
  416. + struct snd_ctl_elem_value *ucontrol)
  417. +{
  418. + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
  419. + int i;
  420. +
  421. + for (i = 0; i < 4; i++)
  422. + ucontrol->value.iec958.status[i] =
  423. + (chip->spdif_status >> (i * 8)) && 0xff;
  424. +
  425. + return 0;
  426. +}
  427. +
  428. +static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
  429. + struct snd_ctl_elem_value *ucontrol)
  430. +{
  431. + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
  432. + unsigned int val = 0;
  433. + int i, change;
  434. +
  435. + for (i = 0; i < 4; i++)
  436. + val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
  437. +
  438. + change = val != chip->spdif_status;
  439. + chip->spdif_status = val;
  440. +
  441. + return change;
  442. +}
  443. +
  444. +static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol,
  445. + struct snd_ctl_elem_info *uinfo)
  446. +{
  447. + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
  448. + uinfo->count = 1;
  449. + return 0;
  450. +}
  451. +
  452. +static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
  453. + struct snd_ctl_elem_value *ucontrol)
  454. +{
  455. + /* bcm2835 supports only consumer mode and sets all other format flags
  456. + * automatically. So the only thing left is signalling non-audio
  457. + * content */
  458. + ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO;
  459. + return 0;
  460. +}
  461. +
  462. +static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol,
  463. + struct snd_ctl_elem_info *uinfo)
  464. +{
  465. + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
  466. + uinfo->count = 1;
  467. + return 0;
  468. +}
  469. +
  470. +static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol,
  471. + struct snd_ctl_elem_value *ucontrol)
  472. +{
  473. + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
  474. + int i;
  475. +
  476. + for (i = 0; i < 4; i++)
  477. + ucontrol->value.iec958.status[i] =
  478. + (chip->spdif_status >> (i * 8)) & 0xff;
  479. + return 0;
  480. +}
  481. +
  482. +static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol,
  483. + struct snd_ctl_elem_value *ucontrol)
  484. +{
  485. + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
  486. + unsigned int val = 0;
  487. + int i, change;
  488. +
  489. + for (i = 0; i < 4; i++)
  490. + val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
  491. + change = val != chip->spdif_status;
  492. + chip->spdif_status = val;
  493. +
  494. + return change;
  495. +}
  496. +
  497. +static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
  498. + {
  499. + .iface = SNDRV_CTL_ELEM_IFACE_PCM,
  500. + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
  501. + .info = snd_bcm2835_spdif_default_info,
  502. + .get = snd_bcm2835_spdif_default_get,
  503. + .put = snd_bcm2835_spdif_default_put
  504. + },
  505. + {
  506. + .access = SNDRV_CTL_ELEM_ACCESS_READ,
  507. + .iface = SNDRV_CTL_ELEM_IFACE_PCM,
  508. + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
  509. + .info = snd_bcm2835_spdif_mask_info,
  510. + .get = snd_bcm2835_spdif_mask_get,
  511. + },
  512. + {
  513. + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
  514. + SNDRV_CTL_ELEM_ACCESS_INACTIVE,
  515. + .iface = SNDRV_CTL_ELEM_IFACE_PCM,
  516. + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
  517. + .info = snd_bcm2835_spdif_stream_info,
  518. + .get = snd_bcm2835_spdif_stream_get,
  519. + .put = snd_bcm2835_spdif_stream_put,
  520. + },
  521. +};
  522. +
  523. +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
  524. +{
  525. + int err;
  526. + unsigned int idx;
  527. +
  528. + strcpy(chip->card->mixername, "Broadcom Mixer");
  529. + for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
  530. + err =
  531. + snd_ctl_add(chip->card,
  532. + snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
  533. + if (err < 0)
  534. + return err;
  535. + }
  536. + for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) {
  537. + err = snd_ctl_add(chip->card,
  538. + snd_ctl_new1(&snd_bcm2835_spdif[idx], chip));
  539. + if (err < 0)
  540. + return err;
  541. + }
  542. + return 0;
  543. +}
  544. --- /dev/null
  545. +++ b/sound/arm/bcm2835-pcm.c
  546. @@ -0,0 +1,552 @@
  547. +/*****************************************************************************
  548. +* Copyright 2011 Broadcom Corporation. All rights reserved.
  549. +*
  550. +* Unless you and Broadcom execute a separate written software license
  551. +* agreement governing use of this software, this software is licensed to you
  552. +* under the terms of the GNU General Public License version 2, available at
  553. +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
  554. +*
  555. +* Notwithstanding the above, under no circumstances may you combine this
  556. +* software in any way with any other Broadcom software provided under a
  557. +* license other than the GPL, without Broadcom's express prior written
  558. +* consent.
  559. +*****************************************************************************/
  560. +
  561. +#include <linux/interrupt.h>
  562. +#include <linux/slab.h>
  563. +
  564. +#include <sound/asoundef.h>
  565. +
  566. +#include "bcm2835.h"
  567. +
  568. +/* hardware definition */
  569. +static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
  570. + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
  571. + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
  572. + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
  573. + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
  574. + .rate_min = 8000,
  575. + .rate_max = 48000,
  576. + .channels_min = 1,
  577. + .channels_max = 2,
  578. + .buffer_bytes_max = 128 * 1024,
  579. + .period_bytes_min = 1 * 1024,
  580. + .period_bytes_max = 128 * 1024,
  581. + .periods_min = 1,
  582. + .periods_max = 128,
  583. +};
  584. +
  585. +static struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
  586. + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
  587. + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
  588. + .formats = SNDRV_PCM_FMTBIT_S16_LE,
  589. + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
  590. + SNDRV_PCM_RATE_48000,
  591. + .rate_min = 44100,
  592. + .rate_max = 48000,
  593. + .channels_min = 2,
  594. + .channels_max = 2,
  595. + .buffer_bytes_max = 128 * 1024,
  596. + .period_bytes_min = 1 * 1024,
  597. + .period_bytes_max = 128 * 1024,
  598. + .periods_min = 1,
  599. + .periods_max = 128,
  600. +};
  601. +
  602. +static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
  603. +{
  604. + audio_info("Freeing up alsa stream here ..\n");
  605. + if (runtime->private_data)
  606. + kfree(runtime->private_data);
  607. + runtime->private_data = NULL;
  608. +}
  609. +
  610. +static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id)
  611. +{
  612. + bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) dev_id;
  613. + uint32_t consumed = 0;
  614. + int new_period = 0;
  615. +
  616. + audio_info(" .. IN\n");
  617. +
  618. + audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
  619. + alsa_stream ? alsa_stream->substream : 0);
  620. +
  621. + if (alsa_stream->open)
  622. + consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
  623. +
  624. + /* We get called only if playback was triggered, So, the number of buffers we retrieve in
  625. + * each iteration are the buffers that have been played out already
  626. + */
  627. +
  628. + if (alsa_stream->period_size) {
  629. + if ((alsa_stream->pos / alsa_stream->period_size) !=
  630. + ((alsa_stream->pos + consumed) / alsa_stream->period_size))
  631. + new_period = 1;
  632. + }
  633. + audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
  634. + alsa_stream->pos,
  635. + consumed,
  636. + alsa_stream->buffer_size,
  637. + (int)(alsa_stream->period_size*alsa_stream->substream->runtime->periods),
  638. + frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr),
  639. + new_period);
  640. + if (alsa_stream->buffer_size) {
  641. + alsa_stream->pos += consumed &~ (1<<30);
  642. + alsa_stream->pos %= alsa_stream->buffer_size;
  643. + }
  644. +
  645. + if (alsa_stream->substream) {
  646. + if (new_period)
  647. + snd_pcm_period_elapsed(alsa_stream->substream);
  648. + } else {
  649. + audio_warning(" unexpected NULL substream\n");
  650. + }
  651. + audio_info(" .. OUT\n");
  652. +
  653. + return IRQ_HANDLED;
  654. +}
  655. +
  656. +/* open callback */
  657. +static int snd_bcm2835_playback_open_generic(
  658. + struct snd_pcm_substream *substream, int spdif)
  659. +{
  660. + bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
  661. + struct snd_pcm_runtime *runtime = substream->runtime;
  662. + bcm2835_alsa_stream_t *alsa_stream;
  663. + int idx;
  664. + int err;
  665. +
  666. + audio_info(" .. IN (%d)\n", substream->number);
  667. +
  668. + if(mutex_lock_interruptible(&chip->audio_mutex))
  669. + {
  670. + audio_error("Interrupted whilst waiting for lock\n");
  671. + return -EINTR;
  672. + }
  673. + audio_info("Alsa open (%d)\n", substream->number);
  674. + idx = substream->number;
  675. +
  676. + if (spdif && chip->opened != 0)
  677. + return -EBUSY;
  678. + else if (!spdif && (chip->opened & (1 << idx)))
  679. + return -EBUSY;
  680. +
  681. + if (idx > MAX_SUBSTREAMS) {
  682. + audio_error
  683. + ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
  684. + idx, MAX_SUBSTREAMS);
  685. + err = -ENODEV;
  686. + goto out;
  687. + }
  688. +
  689. + /* Check if we are ready */
  690. + if (!(chip->avail_substreams & (1 << idx))) {
  691. + /* We are not ready yet */
  692. + audio_error("substream(%d) device is not ready yet\n", idx);
  693. + err = -EAGAIN;
  694. + goto out;
  695. + }
  696. +
  697. + alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL);
  698. + if (alsa_stream == NULL) {
  699. + err = -ENOMEM;
  700. + goto out;
  701. + }
  702. +
  703. + /* Initialise alsa_stream */
  704. + alsa_stream->chip = chip;
  705. + alsa_stream->substream = substream;
  706. + alsa_stream->idx = idx;
  707. +
  708. + sema_init(&alsa_stream->buffers_update_sem, 0);
  709. + sema_init(&alsa_stream->control_sem, 0);
  710. + spin_lock_init(&alsa_stream->lock);
  711. +
  712. + /* Enabled in start trigger, called on each "fifo irq" after that */
  713. + alsa_stream->enable_fifo_irq = 0;
  714. + alsa_stream->fifo_irq_handler = bcm2835_playback_fifo_irq;
  715. +
  716. + err = bcm2835_audio_open(alsa_stream);
  717. + if (err != 0) {
  718. + kfree(alsa_stream);
  719. + return err;
  720. + }
  721. + runtime->private_data = alsa_stream;
  722. + runtime->private_free = snd_bcm2835_playback_free;
  723. + if (spdif) {
  724. + runtime->hw = snd_bcm2835_playback_spdif_hw;
  725. + } else {
  726. + /* clear spdif status, as we are not in spdif mode */
  727. + chip->spdif_status = 0;
  728. + runtime->hw = snd_bcm2835_playback_hw;
  729. + }
  730. + /* minimum 16 bytes alignment (for vchiq bulk transfers) */
  731. + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
  732. + 16);
  733. +
  734. + chip->alsa_stream[idx] = alsa_stream;
  735. +
  736. + chip->opened |= (1 << idx);
  737. + alsa_stream->open = 1;
  738. + alsa_stream->draining = 1;
  739. +
  740. +out:
  741. + mutex_unlock(&chip->audio_mutex);
  742. +
  743. + audio_info(" .. OUT =%d\n", err);
  744. +
  745. + return err;
  746. +}
  747. +
  748. +static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
  749. +{
  750. + return snd_bcm2835_playback_open_generic(substream, 0);
  751. +}
  752. +
  753. +static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream)
  754. +{
  755. + return snd_bcm2835_playback_open_generic(substream, 1);
  756. +}
  757. +
  758. +/* close callback */
  759. +static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
  760. +{
  761. + /* the hardware-specific codes will be here */
  762. +
  763. + bcm2835_chip_t *chip;
  764. + struct snd_pcm_runtime *runtime;
  765. + bcm2835_alsa_stream_t *alsa_stream;
  766. +
  767. + audio_info(" .. IN\n");
  768. +
  769. + chip = snd_pcm_substream_chip(substream);
  770. + if(mutex_lock_interruptible(&chip->audio_mutex))
  771. + {
  772. + audio_error("Interrupted whilst waiting for lock\n");
  773. + return -EINTR;
  774. + }
  775. + runtime = substream->runtime;
  776. + alsa_stream = runtime->private_data;
  777. +
  778. + audio_info("Alsa close\n");
  779. +
  780. + /*
  781. + * Call stop if it's still running. This happens when app
  782. + * is force killed and we don't get a stop trigger.
  783. + */
  784. + if (alsa_stream->running) {
  785. + int err;
  786. + err = bcm2835_audio_stop(alsa_stream);
  787. + alsa_stream->running = 0;
  788. + if (err != 0)
  789. + audio_error(" Failed to STOP alsa device\n");
  790. + }
  791. +
  792. + alsa_stream->period_size = 0;
  793. + alsa_stream->buffer_size = 0;
  794. +
  795. + if (alsa_stream->open) {
  796. + alsa_stream->open = 0;
  797. + bcm2835_audio_close(alsa_stream);
  798. + }
  799. + if (alsa_stream->chip)
  800. + alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
  801. + /*
  802. + * Do not free up alsa_stream here, it will be freed up by
  803. + * runtime->private_free callback we registered in *_open above
  804. + */
  805. +
  806. + chip->opened &= ~(1 << substream->number);
  807. +
  808. + mutex_unlock(&chip->audio_mutex);
  809. + audio_info(" .. OUT\n");
  810. +
  811. + return 0;
  812. +}
  813. +
  814. +/* hw_params callback */
  815. +static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
  816. + struct snd_pcm_hw_params *params)
  817. +{
  818. + struct snd_pcm_runtime *runtime = substream->runtime;
  819. + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
  820. + int err;
  821. +
  822. + audio_info(" .. IN\n");
  823. +
  824. + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
  825. + if (err < 0) {
  826. + audio_error
  827. + (" pcm_lib_malloc failed to allocated pages for buffers\n");
  828. + return err;
  829. + }
  830. +
  831. + alsa_stream->channels = params_channels(params);
  832. + alsa_stream->params_rate = params_rate(params);
  833. + alsa_stream->pcm_format_width = snd_pcm_format_width(params_format (params));
  834. + audio_info(" .. OUT\n");
  835. +
  836. + return err;
  837. +}
  838. +
  839. +/* hw_free callback */
  840. +static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
  841. +{
  842. + audio_info(" .. IN\n");
  843. + return snd_pcm_lib_free_pages(substream);
  844. +}
  845. +
  846. +/* prepare callback */
  847. +static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
  848. +{
  849. + bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
  850. + struct snd_pcm_runtime *runtime = substream->runtime;
  851. + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
  852. + int channels;
  853. + int err;
  854. +
  855. + audio_info(" .. IN\n");
  856. +
  857. + /* notify the vchiq that it should enter spdif passthrough mode by
  858. + * setting channels=0 (see
  859. + * https://github.com/raspberrypi/linux/issues/528) */
  860. + if (chip->spdif_status & IEC958_AES0_NONAUDIO)
  861. + channels = 0;
  862. + else
  863. + channels = alsa_stream->channels;
  864. +
  865. + err = bcm2835_audio_set_params(alsa_stream, channels,
  866. + alsa_stream->params_rate,
  867. + alsa_stream->pcm_format_width);
  868. + if (err < 0) {
  869. + audio_error(" error setting hw params\n");
  870. + }
  871. +
  872. + bcm2835_audio_setup(alsa_stream);
  873. +
  874. + /* in preparation of the stream, set the controls (volume level) of the stream */
  875. + bcm2835_audio_set_ctls(alsa_stream->chip);
  876. +
  877. +
  878. + memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
  879. +
  880. + alsa_stream->pcm_indirect.hw_buffer_size =
  881. + alsa_stream->pcm_indirect.sw_buffer_size =
  882. + snd_pcm_lib_buffer_bytes(substream);
  883. +
  884. + alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
  885. + alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
  886. + alsa_stream->pos = 0;
  887. +
  888. + audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
  889. + alsa_stream->buffer_size, alsa_stream->period_size,
  890. + alsa_stream->pos, runtime->frame_bits);
  891. +
  892. + audio_info(" .. OUT\n");
  893. + return 0;
  894. +}
  895. +
  896. +static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
  897. + struct snd_pcm_indirect *rec, size_t bytes)
  898. +{
  899. + struct snd_pcm_runtime *runtime = substream->runtime;
  900. + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
  901. + void *src = (void *)(substream->runtime->dma_area + rec->sw_data);
  902. + int err;
  903. +
  904. + err = bcm2835_audio_write(alsa_stream, bytes, src);
  905. + if (err)
  906. + audio_error(" Failed to transfer to alsa device (%d)\n", err);
  907. +
  908. +}
  909. +
  910. +static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
  911. +{
  912. + struct snd_pcm_runtime *runtime = substream->runtime;
  913. + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
  914. + struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
  915. +
  916. + pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
  917. + snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
  918. + snd_bcm2835_pcm_transfer);
  919. + return 0;
  920. +}
  921. +
  922. +/* trigger callback */
  923. +static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  924. +{
  925. + struct snd_pcm_runtime *runtime = substream->runtime;
  926. + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
  927. + int err = 0;
  928. +
  929. + audio_info(" .. IN\n");
  930. +
  931. + switch (cmd) {
  932. + case SNDRV_PCM_TRIGGER_START:
  933. + audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n",
  934. + alsa_stream->running);
  935. + if (!alsa_stream->running) {
  936. + err = bcm2835_audio_start(alsa_stream);
  937. + if (err == 0) {
  938. + alsa_stream->pcm_indirect.hw_io =
  939. + alsa_stream->pcm_indirect.hw_data =
  940. + bytes_to_frames(runtime,
  941. + alsa_stream->pos);
  942. + substream->ops->ack(substream);
  943. + alsa_stream->running = 1;
  944. + alsa_stream->draining = 1;
  945. + } else {
  946. + audio_error(" Failed to START alsa device (%d)\n", err);
  947. + }
  948. + }
  949. + break;
  950. + case SNDRV_PCM_TRIGGER_STOP:
  951. + audio_debug
  952. + ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n",
  953. + alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING);
  954. + if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
  955. + audio_info("DRAINING\n");
  956. + alsa_stream->draining = 1;
  957. + } else {
  958. + audio_info("DROPPING\n");
  959. + alsa_stream->draining = 0;
  960. + }
  961. + if (alsa_stream->running) {
  962. + err = bcm2835_audio_stop(alsa_stream);
  963. + if (err != 0)
  964. + audio_error(" Failed to STOP alsa device (%d)\n", err);
  965. + alsa_stream->running = 0;
  966. + }
  967. + break;
  968. + default:
  969. + err = -EINVAL;
  970. + }
  971. +
  972. + audio_info(" .. OUT\n");
  973. + return err;
  974. +}
  975. +
  976. +/* pointer callback */
  977. +static snd_pcm_uframes_t
  978. +snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
  979. +{
  980. + struct snd_pcm_runtime *runtime = substream->runtime;
  981. + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
  982. +
  983. + audio_info(" .. IN\n");
  984. +
  985. + audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
  986. + frames_to_bytes(runtime, runtime->status->hw_ptr),
  987. + frames_to_bytes(runtime, runtime->control->appl_ptr),
  988. + alsa_stream->pos);
  989. +
  990. + audio_info(" .. OUT\n");
  991. + return snd_pcm_indirect_playback_pointer(substream,
  992. + &alsa_stream->pcm_indirect,
  993. + alsa_stream->pos);
  994. +}
  995. +
  996. +static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
  997. + unsigned int cmd, void *arg)
  998. +{
  999. + int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
  1000. + audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
  1001. + cmd, arg, arg ? *(unsigned *)arg : 0, ret);
  1002. + return ret;
  1003. +}
  1004. +
  1005. +/* operators */
  1006. +static struct snd_pcm_ops snd_bcm2835_playback_ops = {
  1007. + .open = snd_bcm2835_playback_open,
  1008. + .close = snd_bcm2835_playback_close,
  1009. + .ioctl = snd_bcm2835_pcm_lib_ioctl,
  1010. + .hw_params = snd_bcm2835_pcm_hw_params,
  1011. + .hw_free = snd_bcm2835_pcm_hw_free,
  1012. + .prepare = snd_bcm2835_pcm_prepare,
  1013. + .trigger = snd_bcm2835_pcm_trigger,
  1014. + .pointer = snd_bcm2835_pcm_pointer,
  1015. + .ack = snd_bcm2835_pcm_ack,
  1016. +};
  1017. +
  1018. +static struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = {
  1019. + .open = snd_bcm2835_playback_spdif_open,
  1020. + .close = snd_bcm2835_playback_close,
  1021. + .ioctl = snd_bcm2835_pcm_lib_ioctl,
  1022. + .hw_params = snd_bcm2835_pcm_hw_params,
  1023. + .hw_free = snd_bcm2835_pcm_hw_free,
  1024. + .prepare = snd_bcm2835_pcm_prepare,
  1025. + .trigger = snd_bcm2835_pcm_trigger,
  1026. + .pointer = snd_bcm2835_pcm_pointer,
  1027. + .ack = snd_bcm2835_pcm_ack,
  1028. +};
  1029. +
  1030. +/* create a pcm device */
  1031. +int snd_bcm2835_new_pcm(bcm2835_chip_t * chip)
  1032. +{
  1033. + struct snd_pcm *pcm;
  1034. + int err;
  1035. +
  1036. + audio_info(" .. IN\n");
  1037. + mutex_init(&chip->audio_mutex);
  1038. + if(mutex_lock_interruptible(&chip->audio_mutex))
  1039. + {
  1040. + audio_error("Interrupted whilst waiting for lock\n");
  1041. + return -EINTR;
  1042. + }
  1043. + err =
  1044. + snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm);
  1045. + if (err < 0)
  1046. + return err;
  1047. + pcm->private_data = chip;
  1048. + strcpy(pcm->name, "bcm2835 ALSA");
  1049. + chip->pcm = pcm;
  1050. + chip->dest = AUDIO_DEST_AUTO;
  1051. + chip->volume = alsa2chip(0);
  1052. + chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */
  1053. + /* set operators */
  1054. + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
  1055. + &snd_bcm2835_playback_ops);
  1056. +
  1057. + /* pre-allocation of buffers */
  1058. + /* NOTE: this may fail */
  1059. + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
  1060. + snd_dma_continuous_data
  1061. + (GFP_KERNEL), 64 * 1024,
  1062. + 64 * 1024);
  1063. +
  1064. + mutex_unlock(&chip->audio_mutex);
  1065. + audio_info(" .. OUT\n");
  1066. +
  1067. + return 0;
  1068. +}
  1069. +
  1070. +int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip)
  1071. +{
  1072. + struct snd_pcm *pcm;
  1073. + int err;
  1074. +
  1075. + audio_info(" .. IN\n");
  1076. + if(mutex_lock_interruptible(&chip->audio_mutex))
  1077. + {
  1078. + audio_error("Interrupted whilst waiting for lock\n");
  1079. + return -EINTR;
  1080. + }
  1081. + err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm);
  1082. + if (err < 0)
  1083. + return err;
  1084. +
  1085. + pcm->private_data = chip;
  1086. + strcpy(pcm->name, "bcm2835 IEC958/HDMI");
  1087. + chip->pcm_spdif = pcm;
  1088. + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
  1089. + &snd_bcm2835_playback_spdif_ops);
  1090. +
  1091. + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
  1092. + snd_dma_continuous_data (GFP_KERNEL),
  1093. + 64 * 1024, 64 * 1024);
  1094. + mutex_unlock(&chip->audio_mutex);
  1095. + audio_info(" .. OUT\n");
  1096. +
  1097. + return 0;
  1098. +}
  1099. --- /dev/null
  1100. +++ b/sound/arm/bcm2835-vchiq.c
  1101. @@ -0,0 +1,902 @@
  1102. +/*****************************************************************************
  1103. +* Copyright 2011 Broadcom Corporation. All rights reserved.
  1104. +*
  1105. +* Unless you and Broadcom execute a separate written software license
  1106. +* agreement governing use of this software, this software is licensed to you
  1107. +* under the terms of the GNU General Public License version 2, available at
  1108. +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
  1109. +*
  1110. +* Notwithstanding the above, under no circumstances may you combine this
  1111. +* software in any way with any other Broadcom software provided under a
  1112. +* license other than the GPL, without Broadcom's express prior written
  1113. +* consent.
  1114. +*****************************************************************************/
  1115. +
  1116. +#include <linux/device.h>
  1117. +#include <sound/core.h>
  1118. +#include <sound/initval.h>
  1119. +#include <sound/pcm.h>
  1120. +#include <linux/io.h>
  1121. +#include <linux/interrupt.h>
  1122. +#include <linux/fs.h>
  1123. +#include <linux/file.h>
  1124. +#include <linux/mm.h>
  1125. +#include <linux/syscalls.h>
  1126. +#include <asm/uaccess.h>
  1127. +#include <linux/slab.h>
  1128. +#include <linux/delay.h>
  1129. +#include <linux/atomic.h>
  1130. +#include <linux/module.h>
  1131. +#include <linux/completion.h>
  1132. +
  1133. +#include "bcm2835.h"
  1134. +
  1135. +/* ---- Include Files -------------------------------------------------------- */
  1136. +
  1137. +#include "interface/vchi/vchi.h"
  1138. +#include "vc_vchi_audioserv_defs.h"
  1139. +
  1140. +/* ---- Private Constants and Types ------------------------------------------ */
  1141. +
  1142. +#define BCM2835_AUDIO_STOP 0
  1143. +#define BCM2835_AUDIO_START 1
  1144. +#define BCM2835_AUDIO_WRITE 2
  1145. +
  1146. +/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
  1147. +#ifdef AUDIO_DEBUG_ENABLE
  1148. + #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
  1149. + #define LOG_WARN( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
  1150. + #define LOG_INFO( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
  1151. + #define LOG_DBG( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
  1152. +#else
  1153. + #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
  1154. + #define LOG_WARN( fmt, arg... )
  1155. + #define LOG_INFO( fmt, arg... )
  1156. + #define LOG_DBG( fmt, arg... )
  1157. +#endif
  1158. +
  1159. +typedef struct opaque_AUDIO_INSTANCE_T {
  1160. + uint32_t num_connections;
  1161. + VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
  1162. + struct completion msg_avail_comp;
  1163. + struct mutex vchi_mutex;
  1164. + bcm2835_alsa_stream_t *alsa_stream;
  1165. + int32_t result;
  1166. + short peer_version;
  1167. +} AUDIO_INSTANCE_T;
  1168. +
  1169. +bool force_bulk = false;
  1170. +
  1171. +/* ---- Private Variables ---------------------------------------------------- */
  1172. +
  1173. +/* ---- Private Function Prototypes ------------------------------------------ */
  1174. +
  1175. +/* ---- Private Functions ---------------------------------------------------- */
  1176. +
  1177. +static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
  1178. +static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
  1179. +static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
  1180. + uint32_t count, void *src);
  1181. +
  1182. +typedef struct {
  1183. + struct work_struct my_work;
  1184. + bcm2835_alsa_stream_t *alsa_stream;
  1185. + int cmd;
  1186. + void *src;
  1187. + uint32_t count;
  1188. +} my_work_t;
  1189. +
  1190. +static void my_wq_function(struct work_struct *work)
  1191. +{
  1192. + my_work_t *w = (my_work_t *) work;
  1193. + int ret = -9;
  1194. + LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
  1195. + switch (w->cmd) {
  1196. + case BCM2835_AUDIO_START:
  1197. + ret = bcm2835_audio_start_worker(w->alsa_stream);
  1198. + break;
  1199. + case BCM2835_AUDIO_STOP:
  1200. + ret = bcm2835_audio_stop_worker(w->alsa_stream);
  1201. + break;
  1202. + case BCM2835_AUDIO_WRITE:
  1203. + ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
  1204. + w->src);
  1205. + break;
  1206. + default:
  1207. + LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
  1208. + break;
  1209. + }
  1210. + kfree((void *)work);
  1211. + LOG_DBG(" .. OUT %d\n", ret);
  1212. +}
  1213. +
  1214. +int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream)
  1215. +{
  1216. + int ret = -1;
  1217. + LOG_DBG(" .. IN\n");
  1218. + if (alsa_stream->my_wq) {
  1219. + my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
  1220. + /*--- Queue some work (item 1) ---*/
  1221. + if (work) {
  1222. + INIT_WORK((struct work_struct *)work, my_wq_function);
  1223. + work->alsa_stream = alsa_stream;
  1224. + work->cmd = BCM2835_AUDIO_START;
  1225. + if (queue_work
  1226. + (alsa_stream->my_wq, (struct work_struct *)work))
  1227. + ret = 0;
  1228. + } else
  1229. + LOG_ERR(" .. Error: NULL work kmalloc\n");
  1230. + }
  1231. + LOG_DBG(" .. OUT %d\n", ret);
  1232. + return ret;
  1233. +}
  1234. +
  1235. +int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
  1236. +{
  1237. + int ret = -1;
  1238. + LOG_DBG(" .. IN\n");
  1239. + if (alsa_stream->my_wq) {
  1240. + my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
  1241. + /*--- Queue some work (item 1) ---*/
  1242. + if (work) {
  1243. + INIT_WORK((struct work_struct *)work, my_wq_function);
  1244. + work->alsa_stream = alsa_stream;
  1245. + work->cmd = BCM2835_AUDIO_STOP;
  1246. + if (queue_work
  1247. + (alsa_stream->my_wq, (struct work_struct *)work))
  1248. + ret = 0;
  1249. + } else
  1250. + LOG_ERR(" .. Error: NULL work kmalloc\n");
  1251. + }
  1252. + LOG_DBG(" .. OUT %d\n", ret);
  1253. + return ret;
  1254. +}
  1255. +
  1256. +int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream,
  1257. + uint32_t count, void *src)
  1258. +{
  1259. + int ret = -1;
  1260. + LOG_DBG(" .. IN\n");
  1261. + if (alsa_stream->my_wq) {
  1262. + my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
  1263. + /*--- Queue some work (item 1) ---*/
  1264. + if (work) {
  1265. + INIT_WORK((struct work_struct *)work, my_wq_function);
  1266. + work->alsa_stream = alsa_stream;
  1267. + work->cmd = BCM2835_AUDIO_WRITE;
  1268. + work->src = src;
  1269. + work->count = count;
  1270. + if (queue_work
  1271. + (alsa_stream->my_wq, (struct work_struct *)work))
  1272. + ret = 0;
  1273. + } else
  1274. + LOG_ERR(" .. Error: NULL work kmalloc\n");
  1275. + }
  1276. + LOG_DBG(" .. OUT %d\n", ret);
  1277. + return ret;
  1278. +}
  1279. +
  1280. +void my_workqueue_init(bcm2835_alsa_stream_t * alsa_stream)
  1281. +{
  1282. + alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
  1283. + return;
  1284. +}
  1285. +
  1286. +void my_workqueue_quit(bcm2835_alsa_stream_t * alsa_stream)
  1287. +{
  1288. + if (alsa_stream->my_wq) {
  1289. + flush_workqueue(alsa_stream->my_wq);
  1290. + destroy_workqueue(alsa_stream->my_wq);
  1291. + alsa_stream->my_wq = NULL;
  1292. + }
  1293. + return;
  1294. +}
  1295. +
  1296. +static void audio_vchi_callback(void *param,
  1297. + const VCHI_CALLBACK_REASON_T reason,
  1298. + void *msg_handle)
  1299. +{
  1300. + AUDIO_INSTANCE_T *instance = (AUDIO_INSTANCE_T *) param;
  1301. + int32_t status;
  1302. + int32_t msg_len;
  1303. + VC_AUDIO_MSG_T m;
  1304. + LOG_DBG(" .. IN instance=%p, handle=%p, alsa=%p, reason=%d, handle=%p\n",
  1305. + instance, instance ? instance->vchi_handle[0] : NULL, instance ? instance->alsa_stream : NULL, reason, msg_handle);
  1306. +
  1307. + if (reason != VCHI_CALLBACK_MSG_AVAILABLE) {
  1308. + return;
  1309. + }
  1310. + if (!instance) {
  1311. + LOG_ERR(" .. instance is null\n");
  1312. + BUG();
  1313. + return;
  1314. + }
  1315. + if (!instance->vchi_handle[0]) {
  1316. + LOG_ERR(" .. instance->vchi_handle[0] is null\n");
  1317. + BUG();
  1318. + return;
  1319. + }
  1320. + status = vchi_msg_dequeue(instance->vchi_handle[0],
  1321. + &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
  1322. + if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
  1323. + LOG_DBG
  1324. + (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
  1325. + instance, m.u.result.success);
  1326. + instance->result = m.u.result.success;
  1327. + complete(&instance->msg_avail_comp);
  1328. + } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
  1329. + bcm2835_alsa_stream_t *alsa_stream = instance->alsa_stream;
  1330. + irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
  1331. + LOG_DBG
  1332. + (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
  1333. + instance, m.u.complete.count);
  1334. + if (alsa_stream && callback) {
  1335. + atomic_add(m.u.complete.count, &alsa_stream->retrieved);
  1336. + callback(0, alsa_stream);
  1337. + } else {
  1338. + LOG_ERR(" .. unexpected alsa_stream=%p, callback=%p\n",
  1339. + alsa_stream, callback);
  1340. + }
  1341. + } else {
  1342. + LOG_ERR(" .. unexpected m.type=%d\n", m.type);
  1343. + }
  1344. + LOG_DBG(" .. OUT\n");
  1345. +}
  1346. +
  1347. +static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
  1348. + VCHI_CONNECTION_T **
  1349. + vchi_connections,
  1350. + uint32_t num_connections)
  1351. +{
  1352. + uint32_t i;
  1353. + AUDIO_INSTANCE_T *instance;
  1354. + int status;
  1355. +
  1356. + LOG_DBG("%s: start", __func__);
  1357. +
  1358. + if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
  1359. + LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
  1360. + __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
  1361. +
  1362. + return NULL;
  1363. + }
  1364. + /* Allocate memory for this instance */
  1365. + instance = kmalloc(sizeof(*instance), GFP_KERNEL);
  1366. + if (!instance)
  1367. + return NULL;
  1368. +
  1369. + memset(instance, 0, sizeof(*instance));
  1370. + instance->num_connections = num_connections;
  1371. +
  1372. + /* Create a lock for exclusive, serialized VCHI connection access */
  1373. + mutex_init(&instance->vchi_mutex);
  1374. + /* Open the VCHI service connections */
  1375. + for (i = 0; i < num_connections; i++) {
  1376. + SERVICE_CREATION_T params = {
  1377. + VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
  1378. + VC_AUDIO_SERVER_NAME, // 4cc service code
  1379. + vchi_connections[i], // passed in fn pointers
  1380. + 0, // rx fifo size (unused)
  1381. + 0, // tx fifo size (unused)
  1382. + audio_vchi_callback, // service callback
  1383. + instance, // service callback parameter
  1384. + 1, //TODO: remove VCOS_FALSE, // unaligned bulk recieves
  1385. + 1, //TODO: remove VCOS_FALSE, // unaligned bulk transmits
  1386. + 0 // want crc check on bulk transfers
  1387. + };
  1388. +
  1389. + LOG_DBG("%s: about to open %i\n", __func__, i);
  1390. + status = vchi_service_open(vchi_instance, &params,
  1391. + &instance->vchi_handle[i]);
  1392. + LOG_DBG("%s: opened %i: %p=%d\n", __func__, i, instance->vchi_handle[i], status);
  1393. + if (status) {
  1394. + LOG_ERR
  1395. + ("%s: failed to open VCHI service connection (status=%d)\n",
  1396. + __func__, status);
  1397. +
  1398. + goto err_close_services;
  1399. + }
  1400. + /* Finished with the service for now */
  1401. + vchi_service_release(instance->vchi_handle[i]);
  1402. + }
  1403. +
  1404. + LOG_DBG("%s: okay\n", __func__);
  1405. + return instance;
  1406. +
  1407. +err_close_services:
  1408. + for (i = 0; i < instance->num_connections; i++) {
  1409. + LOG_ERR("%s: closing %i: %p\n", __func__, i, instance->vchi_handle[i]);
  1410. + if (instance->vchi_handle[i])
  1411. + vchi_service_close(instance->vchi_handle[i]);
  1412. + }
  1413. +
  1414. + kfree(instance);
  1415. + LOG_ERR("%s: error\n", __func__);
  1416. +
  1417. + return NULL;
  1418. +}
  1419. +
  1420. +static int32_t vc_vchi_audio_deinit(AUDIO_INSTANCE_T * instance)
  1421. +{
  1422. + uint32_t i;
  1423. +
  1424. + LOG_DBG(" .. IN\n");
  1425. +
  1426. + if (instance == NULL) {
  1427. + LOG_ERR("%s: invalid handle %p\n", __func__, instance);
  1428. +
  1429. + return -1;
  1430. + }
  1431. +
  1432. + LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
  1433. + if(mutex_lock_interruptible(&instance->vchi_mutex))
  1434. + {
  1435. + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
  1436. + return -EINTR;
  1437. + }
  1438. +
  1439. + /* Close all VCHI service connections */
  1440. + for (i = 0; i < instance->num_connections; i++) {
  1441. + int32_t success;
  1442. + LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
  1443. + vchi_service_use(instance->vchi_handle[i]);
  1444. +
  1445. + success = vchi_service_close(instance->vchi_handle[i]);
  1446. + if (success != 0) {
  1447. + LOG_ERR
  1448. + ("%s: failed to close VCHI service connection (status=%d)\n",
  1449. + __func__, success);
  1450. + }
  1451. + }
  1452. +
  1453. + mutex_unlock(&instance->vchi_mutex);
  1454. +
  1455. + kfree(instance);
  1456. +
  1457. + LOG_DBG(" .. OUT\n");
  1458. +
  1459. + return 0;
  1460. +}
  1461. +
  1462. +static int bcm2835_audio_open_connection(bcm2835_alsa_stream_t * alsa_stream)
  1463. +{
  1464. + static VCHI_INSTANCE_T vchi_instance;
  1465. + static VCHI_CONNECTION_T *vchi_connection;
  1466. + static int initted;
  1467. + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
  1468. + int ret;
  1469. + LOG_DBG(" .. IN\n");
  1470. +
  1471. + LOG_INFO("%s: start\n", __func__);
  1472. + BUG_ON(instance);
  1473. + if (instance) {
  1474. + LOG_ERR("%s: VCHI instance already open (%p)\n",
  1475. + __func__, instance);
  1476. + instance->alsa_stream = alsa_stream;
  1477. + alsa_stream->instance = instance;
  1478. + ret = 0; // xxx todo -1;
  1479. + goto err_free_mem;
  1480. + }
  1481. +
  1482. + /* Initialize and create a VCHI connection */
  1483. + if (!initted) {
  1484. + ret = vchi_initialise(&vchi_instance);
  1485. + if (ret != 0) {
  1486. + LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
  1487. + __func__, ret);
  1488. +
  1489. + ret = -EIO;
  1490. + goto err_free_mem;
  1491. + }
  1492. + ret = vchi_connect(NULL, 0, vchi_instance);
  1493. + if (ret != 0) {
  1494. + LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
  1495. + __func__, ret);
  1496. +
  1497. + ret = -EIO;
  1498. + goto err_free_mem;
  1499. + }
  1500. + initted = 1;
  1501. + }
  1502. +
  1503. + /* Initialize an instance of the audio service */
  1504. + instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1);
  1505. +
  1506. + if (instance == NULL) {
  1507. + LOG_ERR("%s: failed to initialize audio service\n", __func__);
  1508. +
  1509. + ret = -EPERM;
  1510. + goto err_free_mem;
  1511. + }
  1512. +
  1513. + instance->alsa_stream = alsa_stream;
  1514. + alsa_stream->instance = instance;
  1515. +
  1516. + LOG_DBG(" success !\n");
  1517. +err_free_mem:
  1518. + LOG_DBG(" .. OUT\n");
  1519. +
  1520. + return ret;
  1521. +}
  1522. +
  1523. +int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream)
  1524. +{
  1525. + AUDIO_INSTANCE_T *instance;
  1526. + VC_AUDIO_MSG_T m;
  1527. + int32_t success;
  1528. + int ret;
  1529. + LOG_DBG(" .. IN\n");
  1530. +
  1531. + my_workqueue_init(alsa_stream);
  1532. +
  1533. + ret = bcm2835_audio_open_connection(alsa_stream);
  1534. + if (ret != 0) {
  1535. + ret = -1;
  1536. + goto exit;
  1537. + }
  1538. + instance = alsa_stream->instance;
  1539. + LOG_DBG(" instance (%p)\n", instance);
  1540. +
  1541. + if(mutex_lock_interruptible(&instance->vchi_mutex))
  1542. + {
  1543. + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
  1544. + return -EINTR;
  1545. + }
  1546. + vchi_service_use(instance->vchi_handle[0]);
  1547. +
  1548. + m.type = VC_AUDIO_MSG_TYPE_OPEN;
  1549. +
  1550. + /* Send the message to the videocore */
  1551. + success = vchi_msg_queue(instance->vchi_handle[0],
  1552. + &m, sizeof m,
  1553. + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
  1554. +
  1555. + if (success != 0) {
  1556. + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
  1557. + __func__, success);
  1558. +
  1559. + ret = -1;
  1560. + goto unlock;
  1561. + }
  1562. +
  1563. + ret = 0;
  1564. +
  1565. +unlock:
  1566. + vchi_service_release(instance->vchi_handle[0]);
  1567. + mutex_unlock(&instance->vchi_mutex);
  1568. +exit:
  1569. + LOG_DBG(" .. OUT\n");
  1570. + return ret;
  1571. +}
  1572. +
  1573. +static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
  1574. + bcm2835_chip_t * chip)
  1575. +{
  1576. + VC_AUDIO_MSG_T m;
  1577. + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
  1578. + int32_t success;
  1579. + int ret;
  1580. + LOG_DBG(" .. IN\n");
  1581. +
  1582. + LOG_INFO
  1583. + (" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
  1584. +
  1585. + if(mutex_lock_interruptible(&instance->vchi_mutex))
  1586. + {
  1587. + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
  1588. + return -EINTR;
  1589. + }
  1590. + vchi_service_use(instance->vchi_handle[0]);
  1591. +
  1592. + instance->result = -1;
  1593. +
  1594. + m.type = VC_AUDIO_MSG_TYPE_CONTROL;
  1595. + m.u.control.dest = chip->dest;
  1596. + m.u.control.volume = chip->volume;
  1597. +
  1598. + /* Create the message available completion */
  1599. + init_completion(&instance->msg_avail_comp);
  1600. +
  1601. + /* Send the message to the videocore */
  1602. + success = vchi_msg_queue(instance->vchi_handle[0],
  1603. + &m, sizeof m,
  1604. + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
  1605. +
  1606. + if (success != 0) {
  1607. + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
  1608. + __func__, success);
  1609. +
  1610. + ret = -1;
  1611. + goto unlock;
  1612. + }
  1613. +
  1614. + /* We are expecting a reply from the videocore */
  1615. + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
  1616. + if (ret) {
  1617. + LOG_ERR("%s: failed on waiting for event (status=%d)\n",
  1618. + __func__, success);
  1619. + goto unlock;
  1620. + }
  1621. +
  1622. + if (instance->result != 0) {
  1623. + LOG_ERR("%s: result=%d\n", __func__, instance->result);
  1624. +
  1625. + ret = -1;
  1626. + goto unlock;
  1627. + }
  1628. +
  1629. + ret = 0;
  1630. +
  1631. +unlock:
  1632. + vchi_service_release(instance->vchi_handle[0]);
  1633. + mutex_unlock(&instance->vchi_mutex);
  1634. +
  1635. + LOG_DBG(" .. OUT\n");
  1636. + return ret;
  1637. +}
  1638. +
  1639. +int bcm2835_audio_set_ctls(bcm2835_chip_t * chip)
  1640. +{
  1641. + int i;
  1642. + int ret = 0;
  1643. + LOG_DBG(" .. IN\n");
  1644. + LOG_DBG(" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
  1645. +
  1646. + /* change ctls for all substreams */
  1647. + for (i = 0; i < MAX_SUBSTREAMS; i++) {
  1648. + if (chip->avail_substreams & (1 << i)) {
  1649. + if (!chip->alsa_stream[i])
  1650. + {
  1651. + LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
  1652. + ret = 0;
  1653. + }
  1654. + else if (bcm2835_audio_set_ctls_chan /* returns 0 on success */
  1655. + (chip->alsa_stream[i], chip) != 0)
  1656. + {
  1657. + LOG_ERR("Couldn't set the controls for stream %d\n", i);
  1658. + ret = -1;
  1659. + }
  1660. + else LOG_DBG(" Controls set for stream %d\n", i);
  1661. + }
  1662. + }
  1663. + LOG_DBG(" .. OUT ret=%d\n", ret);
  1664. + return ret;
  1665. +}
  1666. +
  1667. +int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
  1668. + uint32_t channels, uint32_t samplerate,
  1669. + uint32_t bps)
  1670. +{
  1671. + VC_AUDIO_MSG_T m;
  1672. + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
  1673. + int32_t success;
  1674. + int ret;
  1675. + LOG_DBG(" .. IN\n");
  1676. +
  1677. + LOG_INFO
  1678. + (" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
  1679. + channels, samplerate, bps);
  1680. +
  1681. + /* resend ctls - alsa_stream may not have been open when first send */
  1682. + ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
  1683. + if (ret != 0) {
  1684. + LOG_ERR(" Alsa controls not supported\n");
  1685. + return -EINVAL;
  1686. + }
  1687. +
  1688. + if(mutex_lock_interruptible(&instance->vchi_mutex))
  1689. + {
  1690. + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
  1691. + return -EINTR;
  1692. + }
  1693. + vchi_service_use(instance->vchi_handle[0]);
  1694. +
  1695. + instance->result = -1;
  1696. +
  1697. + m.type = VC_AUDIO_MSG_TYPE_CONFIG;
  1698. + m.u.config.channels = channels;
  1699. + m.u.config.samplerate = samplerate;
  1700. + m.u.config.bps = bps;
  1701. +
  1702. + /* Create the message available completion */
  1703. + init_completion(&instance->msg_avail_comp);
  1704. +
  1705. + /* Send the message to the videocore */
  1706. + success = vchi_msg_queue(instance->vchi_handle[0],
  1707. + &m, sizeof m,
  1708. + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
  1709. +
  1710. + if (success != 0) {
  1711. + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
  1712. + __func__, success);
  1713. +
  1714. + ret = -1;
  1715. + goto unlock;
  1716. + }
  1717. +
  1718. + /* We are expecting a reply from the videocore */
  1719. + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
  1720. + if (ret) {
  1721. + LOG_ERR("%s: failed on waiting for event (status=%d)\n",
  1722. + __func__, success);
  1723. + goto unlock;
  1724. + }
  1725. +
  1726. + if (instance->result != 0) {
  1727. + LOG_ERR("%s: result=%d", __func__, instance->result);
  1728. +
  1729. + ret = -1;
  1730. + goto unlock;
  1731. + }
  1732. +
  1733. + ret = 0;
  1734. +
  1735. +unlock:
  1736. + vchi_service_release(instance->vchi_handle[0]);
  1737. + mutex_unlock(&instance->vchi_mutex);
  1738. +
  1739. + LOG_DBG(" .. OUT\n");
  1740. + return ret;
  1741. +}
  1742. +
  1743. +int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream)
  1744. +{
  1745. + LOG_DBG(" .. IN\n");
  1746. +
  1747. + LOG_DBG(" .. OUT\n");
  1748. +
  1749. + return 0;
  1750. +}
  1751. +
  1752. +static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream)
  1753. +{
  1754. + VC_AUDIO_MSG_T m;
  1755. + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
  1756. + int32_t success;
  1757. + int ret;
  1758. + LOG_DBG(" .. IN\n");
  1759. +
  1760. + if(mutex_lock_interruptible(&instance->vchi_mutex))
  1761. + {
  1762. + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
  1763. + return -EINTR;
  1764. + }
  1765. + vchi_service_use(instance->vchi_handle[0]);
  1766. +
  1767. + m.type = VC_AUDIO_MSG_TYPE_START;
  1768. +
  1769. + /* Send the message to the videocore */
  1770. + success = vchi_msg_queue(instance->vchi_handle[0],
  1771. + &m, sizeof m,
  1772. + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
  1773. +
  1774. + if (success != 0) {
  1775. + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
  1776. + __func__, success);
  1777. +
  1778. + ret = -1;
  1779. + goto unlock;
  1780. + }
  1781. +
  1782. + ret = 0;
  1783. +
  1784. +unlock:
  1785. + vchi_service_release(instance->vchi_handle[0]);
  1786. + mutex_unlock(&instance->vchi_mutex);
  1787. + LOG_DBG(" .. OUT\n");
  1788. + return ret;
  1789. +}
  1790. +
  1791. +static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream)
  1792. +{
  1793. + VC_AUDIO_MSG_T m;
  1794. + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
  1795. + int32_t success;
  1796. + int ret;
  1797. + LOG_DBG(" .. IN\n");
  1798. +
  1799. + if(mutex_lock_interruptible(&instance->vchi_mutex))
  1800. + {
  1801. + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
  1802. + return -EINTR;
  1803. + }
  1804. + vchi_service_use(instance->vchi_handle[0]);
  1805. +
  1806. + m.type = VC_AUDIO_MSG_TYPE_STOP;
  1807. + m.u.stop.draining = alsa_stream->draining;
  1808. +
  1809. + /* Send the message to the videocore */
  1810. + success = vchi_msg_queue(instance->vchi_handle[0],
  1811. + &m, sizeof m,
  1812. + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
  1813. +
  1814. + if (success != 0) {
  1815. + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
  1816. + __func__, success);
  1817. +
  1818. + ret = -1;
  1819. + goto unlock;
  1820. + }
  1821. +
  1822. + ret = 0;
  1823. +
  1824. +unlock:
  1825. + vchi_service_release(instance->vchi_handle[0]);
  1826. + mutex_unlock(&instance->vchi_mutex);
  1827. + LOG_DBG(" .. OUT\n");
  1828. + return ret;
  1829. +}
  1830. +
  1831. +int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
  1832. +{
  1833. + VC_AUDIO_MSG_T m;
  1834. + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
  1835. + int32_t success;
  1836. + int ret;
  1837. + LOG_DBG(" .. IN\n");
  1838. +
  1839. + my_workqueue_quit(alsa_stream);
  1840. +
  1841. + if(mutex_lock_interruptible(&instance->vchi_mutex))
  1842. + {
  1843. + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
  1844. + return -EINTR;
  1845. + }
  1846. + vchi_service_use(instance->vchi_handle[0]);
  1847. +
  1848. + m.type = VC_AUDIO_MSG_TYPE_CLOSE;
  1849. +
  1850. + /* Create the message available completion */
  1851. + init_completion(&instance->msg_avail_comp);
  1852. +
  1853. + /* Send the message to the videocore */
  1854. + success = vchi_msg_queue(instance->vchi_handle[0],
  1855. + &m, sizeof m,
  1856. + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
  1857. +
  1858. + if (success != 0) {
  1859. + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
  1860. + __func__, success);
  1861. + ret = -1;
  1862. + goto unlock;
  1863. + }
  1864. +
  1865. + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
  1866. + if (ret) {
  1867. + LOG_ERR("%s: failed on waiting for event (status=%d)\n",
  1868. + __func__, success);
  1869. + goto unlock;
  1870. + }
  1871. + if (instance->result != 0) {
  1872. + LOG_ERR("%s: failed result (status=%d)\n",
  1873. + __func__, instance->result);
  1874. +
  1875. + ret = -1;
  1876. + goto unlock;
  1877. + }
  1878. +
  1879. + ret = 0;
  1880. +
  1881. +unlock:
  1882. + vchi_service_release(instance->vchi_handle[0]);
  1883. + mutex_unlock(&instance->vchi_mutex);
  1884. +
  1885. + /* Stop the audio service */
  1886. + if (instance) {
  1887. + vc_vchi_audio_deinit(instance);
  1888. + alsa_stream->instance = NULL;
  1889. + }
  1890. + LOG_DBG(" .. OUT\n");
  1891. + return ret;
  1892. +}
  1893. +
  1894. +int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
  1895. + uint32_t count, void *src)
  1896. +{
  1897. + VC_AUDIO_MSG_T m;
  1898. + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
  1899. + int32_t success;
  1900. + int ret;
  1901. +
  1902. + LOG_DBG(" .. IN\n");
  1903. +
  1904. + LOG_INFO(" Writing %d bytes from %p\n", count, src);
  1905. +
  1906. + if(mutex_lock_interruptible(&instance->vchi_mutex))
  1907. + {
  1908. + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
  1909. + return -EINTR;
  1910. + }
  1911. + vchi_service_use(instance->vchi_handle[0]);
  1912. +
  1913. + if ( instance->peer_version==0 && vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0 ) {
  1914. + LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
  1915. + }
  1916. + m.type = VC_AUDIO_MSG_TYPE_WRITE;
  1917. + m.u.write.count = count;
  1918. + // old version uses bulk, new version uses control
  1919. + m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0:4000;
  1920. + m.u.write.callback = alsa_stream->fifo_irq_handler;
  1921. + m.u.write.cookie = alsa_stream;
  1922. + m.u.write.silence = src == NULL;
  1923. +
  1924. + /* Send the message to the videocore */
  1925. + success = vchi_msg_queue(instance->vchi_handle[0],
  1926. + &m, sizeof m,
  1927. + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
  1928. +
  1929. + if (success != 0) {
  1930. + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
  1931. + __func__, success);
  1932. +
  1933. + ret = -1;
  1934. + goto unlock;
  1935. + }
  1936. + if (!m.u.write.silence) {
  1937. + if (m.u.write.max_packet == 0) {
  1938. + /* Send the message to the videocore */
  1939. + success = vchi_bulk_queue_transmit(instance->vchi_handle[0],
  1940. + src, count,
  1941. + 0 *
  1942. + VCHI_FLAGS_BLOCK_UNTIL_QUEUED
  1943. + +
  1944. + 1 *
  1945. + VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
  1946. + NULL);
  1947. + } else {
  1948. + while (count > 0) {
  1949. + int bytes = min((int)m.u.write.max_packet, (int)count);
  1950. + success = vchi_msg_queue(instance->vchi_handle[0],
  1951. + src, bytes,
  1952. + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
  1953. + src = (char *)src + bytes;
  1954. + count -= bytes;
  1955. + }
  1956. + }
  1957. + if (success != 0) {
  1958. + LOG_ERR
  1959. + ("%s: failed on vchi_bulk_queue_transmit (status=%d)\n",
  1960. + __func__, success);
  1961. +
  1962. + ret = -1;
  1963. + goto unlock;
  1964. + }
  1965. + }
  1966. + ret = 0;
  1967. +
  1968. +unlock:
  1969. + vchi_service_release(instance->vchi_handle[0]);
  1970. + mutex_unlock(&instance->vchi_mutex);
  1971. + LOG_DBG(" .. OUT\n");
  1972. + return ret;
  1973. +}
  1974. +
  1975. +/**
  1976. + * Returns all buffers from arm->vc
  1977. + */
  1978. +void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream)
  1979. +{
  1980. + LOG_DBG(" .. IN\n");
  1981. + LOG_DBG(" .. OUT\n");
  1982. + return;
  1983. +}
  1984. +
  1985. +/**
  1986. + * Forces VC to flush(drop) its filled playback buffers and
  1987. + * return them the us. (VC->ARM)
  1988. + */
  1989. +void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream)
  1990. +{
  1991. + LOG_DBG(" .. IN\n");
  1992. + LOG_DBG(" .. OUT\n");
  1993. +}
  1994. +
  1995. +uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream)
  1996. +{
  1997. + uint32_t count = atomic_read(&alsa_stream->retrieved);
  1998. + atomic_sub(count, &alsa_stream->retrieved);
  1999. + return count;
  2000. +}
  2001. +
  2002. +module_param(force_bulk, bool, 0444);
  2003. +MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
  2004. --- /dev/null
  2005. +++ b/sound/arm/bcm2835.c
  2006. @@ -0,0 +1,420 @@
  2007. +/*****************************************************************************
  2008. +* Copyright 2011 Broadcom Corporation. All rights reserved.
  2009. +*
  2010. +* Unless you and Broadcom execute a separate written software license
  2011. +* agreement governing use of this software, this software is licensed to you
  2012. +* under the terms of the GNU General Public License version 2, available at
  2013. +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
  2014. +*
  2015. +* Notwithstanding the above, under no circumstances may you combine this
  2016. +* software in any way with any other Broadcom software provided under a
  2017. +* license other than the GPL, without Broadcom's express prior written
  2018. +* consent.
  2019. +*****************************************************************************/
  2020. +
  2021. +#include <linux/platform_device.h>
  2022. +
  2023. +#include <linux/init.h>
  2024. +#include <linux/slab.h>
  2025. +#include <linux/module.h>
  2026. +
  2027. +#include "bcm2835.h"
  2028. +
  2029. +/* module parameters (see "Module Parameters") */
  2030. +/* SNDRV_CARDS: maximum number of cards supported by this module */
  2031. +static int index[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = -1 };
  2032. +static char *id[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = NULL };
  2033. +static int enable[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = 1 };
  2034. +
  2035. +/* HACKY global pointers needed for successive probes to work : ssp
  2036. + * But compared against the changes we will have to do in VC audio_ipc code
  2037. + * to export 8 audio_ipc devices as a single IPC device and then monitor all
  2038. + * four devices in a thread, this gets things done quickly and should be easier
  2039. + * to debug if we run into issues
  2040. + */
  2041. +
  2042. +static struct snd_card *g_card = NULL;
  2043. +static bcm2835_chip_t *g_chip = NULL;
  2044. +
  2045. +static int snd_bcm2835_free(bcm2835_chip_t * chip)
  2046. +{
  2047. + kfree(chip);
  2048. + return 0;
  2049. +}
  2050. +
  2051. +/* component-destructor
  2052. + * (see "Management of Cards and Components")
  2053. + */
  2054. +static int snd_bcm2835_dev_free(struct snd_device *device)
  2055. +{
  2056. + return snd_bcm2835_free(device->device_data);
  2057. +}
  2058. +
  2059. +/* chip-specific constructor
  2060. + * (see "Management of Cards and Components")
  2061. + */
  2062. +static int snd_bcm2835_create(struct snd_card *card,
  2063. + struct platform_device *pdev,
  2064. + bcm2835_chip_t ** rchip)
  2065. +{
  2066. + bcm2835_chip_t *chip;
  2067. + int err;
  2068. + static struct snd_device_ops ops = {
  2069. + .dev_free = snd_bcm2835_dev_free,
  2070. + };
  2071. +
  2072. + *rchip = NULL;
  2073. +
  2074. + chip = kzalloc(sizeof(*chip), GFP_KERNEL);
  2075. + if (chip == NULL)
  2076. + return -ENOMEM;
  2077. +
  2078. + chip->card = card;
  2079. +
  2080. + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
  2081. + if (err < 0) {
  2082. + snd_bcm2835_free(chip);
  2083. + return err;
  2084. + }
  2085. +
  2086. + *rchip = chip;
  2087. + return 0;
  2088. +}
  2089. +
  2090. +static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
  2091. +{
  2092. + static int dev;
  2093. + bcm2835_chip_t *chip;
  2094. + struct snd_card *card;
  2095. + int err;
  2096. +
  2097. + if (dev >= MAX_SUBSTREAMS)
  2098. + return -ENODEV;
  2099. +
  2100. + if (!enable[dev]) {
  2101. + dev++;
  2102. + return -ENOENT;
  2103. + }
  2104. +
  2105. + if (dev > 0)
  2106. + goto add_register_map;
  2107. +
  2108. + err = snd_card_new(NULL, index[dev], id[dev], THIS_MODULE, 0, &g_card);
  2109. + if (err < 0)
  2110. + goto out;
  2111. +
  2112. + snd_card_set_dev(g_card, &pdev->dev);
  2113. + strcpy(g_card->driver, "bcm2835");
  2114. + strcpy(g_card->shortname, "bcm2835 ALSA");
  2115. + sprintf(g_card->longname, "%s", g_card->shortname);
  2116. +
  2117. + err = snd_bcm2835_create(g_card, pdev, &chip);
  2118. + if (err < 0) {
  2119. + dev_err(&pdev->dev, "Failed to create bcm2835 chip\n");
  2120. + goto out_bcm2835_create;
  2121. + }
  2122. +
  2123. + g_chip = chip;
  2124. + err = snd_bcm2835_new_pcm(chip);
  2125. + if (err < 0) {
  2126. + dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n");
  2127. + goto out_bcm2835_new_pcm;
  2128. + }
  2129. +
  2130. + err = snd_bcm2835_new_spdif_pcm(chip);
  2131. + if (err < 0) {
  2132. + dev_err(&pdev->dev, "Failed to create new BCM2835 spdif pcm device\n");
  2133. + goto out_bcm2835_new_spdif;
  2134. + }
  2135. +
  2136. + err = snd_bcm2835_new_ctl(chip);
  2137. + if (err < 0) {
  2138. + dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n");
  2139. + goto out_bcm2835_new_ctl;
  2140. + }
  2141. +
  2142. +add_register_map:
  2143. + card = g_card;
  2144. + chip = g_chip;
  2145. +
  2146. + BUG_ON(!(card && chip));
  2147. +
  2148. + chip->avail_substreams |= (1 << dev);
  2149. + chip->pdev[dev] = pdev;
  2150. +
  2151. + if (dev == 0) {
  2152. + err = snd_card_register(card);
  2153. + if (err < 0) {
  2154. + dev_err(&pdev->dev,
  2155. + "Failed to register bcm2835 ALSA card \n");
  2156. + goto out_card_register;
  2157. + }
  2158. + platform_set_drvdata(pdev, card);
  2159. + audio_info("bcm2835 ALSA card created!\n");
  2160. + } else {
  2161. + audio_info("bcm2835 ALSA chip created!\n");
  2162. + platform_set_drvdata(pdev, (void *)dev);
  2163. + }
  2164. +
  2165. + dev++;
  2166. +
  2167. + return 0;
  2168. +
  2169. +out_card_register:
  2170. +out_bcm2835_new_ctl:
  2171. +out_bcm2835_new_spdif:
  2172. +out_bcm2835_new_pcm:
  2173. +out_bcm2835_create:
  2174. + BUG_ON(!g_card);
  2175. + if (snd_card_free(g_card))
  2176. + dev_err(&pdev->dev, "Failed to free Registered alsa card\n");
  2177. + g_card = NULL;
  2178. +out:
  2179. + dev = SNDRV_CARDS; /* stop more avail_substreams from being probed */
  2180. + dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n");
  2181. + return err;
  2182. +}
  2183. +
  2184. +static int snd_bcm2835_alsa_remove(struct platform_device *pdev)
  2185. +{
  2186. + uint32_t idx;
  2187. + void *drv_data;
  2188. +
  2189. + drv_data = platform_get_drvdata(pdev);
  2190. +
  2191. + if (drv_data == (void *)g_card) {
  2192. + /* This is the card device */
  2193. + snd_card_free((struct snd_card *)drv_data);
  2194. + g_card = NULL;
  2195. + g_chip = NULL;
  2196. + } else {
  2197. + idx = (uint32_t) drv_data;
  2198. + if (g_card != NULL) {
  2199. + BUG_ON(!g_chip);
  2200. + /* We pass chip device numbers in audio ipc devices
  2201. + * other than the one we registered our card with
  2202. + */
  2203. + idx = (uint32_t) drv_data;
  2204. + BUG_ON(!idx || idx > MAX_SUBSTREAMS);
  2205. + g_chip->avail_substreams &= ~(1 << idx);
  2206. + /* There should be atleast one substream registered
  2207. + * after we are done here, as it wil be removed when
  2208. + * the *remove* is called for the card device
  2209. + */
  2210. + BUG_ON(!g_chip->avail_substreams);
  2211. + }
  2212. + }
  2213. +
  2214. + platform_set_drvdata(pdev, NULL);
  2215. +
  2216. + return 0;
  2217. +}
  2218. +
  2219. +#ifdef CONFIG_PM
  2220. +static int snd_bcm2835_alsa_suspend(struct platform_device *pdev,
  2221. + pm_message_t state)
  2222. +{
  2223. + return 0;
  2224. +}
  2225. +
  2226. +static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
  2227. +{
  2228. + return 0;
  2229. +}
  2230. +
  2231. +#endif
  2232. +
  2233. +static struct platform_driver bcm2835_alsa0_driver = {
  2234. + .probe = snd_bcm2835_alsa_probe,
  2235. + .remove = snd_bcm2835_alsa_remove,
  2236. +#ifdef CONFIG_PM
  2237. + .suspend = snd_bcm2835_alsa_suspend,
  2238. + .resume = snd_bcm2835_alsa_resume,
  2239. +#endif
  2240. + .driver = {
  2241. + .name = "bcm2835_AUD0",
  2242. + .owner = THIS_MODULE,
  2243. + },
  2244. +};
  2245. +
  2246. +static struct platform_driver bcm2835_alsa1_driver = {
  2247. + .probe = snd_bcm2835_alsa_probe,
  2248. + .remove = snd_bcm2835_alsa_remove,
  2249. +#ifdef CONFIG_PM
  2250. + .suspend = snd_bcm2835_alsa_suspend,
  2251. + .resume = snd_bcm2835_alsa_resume,
  2252. +#endif
  2253. + .driver = {
  2254. + .name = "bcm2835_AUD1",
  2255. + .owner = THIS_MODULE,
  2256. + },
  2257. +};
  2258. +
  2259. +static struct platform_driver bcm2835_alsa2_driver = {
  2260. + .probe = snd_bcm2835_alsa_probe,
  2261. + .remove = snd_bcm2835_alsa_remove,
  2262. +#ifdef CONFIG_PM
  2263. + .suspend = snd_bcm2835_alsa_suspend,
  2264. + .resume = snd_bcm2835_alsa_resume,
  2265. +#endif
  2266. + .driver = {
  2267. + .name = "bcm2835_AUD2",
  2268. + .owner = THIS_MODULE,
  2269. + },
  2270. +};
  2271. +
  2272. +static struct platform_driver bcm2835_alsa3_driver = {
  2273. + .probe = snd_bcm2835_alsa_probe,
  2274. + .remove = snd_bcm2835_alsa_remove,
  2275. +#ifdef CONFIG_PM
  2276. + .suspend = snd_bcm2835_alsa_suspend,
  2277. + .resume = snd_bcm2835_alsa_resume,
  2278. +#endif
  2279. + .driver = {
  2280. + .name = "bcm2835_AUD3",
  2281. + .owner = THIS_MODULE,
  2282. + },
  2283. +};
  2284. +
  2285. +static struct platform_driver bcm2835_alsa4_driver = {
  2286. + .probe = snd_bcm2835_alsa_probe,
  2287. + .remove = snd_bcm2835_alsa_remove,
  2288. +#ifdef CONFIG_PM
  2289. + .suspend = snd_bcm2835_alsa_suspend,
  2290. + .resume = snd_bcm2835_alsa_resume,
  2291. +#endif
  2292. + .driver = {
  2293. + .name = "bcm2835_AUD4",
  2294. + .owner = THIS_MODULE,
  2295. + },
  2296. +};
  2297. +
  2298. +static struct platform_driver bcm2835_alsa5_driver = {
  2299. + .probe = snd_bcm2835_alsa_probe,
  2300. + .remove = snd_bcm2835_alsa_remove,
  2301. +#ifdef CONFIG_PM
  2302. + .suspend = snd_bcm2835_alsa_suspend,
  2303. + .resume = snd_bcm2835_alsa_resume,
  2304. +#endif
  2305. + .driver = {
  2306. + .name = "bcm2835_AUD5",
  2307. + .owner = THIS_MODULE,
  2308. + },
  2309. +};
  2310. +
  2311. +static struct platform_driver bcm2835_alsa6_driver = {
  2312. + .probe = snd_bcm2835_alsa_probe,
  2313. + .remove = snd_bcm2835_alsa_remove,
  2314. +#ifdef CONFIG_PM
  2315. + .suspend = snd_bcm2835_alsa_suspend,
  2316. + .resume = snd_bcm2835_alsa_resume,
  2317. +#endif
  2318. + .driver = {
  2319. + .name = "bcm2835_AUD6",
  2320. + .owner = THIS_MODULE,
  2321. + },
  2322. +};
  2323. +
  2324. +static struct platform_driver bcm2835_alsa7_driver = {
  2325. + .probe = snd_bcm2835_alsa_probe,
  2326. + .remove = snd_bcm2835_alsa_remove,
  2327. +#ifdef CONFIG_PM
  2328. + .suspend = snd_bcm2835_alsa_suspend,
  2329. + .resume = snd_bcm2835_alsa_resume,
  2330. +#endif
  2331. + .driver = {
  2332. + .name = "bcm2835_AUD7",
  2333. + .owner = THIS_MODULE,
  2334. + },
  2335. +};
  2336. +
  2337. +static int bcm2835_alsa_device_init(void)
  2338. +{
  2339. + int err;
  2340. + err = platform_driver_register(&bcm2835_alsa0_driver);
  2341. + if (err) {
  2342. + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
  2343. + goto out;
  2344. + }
  2345. +
  2346. + err = platform_driver_register(&bcm2835_alsa1_driver);
  2347. + if (err) {
  2348. + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
  2349. + goto unregister_0;
  2350. + }
  2351. +
  2352. + err = platform_driver_register(&bcm2835_alsa2_driver);
  2353. + if (err) {
  2354. + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
  2355. + goto unregister_1;
  2356. + }
  2357. +
  2358. + err = platform_driver_register(&bcm2835_alsa3_driver);
  2359. + if (err) {
  2360. + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
  2361. + goto unregister_2;
  2362. + }
  2363. +
  2364. + err = platform_driver_register(&bcm2835_alsa4_driver);
  2365. + if (err) {
  2366. + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
  2367. + goto unregister_3;
  2368. + }
  2369. +
  2370. + err = platform_driver_register(&bcm2835_alsa5_driver);
  2371. + if (err) {
  2372. + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
  2373. + goto unregister_4;
  2374. + }
  2375. +
  2376. + err = platform_driver_register(&bcm2835_alsa6_driver);
  2377. + if (err) {
  2378. + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
  2379. + goto unregister_5;
  2380. + }
  2381. +
  2382. + err = platform_driver_register(&bcm2835_alsa7_driver);
  2383. + if (err) {
  2384. + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
  2385. + goto unregister_6;
  2386. + }
  2387. +
  2388. + return 0;
  2389. +
  2390. +unregister_6:
  2391. + platform_driver_unregister(&bcm2835_alsa6_driver);
  2392. +unregister_5:
  2393. + platform_driver_unregister(&bcm2835_alsa5_driver);
  2394. +unregister_4:
  2395. + platform_driver_unregister(&bcm2835_alsa4_driver);
  2396. +unregister_3:
  2397. + platform_driver_unregister(&bcm2835_alsa3_driver);
  2398. +unregister_2:
  2399. + platform_driver_unregister(&bcm2835_alsa2_driver);
  2400. +unregister_1:
  2401. + platform_driver_unregister(&bcm2835_alsa1_driver);
  2402. +unregister_0:
  2403. + platform_driver_unregister(&bcm2835_alsa0_driver);
  2404. +out:
  2405. + return err;
  2406. +}
  2407. +
  2408. +static void bcm2835_alsa_device_exit(void)
  2409. +{
  2410. + platform_driver_unregister(&bcm2835_alsa0_driver);
  2411. + platform_driver_unregister(&bcm2835_alsa1_driver);
  2412. + platform_driver_unregister(&bcm2835_alsa2_driver);
  2413. + platform_driver_unregister(&bcm2835_alsa3_driver);
  2414. + platform_driver_unregister(&bcm2835_alsa4_driver);
  2415. + platform_driver_unregister(&bcm2835_alsa5_driver);
  2416. + platform_driver_unregister(&bcm2835_alsa6_driver);
  2417. + platform_driver_unregister(&bcm2835_alsa7_driver);
  2418. +}
  2419. +
  2420. +late_initcall(bcm2835_alsa_device_init);
  2421. +module_exit(bcm2835_alsa_device_exit);
  2422. +
  2423. +MODULE_AUTHOR("Dom Cobley");
  2424. +MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
  2425. +MODULE_LICENSE("GPL");
  2426. +MODULE_ALIAS("platform:bcm2835_alsa");
  2427. --- /dev/null
  2428. +++ b/sound/arm/bcm2835.h
  2429. @@ -0,0 +1,167 @@
  2430. +/*****************************************************************************
  2431. +* Copyright 2011 Broadcom Corporation. All rights reserved.
  2432. +*
  2433. +* Unless you and Broadcom execute a separate written software license
  2434. +* agreement governing use of this software, this software is licensed to you
  2435. +* under the terms of the GNU General Public License version 2, available at
  2436. +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
  2437. +*
  2438. +* Notwithstanding the above, under no circumstances may you combine this
  2439. +* software in any way with any other Broadcom software provided under a
  2440. +* license other than the GPL, without Broadcom's express prior written
  2441. +* consent.
  2442. +*****************************************************************************/
  2443. +
  2444. +#ifndef __SOUND_ARM_BCM2835_H
  2445. +#define __SOUND_ARM_BCM2835_H
  2446. +
  2447. +#include <linux/device.h>
  2448. +#include <linux/list.h>
  2449. +#include <linux/interrupt.h>
  2450. +#include <linux/wait.h>
  2451. +#include <sound/core.h>
  2452. +#include <sound/initval.h>
  2453. +#include <sound/pcm.h>
  2454. +#include <sound/pcm_params.h>
  2455. +#include <sound/pcm-indirect.h>
  2456. +#include <linux/workqueue.h>
  2457. +
  2458. +/*
  2459. +#define AUDIO_DEBUG_ENABLE
  2460. +#define AUDIO_VERBOSE_DEBUG_ENABLE
  2461. +*/
  2462. +
  2463. +/* Debug macros */
  2464. +
  2465. +#ifdef AUDIO_DEBUG_ENABLE
  2466. +#ifdef AUDIO_VERBOSE_DEBUG_ENABLE
  2467. +
  2468. +#define audio_debug(fmt, arg...) \
  2469. + printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
  2470. +
  2471. +#define audio_info(fmt, arg...) \
  2472. + printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
  2473. +
  2474. +#else
  2475. +
  2476. +#define audio_debug(fmt, arg...)
  2477. +
  2478. +#define audio_info(fmt, arg...)
  2479. +
  2480. +#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */
  2481. +
  2482. +#else
  2483. +
  2484. +#define audio_debug(fmt, arg...)
  2485. +
  2486. +#define audio_info(fmt, arg...)
  2487. +
  2488. +#endif /* AUDIO_DEBUG_ENABLE */
  2489. +
  2490. +#define audio_error(fmt, arg...) \
  2491. + printk(KERN_ERR"%s:%d " fmt, __func__, __LINE__, ##arg)
  2492. +
  2493. +#define audio_warning(fmt, arg...) \
  2494. + printk(KERN_WARNING"%s:%d " fmt, __func__, __LINE__, ##arg)
  2495. +
  2496. +#define audio_alert(fmt, arg...) \
  2497. + printk(KERN_ALERT"%s:%d " fmt, __func__, __LINE__, ##arg)
  2498. +
  2499. +#define MAX_SUBSTREAMS (8)
  2500. +#define AVAIL_SUBSTREAMS_MASK (0xff)
  2501. +enum {
  2502. + CTRL_VOL_MUTE,
  2503. + CTRL_VOL_UNMUTE
  2504. +};
  2505. +
  2506. +/* macros for alsa2chip and chip2alsa, instead of functions */
  2507. +
  2508. +#define alsa2chip(vol) (uint)(-((vol << 8) / 100)) /* convert alsa to chip volume (defined as macro rather than function call) */
  2509. +#define chip2alsa(vol) -((vol * 100) >> 8) /* convert chip to alsa volume */
  2510. +
  2511. +/* Some constants for values .. */
  2512. +typedef enum {
  2513. + AUDIO_DEST_AUTO = 0,
  2514. + AUDIO_DEST_HEADPHONES = 1,
  2515. + AUDIO_DEST_HDMI = 2,
  2516. + AUDIO_DEST_MAX,
  2517. +} SND_BCM2835_ROUTE_T;
  2518. +
  2519. +typedef enum {
  2520. + PCM_PLAYBACK_VOLUME,
  2521. + PCM_PLAYBACK_MUTE,
  2522. + PCM_PLAYBACK_DEVICE,
  2523. +} SND_BCM2835_CTRL_T;
  2524. +
  2525. +/* definition of the chip-specific record */
  2526. +typedef struct bcm2835_chip {
  2527. + struct snd_card *card;
  2528. + struct snd_pcm *pcm;
  2529. + struct snd_pcm *pcm_spdif;
  2530. + /* Bitmat for valid reg_base and irq numbers */
  2531. + uint32_t avail_substreams;
  2532. + struct platform_device *pdev[MAX_SUBSTREAMS];
  2533. + struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
  2534. +
  2535. + int volume;
  2536. + int old_volume; /* stores the volume value whist muted */
  2537. + int dest;
  2538. + int mute;
  2539. +
  2540. + unsigned int opened;
  2541. + unsigned int spdif_status;
  2542. + struct mutex audio_mutex;
  2543. +} bcm2835_chip_t;
  2544. +
  2545. +typedef struct bcm2835_alsa_stream {
  2546. + bcm2835_chip_t *chip;
  2547. + struct snd_pcm_substream *substream;
  2548. + struct snd_pcm_indirect pcm_indirect;
  2549. +
  2550. + struct semaphore buffers_update_sem;
  2551. + struct semaphore control_sem;
  2552. + spinlock_t lock;
  2553. + volatile uint32_t control;
  2554. + volatile uint32_t status;
  2555. +
  2556. + int open;
  2557. + int running;
  2558. + int draining;
  2559. +
  2560. + int channels;
  2561. + int params_rate;
  2562. + int pcm_format_width;
  2563. +
  2564. + unsigned int pos;
  2565. + unsigned int buffer_size;
  2566. + unsigned int period_size;
  2567. +
  2568. + uint32_t enable_fifo_irq;
  2569. + irq_handler_t fifo_irq_handler;
  2570. +
  2571. + atomic_t retrieved;
  2572. + struct opaque_AUDIO_INSTANCE_T *instance;
  2573. + struct workqueue_struct *my_wq;
  2574. + int idx;
  2575. +} bcm2835_alsa_stream_t;
  2576. +
  2577. +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip);
  2578. +int snd_bcm2835_new_pcm(bcm2835_chip_t * chip);
  2579. +int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip);
  2580. +
  2581. +int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream);
  2582. +int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream);
  2583. +int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
  2584. + uint32_t channels, uint32_t samplerate,
  2585. + uint32_t bps);
  2586. +int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream);
  2587. +int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream);
  2588. +int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream);
  2589. +int bcm2835_audio_set_ctls(bcm2835_chip_t * chip);
  2590. +int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
  2591. + void *src);
  2592. +uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream);
  2593. +void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream);
  2594. +void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream);
  2595. +
  2596. +#endif /* __SOUND_ARM_BCM2835_H */
  2597. --- /dev/null
  2598. +++ b/sound/arm/vc_vchi_audioserv_defs.h
  2599. @@ -0,0 +1,116 @@
  2600. +/*****************************************************************************
  2601. +* Copyright 2011 Broadcom Corporation. All rights reserved.
  2602. +*
  2603. +* Unless you and Broadcom execute a separate written software license
  2604. +* agreement governing use of this software, this software is licensed to you
  2605. +* under the terms of the GNU General Public License version 2, available at
  2606. +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
  2607. +*
  2608. +* Notwithstanding the above, under no circumstances may you combine this
  2609. +* software in any way with any other Broadcom software provided under a
  2610. +* license other than the GPL, without Broadcom's express prior written
  2611. +* consent.
  2612. +*****************************************************************************/
  2613. +
  2614. +#ifndef _VC_AUDIO_DEFS_H_
  2615. +#define _VC_AUDIO_DEFS_H_
  2616. +
  2617. +#define VC_AUDIOSERV_MIN_VER 1
  2618. +#define VC_AUDIOSERV_VER 2
  2619. +
  2620. +// FourCC code used for VCHI connection
  2621. +#define VC_AUDIO_SERVER_NAME MAKE_FOURCC("AUDS")
  2622. +
  2623. +// Maximum message length
  2624. +#define VC_AUDIO_MAX_MSG_LEN (sizeof( VC_AUDIO_MSG_T ))
  2625. +
  2626. +// List of screens that are currently supported
  2627. +// All message types supported for HOST->VC direction
  2628. +typedef enum {
  2629. + VC_AUDIO_MSG_TYPE_RESULT, // Generic result
  2630. + VC_AUDIO_MSG_TYPE_COMPLETE, // Generic result
  2631. + VC_AUDIO_MSG_TYPE_CONFIG, // Configure audio
  2632. + VC_AUDIO_MSG_TYPE_CONTROL, // Configure audio
  2633. + VC_AUDIO_MSG_TYPE_OPEN, // Configure audio
  2634. + VC_AUDIO_MSG_TYPE_CLOSE, // Configure audio
  2635. + VC_AUDIO_MSG_TYPE_START, // Configure audio
  2636. + VC_AUDIO_MSG_TYPE_STOP, // Configure audio
  2637. + VC_AUDIO_MSG_TYPE_WRITE, // Configure audio
  2638. + VC_AUDIO_MSG_TYPE_MAX
  2639. +} VC_AUDIO_MSG_TYPE;
  2640. +
  2641. +// configure the audio
  2642. +typedef struct {
  2643. + uint32_t channels;
  2644. + uint32_t samplerate;
  2645. + uint32_t bps;
  2646. +
  2647. +} VC_AUDIO_CONFIG_T;
  2648. +
  2649. +typedef struct {
  2650. + uint32_t volume;
  2651. + uint32_t dest;
  2652. +
  2653. +} VC_AUDIO_CONTROL_T;
  2654. +
  2655. +// audio
  2656. +typedef struct {
  2657. + uint32_t dummy;
  2658. +
  2659. +} VC_AUDIO_OPEN_T;
  2660. +
  2661. +// audio
  2662. +typedef struct {
  2663. + uint32_t dummy;
  2664. +
  2665. +} VC_AUDIO_CLOSE_T;
  2666. +// audio
  2667. +typedef struct {
  2668. + uint32_t dummy;
  2669. +
  2670. +} VC_AUDIO_START_T;
  2671. +// audio
  2672. +typedef struct {
  2673. + uint32_t draining;
  2674. +
  2675. +} VC_AUDIO_STOP_T;
  2676. +
  2677. +// configure the write audio samples
  2678. +typedef struct {
  2679. + uint32_t count; // in bytes
  2680. + void *callback;
  2681. + void *cookie;
  2682. + uint16_t silence;
  2683. + uint16_t max_packet;
  2684. +} VC_AUDIO_WRITE_T;
  2685. +
  2686. +// Generic result for a request (VC->HOST)
  2687. +typedef struct {
  2688. + int32_t success; // Success value
  2689. +
  2690. +} VC_AUDIO_RESULT_T;
  2691. +
  2692. +// Generic result for a request (VC->HOST)
  2693. +typedef struct {
  2694. + int32_t count; // Success value
  2695. + void *callback;
  2696. + void *cookie;
  2697. +} VC_AUDIO_COMPLETE_T;
  2698. +
  2699. +// Message header for all messages in HOST->VC direction
  2700. +typedef struct {
  2701. + int32_t type; // Message type (VC_AUDIO_MSG_TYPE)
  2702. + union {
  2703. + VC_AUDIO_CONFIG_T config;
  2704. + VC_AUDIO_CONTROL_T control;
  2705. + VC_AUDIO_OPEN_T open;
  2706. + VC_AUDIO_CLOSE_T close;
  2707. + VC_AUDIO_START_T start;
  2708. + VC_AUDIO_STOP_T stop;
  2709. + VC_AUDIO_WRITE_T write;
  2710. + VC_AUDIO_RESULT_T result;
  2711. + VC_AUDIO_COMPLETE_T complete;
  2712. + } u;
  2713. +} VC_AUDIO_MSG_T;
  2714. +
  2715. +#endif // _VC_AUDIO_DEFS_H_