devaudio.c 21 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261
  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 (%#.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 %#.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) &
  532. ~(Bufsize-1));
  533. if (p == nil)
  534. panic("sbbufinit: no memory");
  535. for(i=0; i<Nbuf; i++) {
  536. dcflush(p, Bufsize);
  537. audio.buf[i].virt = UNCACHED(uchar, p);
  538. audio.buf[i].phys = (ulong)PADDR(p);
  539. p += Bufsize;
  540. }
  541. }
  542. static void
  543. setempty(void)
  544. {
  545. int i;
  546. ilock(&blaster);
  547. audio.empty.first = 0;
  548. audio.empty.last = 0;
  549. audio.full.first = 0;
  550. audio.full.last = 0;
  551. audio.current = 0;
  552. audio.filling = 0;
  553. audio.buffered = 0;
  554. for(i=0; i<Nbuf; i++)
  555. putbuf(&audio.empty, &audio.buf[i]);
  556. audio.totcount = 0;
  557. audio.tottime = 0LL;
  558. iunlock(&blaster);
  559. }
  560. static void
  561. resetlevel(void)
  562. {
  563. int i;
  564. for(i=0; volumes[i].name; i++) {
  565. audio.lovol[i] = volumes[i].ilval;
  566. audio.rovol[i] = volumes[i].irval;
  567. audio.livol[i] = volumes[i].ilval;
  568. audio.rivol[i] = volumes[i].irval;
  569. }
  570. }
  571. static int
  572. ess1688(ISAConf* sbconf)
  573. {
  574. int i, major, minor;
  575. /*
  576. * Try for ESS1688.
  577. */
  578. sbcmd(0xE7); /* get version */
  579. major = sbread();
  580. minor = sbread();
  581. if(major != 0x68 || minor != 0x8B){
  582. print("#A: model %#.2x %#.2x; not ESS1688 compatible\n", major, minor);
  583. return 1;
  584. }
  585. ess1688reset();
  586. switch(sbconf->irq){
  587. case 2:
  588. case 9:
  589. i = 0x50|(0<<2);
  590. break;
  591. case 5:
  592. i = 0x50|(1<<2);
  593. break;
  594. case 7:
  595. i = 0x50|(2<<2);
  596. break;
  597. case 10:
  598. i = 0x50|(3<<2);
  599. break;
  600. default:
  601. print("#A: bad ESS1688 irq %d\n", sbconf->irq);
  602. return 1;
  603. }
  604. ess1688w(0xB1, i);
  605. switch(sbconf->dma){
  606. case 0:
  607. i = 0x50|(1<<2);
  608. break;
  609. case 1:
  610. i = 0xF0|(2<<2);
  611. break;
  612. case 3:
  613. i = 0x50|(3<<2);
  614. break;
  615. default:
  616. print("#A: bad ESS1688 dma %lud\n", sbconf->dma);
  617. return 1;
  618. }
  619. ess1688w(0xB2, i);
  620. ess1688reset();
  621. blaster.startdma = ess1688startdma;
  622. blaster.intr = ess1688intr;
  623. return 0;
  624. }
  625. static void
  626. audioinit(void)
  627. {
  628. ISAConf sbconf;
  629. int i, x;
  630. static int irq[] = {2,5,7,10};
  631. sbconf.port = 0x220;
  632. sbconf.dma = Dma;
  633. sbconf.irq = IrqAUDIO;
  634. if(isaconfig("audio", 0, &sbconf) == 0)
  635. return;
  636. if(sbconf.type == nil ||
  637. (cistrcmp(sbconf.type, "sb16") != 0 &&
  638. cistrcmp(sbconf.type, "ess1688") != 0))
  639. return;
  640. switch(sbconf.port){
  641. case 0x220:
  642. case 0x240:
  643. case 0x260:
  644. case 0x280:
  645. break;
  646. default:
  647. print("#A: bad port %#lux\n", sbconf.port);
  648. return;
  649. }
  650. if(ioalloc(sbconf.port, 0x10, 0, "audio") < 0){
  651. print("#A: cannot ioalloc range %lux+0x10\n", sbconf.port);
  652. return;
  653. }
  654. if(ioalloc(sbconf.port+0x100, 1, 0, "audio.mpu401") < 0){
  655. iofree(sbconf.port);
  656. print("#A: cannot ioalloc range %lux+0x01\n", sbconf.port+0x100);
  657. return;
  658. }
  659. switch(sbconf.irq){
  660. case 2:
  661. case 5:
  662. case 7:
  663. case 9:
  664. case 10:
  665. break;
  666. default:
  667. print("#A: bad irq %d\n", sbconf.irq);
  668. iofree(sbconf.port);
  669. iofree(sbconf.port+0x100);
  670. return;
  671. }
  672. blaster.reset = sbconf.port + 0x6;
  673. blaster.read = sbconf.port + 0xa;
  674. blaster.write = sbconf.port + 0xc;
  675. blaster.wstatus = sbconf.port + 0xc;
  676. blaster.rstatus = sbconf.port + 0xe;
  677. blaster.mixaddr = sbconf.port + 0x4;
  678. blaster.mixdata = sbconf.port + 0x5;
  679. blaster.clri8 = sbconf.port + 0xe;
  680. blaster.clri16 = sbconf.port + 0xf;
  681. blaster.clri401 = sbconf.port + 0x100;
  682. blaster.dma = sbconf.dma;
  683. blaster.startdma = sb16startdma;
  684. blaster.intr = sb16intr;
  685. audio.amode = Aclosed;
  686. resetlevel();
  687. outb(blaster.reset, 1);
  688. delay(1); /* >3 υs */
  689. outb(blaster.reset, 0);
  690. delay(1);
  691. i = sbread();
  692. if(i != 0xaa) {
  693. print("#A: no response #%.2x\n", i);
  694. iofree(sbconf.port);
  695. iofree(sbconf.port+0x100);
  696. return;
  697. }
  698. sbcmd(0xe1); /* get version */
  699. audio.major = sbread();
  700. audio.minor = sbread();
  701. if(audio.major != 4) {
  702. if(audio.major != 3 || audio.minor != 1 || ess1688(&sbconf)){
  703. print("#A: model %#.2x %#.2x; not SB 16 compatible\n",
  704. audio.major, audio.minor);
  705. iofree(sbconf.port);
  706. iofree(sbconf.port+0x100);
  707. return;
  708. }
  709. audio.major = 4;
  710. }
  711. /*
  712. * initialize the mixer
  713. */
  714. mxcmd(0x00, 0); /* Reset mixer */
  715. mxvolume();
  716. /*
  717. * Attempt to set IRQ/DMA channels.
  718. * On old ISA boards, these registers are writable.
  719. * On Plug-n-Play boards, these are read-only.
  720. *
  721. * To accomodate both, we write to the registers,
  722. * but then use the contents in case the write is
  723. * disallowed.
  724. */
  725. mxcmd(0x80, /* irq */
  726. (sbconf.irq==2)? 1:
  727. (sbconf.irq==5)? 2:
  728. (sbconf.irq==7)? 4:
  729. (sbconf.irq==9)? 1:
  730. (sbconf.irq==10)? 8:
  731. 0);
  732. mxcmd(0x81, 1<<blaster.dma); /* dma */
  733. x = mxread(0x81);
  734. for(i=5; i<=7; i++)
  735. if(x & (1<<i)){
  736. blaster.dma = i;
  737. break;
  738. }
  739. x = mxread(0x80);
  740. for(i=0; i<=3; i++)
  741. if(x & (1<<i)){
  742. sbconf.irq = irq[i];
  743. break;
  744. }
  745. seteisadma(blaster.dma, audiodmaintr);
  746. setvec(Int0vec+sbconf.irq, pcaudiosbintr, 0);
  747. }
  748. static Chan*
  749. audioattach(char *param)
  750. {
  751. return devattach('A', param);
  752. }
  753. static Walkqid*
  754. audiowalk(Chan *c, Chan *nc, char **name, int nname)
  755. {
  756. return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
  757. }
  758. static int
  759. audiostat(Chan *c, uchar *db, int n)
  760. {
  761. audiodir[Qaudio].length = audio.buffered;
  762. return devstat(c, db, n, audiodir, nelem(audiodir), devgen);
  763. }
  764. static Chan*
  765. audioopen(Chan *c, int omode)
  766. {
  767. int amode;
  768. if(audio.major != 4)
  769. error(Emajor);
  770. switch((ulong)c->qid.path) {
  771. default:
  772. error(Eperm);
  773. break;
  774. case Qstatus:
  775. if((omode&7) != OREAD)
  776. error(Eperm);
  777. case Qvolume:
  778. case Qdir:
  779. break;
  780. case Qaudio:
  781. amode = Awrite;
  782. if((omode&7) == OREAD)
  783. amode = Aread;
  784. qlock(&audio);
  785. if(audio.amode != Aclosed){
  786. qunlock(&audio);
  787. error(Einuse);
  788. }
  789. if(audio.bufinit == 0) {
  790. audio.bufinit = 1;
  791. sbbufinit();
  792. }
  793. audio.amode = amode;
  794. setempty();
  795. audio.curcount = 0;
  796. qunlock(&audio);
  797. mxvolume();
  798. break;
  799. }
  800. c = devopen(c, omode, audiodir, nelem(audiodir), devgen);
  801. c->mode = openmode(omode);
  802. c->flag |= COPEN;
  803. c->offset = 0;
  804. return c;
  805. }
  806. static void
  807. audioclose(Chan *c)
  808. {
  809. Buf *b;
  810. switch((ulong)c->qid.path) {
  811. default:
  812. error(Eperm);
  813. break;
  814. case Qdir:
  815. case Qvolume:
  816. case Qstatus:
  817. break;
  818. case Qaudio:
  819. if(c->flag & COPEN) {
  820. qlock(&audio);
  821. if(audio.amode == Awrite) {
  822. /* flush out last partial buffer */
  823. b = audio.filling;
  824. if(b) {
  825. audio.filling = 0;
  826. memset(b->virt+audio.curcount, 0, Bufsize-audio.curcount);
  827. audio.buffered += Bufsize-audio.curcount;
  828. swab(b->virt);
  829. putbuf(&audio.full, b);
  830. }
  831. if(!audio.active && audio.full.first)
  832. pokeaudio();
  833. }
  834. audio.amode = Aclosed;
  835. if(waserror()){
  836. qunlock(&audio);
  837. nexterror();
  838. }
  839. while(audio.active)
  840. waitaudio();
  841. setempty();
  842. poperror();
  843. qunlock(&audio);
  844. }
  845. break;
  846. }
  847. }
  848. static long
  849. audioread(Chan *c, void *v, long n, vlong off)
  850. {
  851. int liv, riv, lov, rov;
  852. long m, n0;
  853. char buf[300];
  854. Buf *b;
  855. int j;
  856. ulong offset = off;
  857. char *a;
  858. n0 = n;
  859. a = v;
  860. switch((ulong)c->qid.path) {
  861. default:
  862. error(Eperm);
  863. break;
  864. case Qdir:
  865. return devdirread(c, a, n, audiodir, nelem(audiodir), devgen);
  866. case Qaudio:
  867. if(audio.amode != Aread)
  868. error(Emode);
  869. qlock(&audio);
  870. if(waserror()){
  871. qunlock(&audio);
  872. nexterror();
  873. }
  874. while(n > 0) {
  875. b = audio.filling;
  876. if(b == 0) {
  877. b = getbuf(&audio.full);
  878. if(b == 0) {
  879. waitaudio();
  880. continue;
  881. }
  882. audio.filling = b;
  883. swab(b->virt);
  884. audio.curcount = 0;
  885. }
  886. m = Bufsize-audio.curcount;
  887. if(m > n)
  888. m = n;
  889. memmove(a, b->virt+audio.curcount, m);
  890. audio.curcount += m;
  891. n -= m;
  892. a += m;
  893. audio.buffered -= m;
  894. if(audio.curcount >= Bufsize) {
  895. audio.filling = 0;
  896. putbuf(&audio.empty, b);
  897. }
  898. }
  899. poperror();
  900. qunlock(&audio);
  901. break;
  902. case Qstatus:
  903. buf[0] = 0;
  904. snprint(buf, sizeof(buf), "bufsize %6d buffered %6d offset %10lud time %19lld\n",
  905. Bufsize, audio.buffered, audio.totcount, audio.tottime);
  906. return readstr(offset, a, n, buf);
  907. case Qvolume:
  908. j = 0;
  909. buf[0] = 0;
  910. for(m=0; volumes[m].name; m++){
  911. liv = audio.livol[m];
  912. riv = audio.rivol[m];
  913. lov = audio.lovol[m];
  914. rov = audio.rovol[m];
  915. j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name);
  916. if((volumes[m].flag & Fmono) || liv==riv && lov==rov){
  917. if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov)
  918. j += snprint(buf+j, sizeof(buf)-j, " %d", liv);
  919. else{
  920. if(volumes[m].flag & Fin)
  921. j += snprint(buf+j, sizeof(buf)-j,
  922. " in %d", liv);
  923. if(volumes[m].flag & Fout)
  924. j += snprint(buf+j, sizeof(buf)-j,
  925. " out %d", lov);
  926. }
  927. }else{
  928. if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) &&
  929. liv==lov && riv==rov)
  930. j += snprint(buf+j, sizeof(buf)-j,
  931. " left %d right %d",
  932. liv, riv);
  933. else{
  934. if(volumes[m].flag & Fin)
  935. j += snprint(buf+j, sizeof(buf)-j,
  936. " in left %d right %d",
  937. liv, riv);
  938. if(volumes[m].flag & Fout)
  939. j += snprint(buf+j, sizeof(buf)-j,
  940. " out left %d right %d",
  941. lov, rov);
  942. }
  943. }
  944. j += snprint(buf+j, sizeof(buf)-j, "\n");
  945. }
  946. return readstr(offset, a, n, buf);
  947. }
  948. return n0-n;
  949. }
  950. static long
  951. audiowrite(Chan *c, void *vp, long n, vlong)
  952. {
  953. long m, n0;
  954. int i, v, left, right, in, out;
  955. Cmdbuf *cb;
  956. Buf *b;
  957. char *a;
  958. a = vp;
  959. n0 = n;
  960. switch((ulong)c->qid.path) {
  961. default:
  962. error(Eperm);
  963. break;
  964. case Qvolume:
  965. v = Vaudio;
  966. left = 1;
  967. right = 1;
  968. in = 1;
  969. out = 1;
  970. cb = parsecmd(vp, n);
  971. if(waserror()){
  972. free(cb);
  973. nexterror();
  974. }
  975. for(i = 0; i < cb->nf; i++){
  976. /*
  977. * a number is volume
  978. */
  979. if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') {
  980. m = strtoul(cb->f[i], 0, 10);
  981. if(left && out)
  982. audio.lovol[v] = m;
  983. if(left && in)
  984. audio.livol[v] = m;
  985. if(right && out)
  986. audio.rovol[v] = m;
  987. if(right && in)
  988. audio.rivol[v] = m;
  989. mxvolume();
  990. goto cont0;
  991. }
  992. for(m=0; volumes[m].name; m++) {
  993. if(strcmp(cb->f[i], volumes[m].name) == 0) {
  994. v = m;
  995. in = 1;
  996. out = 1;
  997. left = 1;
  998. right = 1;
  999. goto cont0;
  1000. }
  1001. }
  1002. if(strcmp(cb->f[i], "reset") == 0) {
  1003. resetlevel();
  1004. mxvolume();
  1005. goto cont0;
  1006. }
  1007. if(strcmp(cb->f[i], "in") == 0) {
  1008. in = 1;
  1009. out = 0;
  1010. goto cont0;
  1011. }
  1012. if(strcmp(cb->f[i], "out") == 0) {
  1013. in = 0;
  1014. out = 1;
  1015. goto cont0;
  1016. }
  1017. if(strcmp(cb->f[i], "left") == 0) {
  1018. left = 1;
  1019. right = 0;
  1020. goto cont0;
  1021. }
  1022. if(strcmp(cb->f[i], "right") == 0) {
  1023. left = 0;
  1024. right = 1;
  1025. goto cont0;
  1026. }
  1027. error(Evolume);
  1028. break;
  1029. cont0:;
  1030. }
  1031. free(cb);
  1032. poperror();
  1033. break;
  1034. case Qaudio:
  1035. if(audio.amode != Awrite)
  1036. error(Emode);
  1037. qlock(&audio);
  1038. if(waserror()){
  1039. qunlock(&audio);
  1040. nexterror();
  1041. }
  1042. while(n > 0) {
  1043. b = audio.filling;
  1044. if(b == 0) {
  1045. b = getbuf(&audio.empty);
  1046. if(b == 0) {
  1047. waitaudio();
  1048. continue;
  1049. }
  1050. audio.filling = b;
  1051. audio.curcount = 0;
  1052. }
  1053. m = Bufsize-audio.curcount;
  1054. if(m > n)
  1055. m = n;
  1056. memmove(b->virt+audio.curcount, a, m);
  1057. audio.curcount += m;
  1058. n -= m;
  1059. a += m;
  1060. audio.buffered += m;
  1061. if(audio.curcount >= Bufsize) {
  1062. audio.filling = 0;
  1063. swab(b->virt);
  1064. putbuf(&audio.full, b);
  1065. pokeaudio();
  1066. }
  1067. }
  1068. poperror();
  1069. qunlock(&audio);
  1070. break;
  1071. }
  1072. return n0 - n;
  1073. }
  1074. static void
  1075. swab(uchar *a)
  1076. {
  1077. ulong *p, *ep, b;
  1078. if(!SBswab){
  1079. USED(a);
  1080. return;
  1081. }
  1082. p = (ulong*)a;
  1083. ep = p + (Bufsize>>2);
  1084. while(p < ep) {
  1085. b = *p;
  1086. b = (b>>24) | (b<<24) |
  1087. ((b&0xff0000) >> 8) |
  1088. ((b&0x00ff00) << 8);
  1089. *p++ = b;
  1090. }
  1091. }
  1092. Dev audiodevtab = {
  1093. 'A',
  1094. "audio",
  1095. devreset,
  1096. audioinit,
  1097. devshutdown,
  1098. audioattach,
  1099. audiowalk,
  1100. audiostat,
  1101. audioopen,
  1102. devcreate,
  1103. audioclose,
  1104. audioread,
  1105. devbread,
  1106. audiowrite,
  1107. devbwrite,
  1108. devremove,
  1109. devwstat,
  1110. };