devaudio.c 21 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258
  1. /*
  2. * SB 16 driver
  3. */
  4. #include "u.h"
  5. #include "../port/lib.h"
  6. #include "mem.h"
  7. #include "dat.h"
  8. #include "fns.h"
  9. #include "../port/error.h"
  10. #include "io.h"
  11. #include "audio.h"
  12. typedef struct AQueue AQueue;
  13. typedef struct Buf Buf;
  14. enum
  15. {
  16. Qdir = 0,
  17. Qaudio,
  18. Qvolume,
  19. Qstatus,
  20. Fmono = 1,
  21. Fin = 2,
  22. Fout = 4,
  23. Aclosed = 0,
  24. Aread,
  25. Awrite,
  26. Vaudio = 0,
  27. Vsynth,
  28. Vcd,
  29. Vline,
  30. Vmic,
  31. Vspeaker,
  32. Vtreb,
  33. Vbass,
  34. Vspeed,
  35. Nvol,
  36. Speed = 44100,
  37. Ncmd = 50, /* max volume command words */
  38. };
  39. Dirtab
  40. audiodir[] =
  41. {
  42. ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
  43. "audio", {Qaudio}, 0, 0666,
  44. "volume", {Qvolume}, 0, 0666,
  45. "audiostat",{Qstatus}, 0, 0444,
  46. };
  47. struct Buf
  48. {
  49. uchar* virt;
  50. ulong phys;
  51. Buf* next;
  52. };
  53. struct AQueue
  54. {
  55. Lock;
  56. Buf* first;
  57. Buf* last;
  58. };
  59. static struct
  60. {
  61. QLock;
  62. Rendez vous;
  63. int buffered; /* number of bytes en route */
  64. int bufinit; /* boolean if buffers allocated */
  65. int curcount; /* how much data in current buffer */
  66. int active; /* boolean dma running */
  67. int intr; /* boolean an interrupt has happened */
  68. int amode; /* Aclosed/Aread/Awrite for /audio */
  69. int rivol[Nvol]; /* right/left input/output volumes */
  70. int livol[Nvol];
  71. int rovol[Nvol];
  72. int lovol[Nvol];
  73. int major; /* SB16 major version number (sb 4) */
  74. int minor; /* SB16 minor version number */
  75. ulong totcount; /* how many bytes processed since open */
  76. vlong tottime; /* time at which totcount bytes were processed */
  77. Buf buf[Nbuf]; /* buffers and queues */
  78. AQueue empty;
  79. AQueue full;
  80. Buf* current;
  81. Buf* filling;
  82. } audio;
  83. static struct
  84. {
  85. char* name;
  86. int flag;
  87. int ilval; /* initial values */
  88. int irval;
  89. } volumes[] =
  90. {
  91. [Vaudio] "audio", Fout, 50, 50,
  92. [Vsynth] "synth", Fin|Fout, 0, 0,
  93. [Vcd] "cd", Fin|Fout, 0, 0,
  94. [Vline] "line", Fin|Fout, 0, 0,
  95. [Vmic] "mic", Fin|Fout|Fmono, 0, 0,
  96. [Vspeaker] "speaker", Fout|Fmono, 0, 0,
  97. [Vtreb] "treb", Fout, 50, 50,
  98. [Vbass] "bass", Fout, 50, 50,
  99. [Vspeed] "speed", Fin|Fout|Fmono, Speed, Speed,
  100. 0
  101. };
  102. static struct
  103. {
  104. Lock;
  105. int reset; /* io ports to the sound blaster */
  106. int read;
  107. int write;
  108. int wstatus;
  109. int rstatus;
  110. int mixaddr;
  111. int mixdata;
  112. int clri8;
  113. int clri16;
  114. int clri401;
  115. int dma;
  116. void (*startdma)(void);
  117. void (*intr)(void);
  118. } blaster;
  119. static void swab(uchar*);
  120. static char Emajor[] = "soundblaster not responding/wrong version";
  121. static char Emode[] = "illegal open mode";
  122. static char Evolume[] = "illegal volume specifier";
  123. static int
  124. sbcmd(int val)
  125. {
  126. int i, s;
  127. for(i=1<<16; i!=0; i--) {
  128. s = inb(blaster.wstatus);
  129. if((s & 0x80) == 0) {
  130. outb(blaster.write, val);
  131. return 0;
  132. }
  133. }
  134. /* print("#A: sbcmd (0x%.2x) timeout\n", val); /**/
  135. return 1;
  136. }
  137. static int
  138. sbread(void)
  139. {
  140. int i, s;
  141. for(i=1<<16; i!=0; i--) {
  142. s = inb(blaster.rstatus);
  143. if((s & 0x80) != 0) {
  144. return inb(blaster.read);
  145. }
  146. }
  147. /* print("#A: sbread did not respond\n"); /**/
  148. return -1;
  149. }
  150. static int
  151. ess1688w(int reg, int val)
  152. {
  153. if(sbcmd(reg) || sbcmd(val))
  154. return 1;
  155. return 0;
  156. }
  157. static int
  158. ess1688r(int reg)
  159. {
  160. if(sbcmd(0xC0) || sbcmd(reg))
  161. return -1;
  162. return sbread();
  163. }
  164. static int
  165. mxcmd(int addr, int val)
  166. {
  167. outb(blaster.mixaddr, addr);
  168. outb(blaster.mixdata, val);
  169. return 1;
  170. }
  171. static int
  172. mxread(int addr)
  173. {
  174. int s;
  175. outb(blaster.mixaddr, addr);
  176. s = inb(blaster.mixdata);
  177. return s;
  178. }
  179. static void
  180. mxcmds(int s, int v)
  181. {
  182. if(v > 100)
  183. v = 100;
  184. if(v < 0)
  185. v = 0;
  186. mxcmd(s, (v*255)/100);
  187. }
  188. static void
  189. mxcmdt(int s, int v)
  190. {
  191. if(v > 100)
  192. v = 100;
  193. if(v <= 0)
  194. mxcmd(s, 0);
  195. else
  196. mxcmd(s, 255-100+v);
  197. }
  198. static void
  199. mxcmdu(int s, int v)
  200. {
  201. if(v > 100)
  202. v = 100;
  203. if(v <= 0)
  204. v = 0;
  205. mxcmd(s, 128-50+v);
  206. }
  207. static void
  208. mxvolume(void)
  209. {
  210. int *left, *right;
  211. int source;
  212. if(audio.amode == Aread){
  213. left = audio.livol;
  214. right = audio.rivol;
  215. }else{
  216. left = audio.lovol;
  217. right = audio.rovol;
  218. }
  219. ilock(&blaster);
  220. mxcmd(0x30, 255); /* left master */
  221. mxcmd(0x31, 255); /* right master */
  222. mxcmd(0x3f, 0); /* left igain */
  223. mxcmd(0x40, 0); /* right igain */
  224. mxcmd(0x41, 0); /* left ogain */
  225. mxcmd(0x42, 0); /* right ogain */
  226. mxcmds(0x32, left[Vaudio]);
  227. mxcmds(0x33, right[Vaudio]);
  228. mxcmds(0x34, left[Vsynth]);
  229. mxcmds(0x35, right[Vsynth]);
  230. mxcmds(0x36, left[Vcd]);
  231. mxcmds(0x37, right[Vcd]);
  232. mxcmds(0x38, left[Vline]);
  233. mxcmds(0x39, right[Vline]);
  234. mxcmds(0x3a, left[Vmic]);
  235. mxcmds(0x3b, left[Vspeaker]);
  236. mxcmdu(0x44, left[Vtreb]);
  237. mxcmdu(0x45, right[Vtreb]);
  238. mxcmdu(0x46, left[Vbass]);
  239. mxcmdu(0x47, right[Vbass]);
  240. source = 0;
  241. if(left[Vsynth])
  242. source |= 1<<6;
  243. if(right[Vsynth])
  244. source |= 1<<5;
  245. if(left[Vaudio])
  246. source |= 1<<4;
  247. if(right[Vaudio])
  248. source |= 1<<3;
  249. if(left[Vcd])
  250. source |= 1<<2;
  251. if(right[Vcd])
  252. source |= 1<<1;
  253. if(left[Vmic])
  254. source |= 1<<0;
  255. if(audio.amode == Aread)
  256. mxcmd(0x3c, 0); /* output switch */
  257. else
  258. mxcmd(0x3c, source);
  259. mxcmd(0x3d, source); /* input left switch */
  260. mxcmd(0x3e, source); /* input right switch */
  261. iunlock(&blaster);
  262. }
  263. static Buf*
  264. getbuf(AQueue *q)
  265. {
  266. Buf *b;
  267. ilock(q);
  268. b = q->first;
  269. if(b)
  270. q->first = b->next;
  271. iunlock(q);
  272. return b;
  273. }
  274. static void
  275. putbuf(AQueue *q, Buf *b)
  276. {
  277. ilock(q);
  278. b->next = 0;
  279. if(q->first)
  280. q->last->next = b;
  281. else
  282. q->first = b;
  283. q->last = b;
  284. iunlock(q);
  285. }
  286. /*
  287. * move the dma to the next buffer
  288. */
  289. static void
  290. contindma(void)
  291. {
  292. Buf *b;
  293. if(!audio.active)
  294. goto shutdown;
  295. b = audio.current;
  296. if(b){
  297. audio.totcount += Bufsize;
  298. audio.tottime = todget(nil);
  299. }
  300. if(audio.amode == Aread) {
  301. if(b){
  302. putbuf(&audio.full, b);
  303. audio.buffered += Bufsize;
  304. }
  305. b = getbuf(&audio.empty);
  306. } else {
  307. if(b){
  308. putbuf(&audio.empty, b);
  309. audio.buffered -= Bufsize;
  310. }
  311. b = getbuf(&audio.full);
  312. }
  313. audio.current = b;
  314. if(b == 0)
  315. goto shutdown;
  316. if(dmasetup(blaster.dma, b->virt, Bufsize, audio.amode == Aread) >= 0)
  317. return;
  318. print("#A: dmasetup fail\n");
  319. putbuf(&audio.empty, b);
  320. shutdown:
  321. dmaend(blaster.dma);
  322. sbcmd(0xd9); /* exit at end of count */
  323. sbcmd(0xd5); /* pause */
  324. audio.curcount = 0;
  325. audio.active = 0;
  326. }
  327. /*
  328. * cause sb to get an interrupt per buffer.
  329. * start first dma
  330. */
  331. static void
  332. sb16startdma(void)
  333. {
  334. ulong count;
  335. int speed;
  336. ilock(&blaster);
  337. dmaend(blaster.dma);
  338. if(audio.amode == Aread) {
  339. sbcmd(0x42); /* input sampling rate */
  340. speed = audio.livol[Vspeed];
  341. } else {
  342. sbcmd(0x41); /* output sampling rate */
  343. speed = audio.lovol[Vspeed];
  344. }
  345. sbcmd(speed>>8);
  346. sbcmd(speed);
  347. count = (Bufsize >> 1) - 1;
  348. if(audio.amode == Aread)
  349. sbcmd(0xbe); /* A/D, autoinit */
  350. else
  351. sbcmd(0xb6); /* D/A, autoinit */
  352. sbcmd(0x30); /* stereo, 16 bit */
  353. sbcmd(count);
  354. sbcmd(count>>8);
  355. audio.active = 1;
  356. contindma();
  357. iunlock(&blaster);
  358. }
  359. static int
  360. ess1688reset(void)
  361. {
  362. int i;
  363. outb(blaster.reset, 3);
  364. delay(1); /* >3 υs */
  365. outb(blaster.reset, 0);
  366. delay(1);
  367. i = sbread();
  368. if(i != 0xAA) {
  369. print("#A: no response 0x%.2x\n", i);
  370. return 1;
  371. }
  372. if(sbcmd(0xC6)){ /* extended mode */
  373. print("#A: barf 3\n");
  374. return 1;
  375. }
  376. return 0;
  377. }
  378. static void
  379. ess1688startdma(void)
  380. {
  381. ulong count;
  382. int speed, x;
  383. ilock(&blaster);
  384. dmaend(blaster.dma);
  385. if(audio.amode == Awrite)
  386. ess1688reset();
  387. if(audio.amode == Aread)
  388. sbcmd(0xD3); /* speaker off */
  389. /*
  390. * Set the speed.
  391. */
  392. if(audio.amode == Aread)
  393. speed = audio.livol[Vspeed];
  394. else
  395. speed = audio.lovol[Vspeed];
  396. if(speed < 4000)
  397. speed = 4000;
  398. else if(speed > 48000)
  399. speed = 48000;
  400. if(speed > 22000)
  401. x = 0x80|(256-(795500+speed/2)/speed);
  402. else
  403. x = 128-(397700+speed/2)/speed;
  404. ess1688w(0xA1, x & 0xFF);
  405. speed = (speed * 9) / 20;
  406. x = 256 - 7160000 / (speed * 82);
  407. ess1688w(0xA2, x & 0xFF);
  408. if(audio.amode == Aread)
  409. ess1688w(0xB8, 0x0E); /* A/D, autoinit */
  410. else
  411. ess1688w(0xB8, 0x04); /* D/A, autoinit */
  412. x = ess1688r(0xA8) & ~0x03;
  413. ess1688w(0xA8, x|0x01); /* 2 channels */
  414. ess1688w(0xB9, 2); /* demand mode, 4 bytes per request */
  415. if(audio.amode == Awrite)
  416. ess1688w(0xB6, 0);
  417. ess1688w(0xB7, 0x71);
  418. ess1688w(0xB7, 0xBC);
  419. x = ess1688r(0xB1) & 0x0F;
  420. ess1688w(0xB1, x|0x50);
  421. x = ess1688r(0xB2) & 0x0F;
  422. ess1688w(0xB2, x|0x50);
  423. if(audio.amode == Awrite)
  424. sbcmd(0xD1); /* speaker on */
  425. count = -Bufsize;
  426. ess1688w(0xA4, count & 0xFF);
  427. ess1688w(0xA5, (count>>8) & 0xFF);
  428. x = ess1688r(0xB8);
  429. ess1688w(0xB8, x|0x05);
  430. audio.active = 1;
  431. contindma();
  432. iunlock(&blaster);
  433. }
  434. /*
  435. * if audio is stopped,
  436. * start it up again.
  437. */
  438. static void
  439. pokeaudio(void)
  440. {
  441. if(!audio.active)
  442. blaster.startdma();
  443. }
  444. static void
  445. sb16intr(void)
  446. {
  447. int stat, dummy;
  448. stat = mxread(0x82) & 7; /* get irq status */
  449. if(stat) {
  450. dummy = 0;
  451. if(stat & 2) {
  452. ilock(&blaster);
  453. dummy = inb(blaster.clri16);
  454. contindma();
  455. iunlock(&blaster);
  456. audio.intr = 1;
  457. wakeup(&audio.vous);
  458. }
  459. if(stat & 1) {
  460. dummy = inb(blaster.clri8);
  461. }
  462. if(stat & 4) {
  463. dummy = inb(blaster.clri401);
  464. }
  465. USED(dummy);
  466. }
  467. }
  468. static void
  469. ess1688intr(void)
  470. {
  471. int dummy;
  472. if(audio.active){
  473. ilock(&blaster);
  474. contindma();
  475. dummy = inb(blaster.clri8);
  476. iunlock(&blaster);
  477. audio.intr = 1;
  478. wakeup(&audio.vous);
  479. USED(dummy);
  480. }
  481. else
  482. print("#A: unexpected ess1688 interrupt\n");
  483. }
  484. void
  485. audiosbintr(void)
  486. {
  487. /*
  488. * Carrera interrupt interface.
  489. */
  490. blaster.intr();
  491. }
  492. static void
  493. pcaudiosbintr(Ureg*, void*)
  494. {
  495. /*
  496. * x86 interrupt interface.
  497. */
  498. blaster.intr();
  499. }
  500. void
  501. audiodmaintr(void)
  502. {
  503. /* print("#A: dma interrupt\n"); /**/
  504. }
  505. static int
  506. anybuf(void*)
  507. {
  508. return audio.intr;
  509. }
  510. /*
  511. * wait for some output to get
  512. * empty buffers back.
  513. */
  514. static void
  515. waitaudio(void)
  516. {
  517. audio.intr = 0;
  518. pokeaudio();
  519. tsleep(&audio.vous, anybuf, 0, 10000);
  520. if(audio.intr == 0) {
  521. /* print("#A: audio timeout\n"); /**/
  522. audio.active = 0;
  523. pokeaudio();
  524. }
  525. }
  526. static void
  527. sbbufinit(void)
  528. {
  529. int i;
  530. uchar *p;
  531. p = (uchar*)(((ulong)xalloc((Nbuf+1) * Bufsize) + Bufsize-1)&~(Bufsize-1));
  532. for(i=0; i<Nbuf; i++) {
  533. dcflush(p, Bufsize);
  534. audio.buf[i].virt = UNCACHED(uchar, p);
  535. audio.buf[i].phys = (ulong)PADDR(p);
  536. p += Bufsize;
  537. }
  538. }
  539. static void
  540. setempty(void)
  541. {
  542. int i;
  543. ilock(&blaster);
  544. audio.empty.first = 0;
  545. audio.empty.last = 0;
  546. audio.full.first = 0;
  547. audio.full.last = 0;
  548. audio.current = 0;
  549. audio.filling = 0;
  550. audio.buffered = 0;
  551. for(i=0; i<Nbuf; i++)
  552. putbuf(&audio.empty, &audio.buf[i]);
  553. audio.totcount = 0;
  554. audio.tottime = 0LL;
  555. iunlock(&blaster);
  556. }
  557. static void
  558. resetlevel(void)
  559. {
  560. int i;
  561. for(i=0; volumes[i].name; i++) {
  562. audio.lovol[i] = volumes[i].ilval;
  563. audio.rovol[i] = volumes[i].irval;
  564. audio.livol[i] = volumes[i].ilval;
  565. audio.rivol[i] = volumes[i].irval;
  566. }
  567. }
  568. static int
  569. ess1688(ISAConf* sbconf)
  570. {
  571. int i, major, minor;
  572. /*
  573. * Try for ESS1688.
  574. */
  575. sbcmd(0xE7); /* get version */
  576. major = sbread();
  577. minor = sbread();
  578. if(major != 0x68 || minor != 0x8B){
  579. print("#A: model 0x%.2x 0x%.2x; not ESS1688 compatible\n", major, minor);
  580. return 1;
  581. }
  582. ess1688reset();
  583. switch(sbconf->irq){
  584. case 2:
  585. case 9:
  586. i = 0x50|(0<<2);
  587. break;
  588. case 5:
  589. i = 0x50|(1<<2);
  590. break;
  591. case 7:
  592. i = 0x50|(2<<2);
  593. break;
  594. case 10:
  595. i = 0x50|(3<<2);
  596. break;
  597. default:
  598. print("#A: bad ESS1688 irq %d\n", sbconf->irq);
  599. return 1;
  600. }
  601. ess1688w(0xB1, i);
  602. switch(sbconf->dma){
  603. case 0:
  604. i = 0x50|(1<<2);
  605. break;
  606. case 1:
  607. i = 0xF0|(2<<2);
  608. break;
  609. case 3:
  610. i = 0x50|(3<<2);
  611. break;
  612. default:
  613. print("#A: bad ESS1688 dma %lud\n", sbconf->dma);
  614. return 1;
  615. }
  616. ess1688w(0xB2, i);
  617. ess1688reset();
  618. blaster.startdma = ess1688startdma;
  619. blaster.intr = ess1688intr;
  620. return 0;
  621. }
  622. static void
  623. audioinit(void)
  624. {
  625. ISAConf sbconf;
  626. int i, x;
  627. static int irq[] = {2,5,7,10};
  628. sbconf.port = 0x220;
  629. sbconf.dma = Dma;
  630. sbconf.irq = IrqAUDIO;
  631. if(isaconfig("audio", 0, &sbconf) == 0)
  632. return;
  633. if(sbconf.type == nil ||
  634. (cistrcmp(sbconf.type, "sb16") != 0 &&
  635. cistrcmp(sbconf.type, "ess1688") != 0))
  636. return;
  637. switch(sbconf.port){
  638. case 0x220:
  639. case 0x240:
  640. case 0x260:
  641. case 0x280:
  642. break;
  643. default:
  644. print("#A: bad port 0x%lux\n", sbconf.port);
  645. return;
  646. }
  647. if(ioalloc(sbconf.port, 0x10, 0, "audio") < 0){
  648. print("#A: cannot ioalloc range %lux+0x10\n", sbconf.port);
  649. return;
  650. }
  651. if(ioalloc(sbconf.port+0x100, 1, 0, "audio.mpu401") < 0){
  652. iofree(sbconf.port);
  653. print("#A: cannot ioalloc range %lux+0x01\n", sbconf.port+0x100);
  654. return;
  655. }
  656. switch(sbconf.irq){
  657. case 2:
  658. case 5:
  659. case 7:
  660. case 9:
  661. case 10:
  662. break;
  663. default:
  664. print("#A: bad irq %d\n", sbconf.irq);
  665. iofree(sbconf.port);
  666. iofree(sbconf.port+0x100);
  667. return;
  668. }
  669. blaster.reset = sbconf.port + 0x6;
  670. blaster.read = sbconf.port + 0xa;
  671. blaster.write = sbconf.port + 0xc;
  672. blaster.wstatus = sbconf.port + 0xc;
  673. blaster.rstatus = sbconf.port + 0xe;
  674. blaster.mixaddr = sbconf.port + 0x4;
  675. blaster.mixdata = sbconf.port + 0x5;
  676. blaster.clri8 = sbconf.port + 0xe;
  677. blaster.clri16 = sbconf.port + 0xf;
  678. blaster.clri401 = sbconf.port + 0x100;
  679. blaster.dma = sbconf.dma;
  680. blaster.startdma = sb16startdma;
  681. blaster.intr = sb16intr;
  682. audio.amode = Aclosed;
  683. resetlevel();
  684. outb(blaster.reset, 1);
  685. delay(1); /* >3 υs */
  686. outb(blaster.reset, 0);
  687. delay(1);
  688. i = sbread();
  689. if(i != 0xaa) {
  690. print("#A: no response #%.2x\n", i);
  691. iofree(sbconf.port);
  692. iofree(sbconf.port+0x100);
  693. return;
  694. }
  695. sbcmd(0xe1); /* get version */
  696. audio.major = sbread();
  697. audio.minor = sbread();
  698. if(audio.major != 4) {
  699. if(audio.major != 3 || audio.minor != 1 || ess1688(&sbconf)){
  700. print("#A: model 0x%.2x 0x%.2x; not SB 16 compatible\n",
  701. audio.major, audio.minor);
  702. iofree(sbconf.port);
  703. iofree(sbconf.port+0x100);
  704. return;
  705. }
  706. audio.major = 4;
  707. }
  708. /*
  709. * initialize the mixer
  710. */
  711. mxcmd(0x00, 0); /* Reset mixer */
  712. mxvolume();
  713. /*
  714. * Attempt to set IRQ/DMA channels.
  715. * On old ISA boards, these registers are writable.
  716. * On Plug-n-Play boards, these are read-only.
  717. *
  718. * To accomodate both, we write to the registers,
  719. * but then use the contents in case the write is
  720. * disallowed.
  721. */
  722. mxcmd(0x80, /* irq */
  723. (sbconf.irq==2)? 1:
  724. (sbconf.irq==5)? 2:
  725. (sbconf.irq==7)? 4:
  726. (sbconf.irq==9)? 1:
  727. (sbconf.irq==10)? 8:
  728. 0);
  729. mxcmd(0x81, 1<<blaster.dma); /* dma */
  730. x = mxread(0x81);
  731. for(i=5; i<=7; i++)
  732. if(x & (1<<i)){
  733. blaster.dma = i;
  734. break;
  735. }
  736. x = mxread(0x80);
  737. for(i=0; i<=3; i++)
  738. if(x & (1<<i)){
  739. sbconf.irq = irq[i];
  740. break;
  741. }
  742. seteisadma(blaster.dma, audiodmaintr);
  743. setvec(Int0vec+sbconf.irq, pcaudiosbintr, 0);
  744. }
  745. static Chan*
  746. audioattach(char *param)
  747. {
  748. return devattach('A', param);
  749. }
  750. static Walkqid*
  751. audiowalk(Chan *c, Chan *nc, char **name, int nname)
  752. {
  753. return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
  754. }
  755. static int
  756. audiostat(Chan *c, uchar *db, int n)
  757. {
  758. audiodir[Qaudio].length = audio.buffered;
  759. return devstat(c, db, n, audiodir, nelem(audiodir), devgen);
  760. }
  761. static Chan*
  762. audioopen(Chan *c, int omode)
  763. {
  764. int amode;
  765. if(audio.major != 4)
  766. error(Emajor);
  767. switch((ulong)c->qid.path) {
  768. default:
  769. error(Eperm);
  770. break;
  771. case Qstatus:
  772. if((omode&7) != OREAD)
  773. error(Eperm);
  774. case Qvolume:
  775. case Qdir:
  776. break;
  777. case Qaudio:
  778. amode = Awrite;
  779. if((omode&7) == OREAD)
  780. amode = Aread;
  781. qlock(&audio);
  782. if(audio.amode != Aclosed){
  783. qunlock(&audio);
  784. error(Einuse);
  785. }
  786. if(audio.bufinit == 0) {
  787. audio.bufinit = 1;
  788. sbbufinit();
  789. }
  790. audio.amode = amode;
  791. setempty();
  792. audio.curcount = 0;
  793. qunlock(&audio);
  794. mxvolume();
  795. break;
  796. }
  797. c = devopen(c, omode, audiodir, nelem(audiodir), devgen);
  798. c->mode = openmode(omode);
  799. c->flag |= COPEN;
  800. c->offset = 0;
  801. return c;
  802. }
  803. static void
  804. audioclose(Chan *c)
  805. {
  806. Buf *b;
  807. switch((ulong)c->qid.path) {
  808. default:
  809. error(Eperm);
  810. break;
  811. case Qdir:
  812. case Qvolume:
  813. case Qstatus:
  814. break;
  815. case Qaudio:
  816. if(c->flag & COPEN) {
  817. qlock(&audio);
  818. if(audio.amode == Awrite) {
  819. /* flush out last partial buffer */
  820. b = audio.filling;
  821. if(b) {
  822. audio.filling = 0;
  823. memset(b->virt+audio.curcount, 0, Bufsize-audio.curcount);
  824. audio.buffered += Bufsize-audio.curcount;
  825. swab(b->virt);
  826. putbuf(&audio.full, b);
  827. }
  828. if(!audio.active && audio.full.first)
  829. pokeaudio();
  830. }
  831. audio.amode = Aclosed;
  832. if(waserror()){
  833. qunlock(&audio);
  834. nexterror();
  835. }
  836. while(audio.active)
  837. waitaudio();
  838. setempty();
  839. poperror();
  840. qunlock(&audio);
  841. }
  842. break;
  843. }
  844. }
  845. static long
  846. audioread(Chan *c, void *v, long n, vlong off)
  847. {
  848. int liv, riv, lov, rov;
  849. long m, n0;
  850. char buf[300];
  851. Buf *b;
  852. int j;
  853. ulong offset = off;
  854. char *a;
  855. n0 = n;
  856. a = v;
  857. switch((ulong)c->qid.path) {
  858. default:
  859. error(Eperm);
  860. break;
  861. case Qdir:
  862. return devdirread(c, a, n, audiodir, nelem(audiodir), devgen);
  863. case Qaudio:
  864. if(audio.amode != Aread)
  865. error(Emode);
  866. qlock(&audio);
  867. if(waserror()){
  868. qunlock(&audio);
  869. nexterror();
  870. }
  871. while(n > 0) {
  872. b = audio.filling;
  873. if(b == 0) {
  874. b = getbuf(&audio.full);
  875. if(b == 0) {
  876. waitaudio();
  877. continue;
  878. }
  879. audio.filling = b;
  880. swab(b->virt);
  881. audio.curcount = 0;
  882. }
  883. m = Bufsize-audio.curcount;
  884. if(m > n)
  885. m = n;
  886. memmove(a, b->virt+audio.curcount, m);
  887. audio.curcount += m;
  888. n -= m;
  889. a += m;
  890. audio.buffered -= m;
  891. if(audio.curcount >= Bufsize) {
  892. audio.filling = 0;
  893. putbuf(&audio.empty, b);
  894. }
  895. }
  896. poperror();
  897. qunlock(&audio);
  898. break;
  899. case Qstatus:
  900. buf[0] = 0;
  901. snprint(buf, sizeof(buf), "bufsize %6d buffered %6d offset %10lud time %19lld\n",
  902. Bufsize, audio.buffered, audio.totcount, audio.tottime);
  903. return readstr(offset, a, n, buf);
  904. case Qvolume:
  905. j = 0;
  906. buf[0] = 0;
  907. for(m=0; volumes[m].name; m++){
  908. liv = audio.livol[m];
  909. riv = audio.rivol[m];
  910. lov = audio.lovol[m];
  911. rov = audio.rovol[m];
  912. j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name);
  913. if((volumes[m].flag & Fmono) || liv==riv && lov==rov){
  914. if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov)
  915. j += snprint(buf+j, sizeof(buf)-j, " %d", liv);
  916. else{
  917. if(volumes[m].flag & Fin)
  918. j += snprint(buf+j, sizeof(buf)-j,
  919. " in %d", liv);
  920. if(volumes[m].flag & Fout)
  921. j += snprint(buf+j, sizeof(buf)-j,
  922. " out %d", lov);
  923. }
  924. }else{
  925. if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) &&
  926. liv==lov && riv==rov)
  927. j += snprint(buf+j, sizeof(buf)-j,
  928. " left %d right %d",
  929. liv, riv);
  930. else{
  931. if(volumes[m].flag & Fin)
  932. j += snprint(buf+j, sizeof(buf)-j,
  933. " in left %d right %d",
  934. liv, riv);
  935. if(volumes[m].flag & Fout)
  936. j += snprint(buf+j, sizeof(buf)-j,
  937. " out left %d right %d",
  938. lov, rov);
  939. }
  940. }
  941. j += snprint(buf+j, sizeof(buf)-j, "\n");
  942. }
  943. return readstr(offset, a, n, buf);
  944. }
  945. return n0-n;
  946. }
  947. static long
  948. audiowrite(Chan *c, void *vp, long n, vlong)
  949. {
  950. long m, n0;
  951. int i, v, left, right, in, out;
  952. Cmdbuf *cb;
  953. Buf *b;
  954. char *a;
  955. a = vp;
  956. n0 = n;
  957. switch((ulong)c->qid.path) {
  958. default:
  959. error(Eperm);
  960. break;
  961. case Qvolume:
  962. v = Vaudio;
  963. left = 1;
  964. right = 1;
  965. in = 1;
  966. out = 1;
  967. cb = parsecmd(vp, n);
  968. if(waserror()){
  969. free(cb);
  970. nexterror();
  971. }
  972. for(i = 0; i < cb->nf; i++){
  973. /*
  974. * a number is volume
  975. */
  976. if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') {
  977. m = strtoul(cb->f[i], 0, 10);
  978. if(left && out)
  979. audio.lovol[v] = m;
  980. if(left && in)
  981. audio.livol[v] = m;
  982. if(right && out)
  983. audio.rovol[v] = m;
  984. if(right && in)
  985. audio.rivol[v] = m;
  986. mxvolume();
  987. goto cont0;
  988. }
  989. for(m=0; volumes[m].name; m++) {
  990. if(strcmp(cb->f[i], volumes[m].name) == 0) {
  991. v = m;
  992. in = 1;
  993. out = 1;
  994. left = 1;
  995. right = 1;
  996. goto cont0;
  997. }
  998. }
  999. if(strcmp(cb->f[i], "reset") == 0) {
  1000. resetlevel();
  1001. mxvolume();
  1002. goto cont0;
  1003. }
  1004. if(strcmp(cb->f[i], "in") == 0) {
  1005. in = 1;
  1006. out = 0;
  1007. goto cont0;
  1008. }
  1009. if(strcmp(cb->f[i], "out") == 0) {
  1010. in = 0;
  1011. out = 1;
  1012. goto cont0;
  1013. }
  1014. if(strcmp(cb->f[i], "left") == 0) {
  1015. left = 1;
  1016. right = 0;
  1017. goto cont0;
  1018. }
  1019. if(strcmp(cb->f[i], "right") == 0) {
  1020. left = 0;
  1021. right = 1;
  1022. goto cont0;
  1023. }
  1024. error(Evolume);
  1025. break;
  1026. cont0:;
  1027. }
  1028. free(cb);
  1029. poperror();
  1030. break;
  1031. case Qaudio:
  1032. if(audio.amode != Awrite)
  1033. error(Emode);
  1034. qlock(&audio);
  1035. if(waserror()){
  1036. qunlock(&audio);
  1037. nexterror();
  1038. }
  1039. while(n > 0) {
  1040. b = audio.filling;
  1041. if(b == 0) {
  1042. b = getbuf(&audio.empty);
  1043. if(b == 0) {
  1044. waitaudio();
  1045. continue;
  1046. }
  1047. audio.filling = b;
  1048. audio.curcount = 0;
  1049. }
  1050. m = Bufsize-audio.curcount;
  1051. if(m > n)
  1052. m = n;
  1053. memmove(b->virt+audio.curcount, a, m);
  1054. audio.curcount += m;
  1055. n -= m;
  1056. a += m;
  1057. audio.buffered += m;
  1058. if(audio.curcount >= Bufsize) {
  1059. audio.filling = 0;
  1060. swab(b->virt);
  1061. putbuf(&audio.full, b);
  1062. pokeaudio();
  1063. }
  1064. }
  1065. poperror();
  1066. qunlock(&audio);
  1067. break;
  1068. }
  1069. return n0 - n;
  1070. }
  1071. static void
  1072. swab(uchar *a)
  1073. {
  1074. ulong *p, *ep, b;
  1075. if(!SBswab){
  1076. USED(a);
  1077. return;
  1078. }
  1079. p = (ulong*)a;
  1080. ep = p + (Bufsize>>2);
  1081. while(p < ep) {
  1082. b = *p;
  1083. b = (b>>24) | (b<<24) |
  1084. ((b&0xff0000) >> 8) |
  1085. ((b&0x00ff00) << 8);
  1086. *p++ = b;
  1087. }
  1088. }
  1089. Dev audiodevtab = {
  1090. 'A',
  1091. "audio",
  1092. devreset,
  1093. audioinit,
  1094. devshutdown,
  1095. audioattach,
  1096. audiowalk,
  1097. audiostat,
  1098. audioopen,
  1099. devcreate,
  1100. audioclose,
  1101. audioread,
  1102. devbread,
  1103. audiowrite,
  1104. devbwrite,
  1105. devremove,
  1106. devwstat,
  1107. };