xref: /minix3/minix/drivers/audio/sb16/sb16.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /*  Driver for SB16 ISA card
2*433d6423SLionel Sambuc  *  Implementing audio/audio_fw.h
3*433d6423SLionel Sambuc  *
4*433d6423SLionel Sambuc  *  February 2006   Integrated standalone driver with audio framework (Peter Boonstoppel)
5*433d6423SLionel Sambuc  *  August 24 2005  Ported audio driver to user space (only audio playback) (Peter Boonstoppel)
6*433d6423SLionel Sambuc  *  May 20 1995	    SB16 Driver: Michel R. Prevenier
7*433d6423SLionel Sambuc  */
8*433d6423SLionel Sambuc 
9*433d6423SLionel Sambuc 
10*433d6423SLionel Sambuc #include "sb16.h"
11*433d6423SLionel Sambuc #include "mixer.h"
12*433d6423SLionel Sambuc 
13*433d6423SLionel Sambuc 
14*433d6423SLionel Sambuc static void dsp_dma_setup(phys_bytes address, int count, int sub_dev);
15*433d6423SLionel Sambuc 
16*433d6423SLionel Sambuc static int dsp_ioctl(unsigned long request, void *val, int *len);
17*433d6423SLionel Sambuc static int dsp_set_size(unsigned int size);
18*433d6423SLionel Sambuc static int dsp_set_speed(unsigned int speed);
19*433d6423SLionel Sambuc static int dsp_set_stereo(unsigned int stereo);
20*433d6423SLionel Sambuc static int dsp_set_bits(unsigned int bits);
21*433d6423SLionel Sambuc static int dsp_set_sign(unsigned int sign);
22*433d6423SLionel Sambuc static int dsp_get_max_frag_size(u32_t *val, int *len);
23*433d6423SLionel Sambuc 
24*433d6423SLionel Sambuc 
25*433d6423SLionel Sambuc static unsigned int DspStereo = DEFAULT_STEREO;
26*433d6423SLionel Sambuc static unsigned int DspSpeed = DEFAULT_SPEED;
27*433d6423SLionel Sambuc static unsigned int DspBits = DEFAULT_BITS;
28*433d6423SLionel Sambuc static unsigned int DspSign = DEFAULT_SIGN;
29*433d6423SLionel Sambuc static unsigned int DspFragmentSize;
30*433d6423SLionel Sambuc 
31*433d6423SLionel Sambuc static phys_bytes DmaPhys;
32*433d6423SLionel Sambuc static int running = FALSE;
33*433d6423SLionel Sambuc 
34*433d6423SLionel Sambuc 
35*433d6423SLionel Sambuc sub_dev_t sub_dev[2];
36*433d6423SLionel Sambuc special_file_t special_file[3];
37*433d6423SLionel Sambuc drv_t drv;
38*433d6423SLionel Sambuc 
39*433d6423SLionel Sambuc 
40*433d6423SLionel Sambuc 
drv_init(void)41*433d6423SLionel Sambuc int drv_init(void) {
42*433d6423SLionel Sambuc 	drv.DriverName = "SB16";
43*433d6423SLionel Sambuc 	drv.NrOfSubDevices = 2;
44*433d6423SLionel Sambuc 	drv.NrOfSpecialFiles = 3;
45*433d6423SLionel Sambuc 
46*433d6423SLionel Sambuc 	sub_dev[AUDIO].readable = 1;
47*433d6423SLionel Sambuc 	sub_dev[AUDIO].writable = 1;
48*433d6423SLionel Sambuc 	sub_dev[AUDIO].DmaSize = 64 * 1024;
49*433d6423SLionel Sambuc 	sub_dev[AUDIO].NrOfDmaFragments = 2;
50*433d6423SLionel Sambuc 	sub_dev[AUDIO].MinFragmentSize = 1024;
51*433d6423SLionel Sambuc 	sub_dev[AUDIO].NrOfExtraBuffers = 4;
52*433d6423SLionel Sambuc 
53*433d6423SLionel Sambuc 	sub_dev[MIXER].writable = 0;
54*433d6423SLionel Sambuc 	sub_dev[MIXER].readable = 0;
55*433d6423SLionel Sambuc 
56*433d6423SLionel Sambuc 	special_file[0].minor_dev_nr = 0;
57*433d6423SLionel Sambuc 	special_file[0].write_chan = AUDIO;
58*433d6423SLionel Sambuc 	special_file[0].read_chan = NO_CHANNEL;
59*433d6423SLionel Sambuc 	special_file[0].io_ctl = AUDIO;
60*433d6423SLionel Sambuc 
61*433d6423SLionel Sambuc 	special_file[1].minor_dev_nr = 1;
62*433d6423SLionel Sambuc 	special_file[1].write_chan = NO_CHANNEL;
63*433d6423SLionel Sambuc 	special_file[1].read_chan = AUDIO;
64*433d6423SLionel Sambuc 	special_file[1].io_ctl = AUDIO;
65*433d6423SLionel Sambuc 
66*433d6423SLionel Sambuc 	special_file[2].minor_dev_nr = 2;
67*433d6423SLionel Sambuc 	special_file[2].write_chan = NO_CHANNEL;
68*433d6423SLionel Sambuc 	special_file[2].read_chan = NO_CHANNEL;
69*433d6423SLionel Sambuc 	special_file[2].io_ctl = MIXER;
70*433d6423SLionel Sambuc 
71*433d6423SLionel Sambuc 	return OK;
72*433d6423SLionel Sambuc }
73*433d6423SLionel Sambuc 
74*433d6423SLionel Sambuc 
drv_init_hw(void)75*433d6423SLionel Sambuc int drv_init_hw(void) {
76*433d6423SLionel Sambuc 	int i;
77*433d6423SLionel Sambuc 	int DspVersion[2];
78*433d6423SLionel Sambuc 	Dprint(("drv_init_hw():\n"));
79*433d6423SLionel Sambuc 
80*433d6423SLionel Sambuc 	if(drv_reset () != OK) {
81*433d6423SLionel Sambuc 		Dprint(("sb16: No SoundBlaster card detected\n"));
82*433d6423SLionel Sambuc 		return -1;
83*433d6423SLionel Sambuc 	}
84*433d6423SLionel Sambuc 
85*433d6423SLionel Sambuc 	DspVersion[0] = DspVersion[1] = 0;
86*433d6423SLionel Sambuc 	dsp_command(DSP_GET_VERSION);	/* Get DSP version bytes */
87*433d6423SLionel Sambuc 
88*433d6423SLionel Sambuc 	for(i = 1000; i; i--) {
89*433d6423SLionel Sambuc 		if(sb16_inb(DSP_DATA_AVL) & 0x80) {
90*433d6423SLionel Sambuc 			if(DspVersion[0] == 0) {
91*433d6423SLionel Sambuc 				DspVersion[0] = sb16_inb(DSP_READ);
92*433d6423SLionel Sambuc 			} else {
93*433d6423SLionel Sambuc 				DspVersion[1] = sb16_inb(DSP_READ);
94*433d6423SLionel Sambuc 				break;
95*433d6423SLionel Sambuc 			}
96*433d6423SLionel Sambuc 		}
97*433d6423SLionel Sambuc 	}
98*433d6423SLionel Sambuc 
99*433d6423SLionel Sambuc 	if(DspVersion[0] < 4) {
100*433d6423SLionel Sambuc 		Dprint(("sb16: No SoundBlaster 16 compatible card detected\n"));
101*433d6423SLionel Sambuc 		return -1;
102*433d6423SLionel Sambuc 	}
103*433d6423SLionel Sambuc 
104*433d6423SLionel Sambuc 	Dprint(("sb16: SoundBlaster DSP version %d.%d detected!\n", DspVersion[0], DspVersion[1]));
105*433d6423SLionel Sambuc 
106*433d6423SLionel Sambuc 	/* set SB to use our IRQ and DMA channels */
107*433d6423SLionel Sambuc 	mixer_set(MIXER_SET_IRQ, (1 << (SB_IRQ / 2 - 1)));
108*433d6423SLionel Sambuc 	mixer_set(MIXER_SET_DMA, (1 << SB_DMA_8 | 1 << SB_DMA_16));
109*433d6423SLionel Sambuc 
110*433d6423SLionel Sambuc 	DspFragmentSize = sub_dev[AUDIO].DmaSize / sub_dev[AUDIO].NrOfDmaFragments;
111*433d6423SLionel Sambuc 
112*433d6423SLionel Sambuc 	return OK;
113*433d6423SLionel Sambuc }
114*433d6423SLionel Sambuc 
115*433d6423SLionel Sambuc 
116*433d6423SLionel Sambuc 
drv_reset(void)117*433d6423SLionel Sambuc int drv_reset(void) {
118*433d6423SLionel Sambuc 	int i;
119*433d6423SLionel Sambuc 	Dprint(("drv_reset():\n"));
120*433d6423SLionel Sambuc 
121*433d6423SLionel Sambuc 	sb16_outb(DSP_RESET, 1);
122*433d6423SLionel Sambuc 	for(i = 0; i < 1000; i++); /* wait a while */
123*433d6423SLionel Sambuc 	sb16_outb(DSP_RESET, 0);
124*433d6423SLionel Sambuc 
125*433d6423SLionel Sambuc 	for(i = 0; i < 1000 && !(sb16_inb(DSP_DATA_AVL) & 0x80); i++);
126*433d6423SLionel Sambuc 
127*433d6423SLionel Sambuc 	if(sb16_inb(DSP_READ) != 0xAA) return EIO; /* No SoundBlaster */
128*433d6423SLionel Sambuc 
129*433d6423SLionel Sambuc 	return OK;
130*433d6423SLionel Sambuc }
131*433d6423SLionel Sambuc 
132*433d6423SLionel Sambuc 
133*433d6423SLionel Sambuc 
drv_start(int channel,int DmaMode)134*433d6423SLionel Sambuc int drv_start(int channel, int DmaMode) {
135*433d6423SLionel Sambuc 	Dprint(("drv_start():\n"));
136*433d6423SLionel Sambuc 
137*433d6423SLionel Sambuc 	drv_reset();
138*433d6423SLionel Sambuc 
139*433d6423SLionel Sambuc 	dsp_dma_setup(DmaPhys, DspFragmentSize * sub_dev[channel].NrOfDmaFragments, DmaMode);
140*433d6423SLionel Sambuc 
141*433d6423SLionel Sambuc 	dsp_set_speed(DspSpeed);
142*433d6423SLionel Sambuc 
143*433d6423SLionel Sambuc 	/* Put the speaker on */
144*433d6423SLionel Sambuc 	if(DmaMode == WRITE_DMA) {
145*433d6423SLionel Sambuc 		dsp_command (DSP_CMD_SPKON); /* put speaker on */
146*433d6423SLionel Sambuc 
147*433d6423SLionel Sambuc 		/* Program DSP with dma mode */
148*433d6423SLionel Sambuc 		dsp_command((DspBits == 8 ? DSP_CMD_8BITAUTO_OUT : DSP_CMD_16BITAUTO_OUT));
149*433d6423SLionel Sambuc 	} else {
150*433d6423SLionel Sambuc 		dsp_command (DSP_CMD_SPKOFF); /* put speaker off */
151*433d6423SLionel Sambuc 
152*433d6423SLionel Sambuc 		/* Program DSP with dma mode */
153*433d6423SLionel Sambuc 		dsp_command((DspBits == 8 ? DSP_CMD_8BITAUTO_IN : DSP_CMD_16BITAUTO_IN));
154*433d6423SLionel Sambuc 	}
155*433d6423SLionel Sambuc 
156*433d6423SLionel Sambuc 	/* Program DSP with transfer mode */
157*433d6423SLionel Sambuc 	if (!DspSign) {
158*433d6423SLionel Sambuc 		dsp_command((DspStereo == 1 ? DSP_MODE_STEREO_US : DSP_MODE_MONO_US));
159*433d6423SLionel Sambuc 	} else {
160*433d6423SLionel Sambuc 		dsp_command((DspStereo == 1 ? DSP_MODE_STEREO_S : DSP_MODE_MONO_S));
161*433d6423SLionel Sambuc 	}
162*433d6423SLionel Sambuc 
163*433d6423SLionel Sambuc 	/* Give length of fragment to DSP */
164*433d6423SLionel Sambuc 	if (DspBits == 8) { /* 8 bit transfer */
165*433d6423SLionel Sambuc 		/* #bytes - 1 */
166*433d6423SLionel Sambuc 		dsp_command((DspFragmentSize - 1) >> 0);
167*433d6423SLionel Sambuc 		dsp_command((DspFragmentSize - 1) >> 8);
168*433d6423SLionel Sambuc 	} else {             /* 16 bit transfer */
169*433d6423SLionel Sambuc 		/* #words - 1 */
170*433d6423SLionel Sambuc 		dsp_command((DspFragmentSize - 1) >> 1);
171*433d6423SLionel Sambuc 		dsp_command((DspFragmentSize - 1) >> 9);
172*433d6423SLionel Sambuc 	}
173*433d6423SLionel Sambuc 
174*433d6423SLionel Sambuc 	running = TRUE;
175*433d6423SLionel Sambuc 
176*433d6423SLionel Sambuc 	return OK;
177*433d6423SLionel Sambuc }
178*433d6423SLionel Sambuc 
179*433d6423SLionel Sambuc 
180*433d6423SLionel Sambuc 
drv_stop(int sub_dev)181*433d6423SLionel Sambuc int drv_stop(int sub_dev) {
182*433d6423SLionel Sambuc 	if(running) {
183*433d6423SLionel Sambuc 		Dprint(("drv_stop():\n"));
184*433d6423SLionel Sambuc 		dsp_command((DspBits == 8 ? DSP_CMD_DMA8HALT : DSP_CMD_DMA16HALT));
185*433d6423SLionel Sambuc 		running = FALSE;
186*433d6423SLionel Sambuc 		drv_reenable_int(sub_dev);
187*433d6423SLionel Sambuc 	}
188*433d6423SLionel Sambuc 	return OK;
189*433d6423SLionel Sambuc }
190*433d6423SLionel Sambuc 
191*433d6423SLionel Sambuc 
192*433d6423SLionel Sambuc 
drv_set_dma(u32_t dma,u32_t UNUSED (length),int UNUSED (chan))193*433d6423SLionel Sambuc int drv_set_dma(u32_t dma, u32_t UNUSED(length), int UNUSED(chan)) {
194*433d6423SLionel Sambuc 	Dprint(("drv_set_dma():\n"));
195*433d6423SLionel Sambuc 	DmaPhys = dma;
196*433d6423SLionel Sambuc 	return OK;
197*433d6423SLionel Sambuc }
198*433d6423SLionel Sambuc 
199*433d6423SLionel Sambuc 
200*433d6423SLionel Sambuc 
drv_reenable_int(int UNUSED (chan))201*433d6423SLionel Sambuc int drv_reenable_int(int UNUSED(chan)) {
202*433d6423SLionel Sambuc 	Dprint(("drv_reenable_int()\n"));
203*433d6423SLionel Sambuc 	sb16_inb((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL));
204*433d6423SLionel Sambuc 	return OK;
205*433d6423SLionel Sambuc }
206*433d6423SLionel Sambuc 
207*433d6423SLionel Sambuc 
208*433d6423SLionel Sambuc 
drv_int_sum(void)209*433d6423SLionel Sambuc int drv_int_sum(void) {
210*433d6423SLionel Sambuc 	return mixer_get(MIXER_IRQ_STATUS) & 0x0F;
211*433d6423SLionel Sambuc }
212*433d6423SLionel Sambuc 
213*433d6423SLionel Sambuc 
214*433d6423SLionel Sambuc 
drv_int(int sub_dev)215*433d6423SLionel Sambuc int drv_int(int sub_dev) {
216*433d6423SLionel Sambuc 	return sub_dev == AUDIO && mixer_get(MIXER_IRQ_STATUS) & 0x03;
217*433d6423SLionel Sambuc }
218*433d6423SLionel Sambuc 
219*433d6423SLionel Sambuc 
220*433d6423SLionel Sambuc 
drv_pause(int chan)221*433d6423SLionel Sambuc int drv_pause(int chan) {
222*433d6423SLionel Sambuc 	drv_stop(chan);
223*433d6423SLionel Sambuc 	return OK;
224*433d6423SLionel Sambuc }
225*433d6423SLionel Sambuc 
226*433d6423SLionel Sambuc 
227*433d6423SLionel Sambuc 
drv_resume(int UNUSED (chan))228*433d6423SLionel Sambuc int drv_resume(int UNUSED(chan)) {
229*433d6423SLionel Sambuc 	dsp_command((DspBits == 8 ? DSP_CMD_DMA8CONT : DSP_CMD_DMA16CONT));
230*433d6423SLionel Sambuc 	return OK;
231*433d6423SLionel Sambuc }
232*433d6423SLionel Sambuc 
233*433d6423SLionel Sambuc 
234*433d6423SLionel Sambuc 
drv_io_ctl(unsigned long request,void * val,int * len,int sub_dev)235*433d6423SLionel Sambuc int drv_io_ctl(unsigned long request, void *val, int *len, int sub_dev) {
236*433d6423SLionel Sambuc 	Dprint(("dsp_ioctl: got ioctl %lu, argument: %d sub_dev: %d\n",
237*433d6423SLionel Sambuc 		request, val, sub_dev));
238*433d6423SLionel Sambuc 
239*433d6423SLionel Sambuc 	if(sub_dev == AUDIO) {
240*433d6423SLionel Sambuc 		return dsp_ioctl(request, val, len);
241*433d6423SLionel Sambuc 	} else if(sub_dev == MIXER) {
242*433d6423SLionel Sambuc 		return mixer_ioctl(request, val, len);
243*433d6423SLionel Sambuc 	}
244*433d6423SLionel Sambuc 
245*433d6423SLionel Sambuc 	return EIO;
246*433d6423SLionel Sambuc }
247*433d6423SLionel Sambuc 
248*433d6423SLionel Sambuc 
249*433d6423SLionel Sambuc 
drv_get_irq(char * irq)250*433d6423SLionel Sambuc int drv_get_irq(char *irq) {
251*433d6423SLionel Sambuc 	Dprint(("drv_get_irq():\n"));
252*433d6423SLionel Sambuc 	*irq = SB_IRQ;
253*433d6423SLionel Sambuc 	return OK;
254*433d6423SLionel Sambuc }
255*433d6423SLionel Sambuc 
256*433d6423SLionel Sambuc 
257*433d6423SLionel Sambuc 
drv_get_frag_size(u32_t * frag_size,int UNUSED (sub_dev))258*433d6423SLionel Sambuc int drv_get_frag_size(u32_t *frag_size, int UNUSED(sub_dev)) {
259*433d6423SLionel Sambuc 	Dprint(("drv_get_frag_size():\n"));
260*433d6423SLionel Sambuc 	*frag_size = DspFragmentSize;
261*433d6423SLionel Sambuc 	return OK;
262*433d6423SLionel Sambuc }
263*433d6423SLionel Sambuc 
264*433d6423SLionel Sambuc 
265*433d6423SLionel Sambuc 
dsp_ioctl(unsigned long request,void * val,int * len)266*433d6423SLionel Sambuc static int dsp_ioctl(unsigned long request, void *val, int *len) {
267*433d6423SLionel Sambuc 	int status;
268*433d6423SLionel Sambuc 
269*433d6423SLionel Sambuc 	switch(request) {
270*433d6423SLionel Sambuc 		case DSPIORATE:		status = dsp_set_speed(*((u32_t*) val)); break;
271*433d6423SLionel Sambuc 		case DSPIOSTEREO:	status = dsp_set_stereo(*((u32_t*) val)); break;
272*433d6423SLionel Sambuc 		case DSPIOBITS:		status = dsp_set_bits(*((u32_t*) val)); break;
273*433d6423SLionel Sambuc 		case DSPIOSIZE:		status = dsp_set_size(*((u32_t*) val)); break;
274*433d6423SLionel Sambuc 		case DSPIOSIGN:		status = dsp_set_sign(*((u32_t*) val)); break;
275*433d6423SLionel Sambuc 		case DSPIOMAX:		status = dsp_get_max_frag_size(val, len); break;
276*433d6423SLionel Sambuc 		case DSPIORESET:    status = drv_reset(); break;
277*433d6423SLionel Sambuc 		default:            status = ENOTTY; break;
278*433d6423SLionel Sambuc 	}
279*433d6423SLionel Sambuc 
280*433d6423SLionel Sambuc 	return status;
281*433d6423SLionel Sambuc }
282*433d6423SLionel Sambuc 
283*433d6423SLionel Sambuc 
284*433d6423SLionel Sambuc 
dsp_dma_setup(phys_bytes address,int count,int DmaMode)285*433d6423SLionel Sambuc static void dsp_dma_setup(phys_bytes address, int count, int DmaMode) {
286*433d6423SLionel Sambuc 	pvb_pair_t pvb[9];
287*433d6423SLionel Sambuc 
288*433d6423SLionel Sambuc 	Dprint(("Setting up %d bit DMA\n", DspBits));
289*433d6423SLionel Sambuc 
290*433d6423SLionel Sambuc 	if(DspBits == 8) {   /* 8 bit sound */
291*433d6423SLionel Sambuc 		count--;
292*433d6423SLionel Sambuc 
293*433d6423SLionel Sambuc 		pv_set(pvb[0], DMA8_MASK, SB_DMA_8 | 0x04);      /* Disable DMA channel */
294*433d6423SLionel Sambuc 		pv_set(pvb[1], DMA8_CLEAR, 0x00);		       /* Clear flip flop */
295*433d6423SLionel Sambuc 
296*433d6423SLionel Sambuc 		/* set DMA mode */
297*433d6423SLionel Sambuc 		pv_set(pvb[2], DMA8_MODE, (DmaMode == WRITE_DMA ? DMA8_AUTO_PLAY : DMA8_AUTO_REC));
298*433d6423SLionel Sambuc 
299*433d6423SLionel Sambuc 		pv_set(pvb[3], DMA8_ADDR, (u8_t)(address >>  0)); /* Low_byte of address */
300*433d6423SLionel Sambuc 		pv_set(pvb[4], DMA8_ADDR, (u8_t)(address >>  8)); /* High byte of address */
301*433d6423SLionel Sambuc 		pv_set(pvb[5], DMA8_PAGE, (u8_t)(address >> 16)); /* 64K page number */
302*433d6423SLionel Sambuc 		pv_set(pvb[6], DMA8_COUNT, (u8_t)(count >> 0));   /* Low byte of count */
303*433d6423SLionel Sambuc 		pv_set(pvb[7], DMA8_COUNT, (u8_t)(count >> 8));   /* High byte of count */
304*433d6423SLionel Sambuc 		pv_set(pvb[8], DMA8_MASK, SB_DMA_8);              /* Enable DMA channel */
305*433d6423SLionel Sambuc 
306*433d6423SLionel Sambuc 		sys_voutb(pvb, 9);
307*433d6423SLionel Sambuc 	} else {  /* 16 bit sound */
308*433d6423SLionel Sambuc 		count -= 2;
309*433d6423SLionel Sambuc 
310*433d6423SLionel Sambuc 		pv_set(pvb[0], DMA16_MASK, (SB_DMA_16 & 3) | 0x04);	/* Disable DMA channel */
311*433d6423SLionel Sambuc 
312*433d6423SLionel Sambuc 		pv_set(pvb[1], DMA16_CLEAR, 0x00);                  /* Clear flip flop */
313*433d6423SLionel Sambuc 
314*433d6423SLionel Sambuc 		/* Set dma mode */
315*433d6423SLionel Sambuc 		pv_set(pvb[2], DMA16_MODE, (DmaMode == WRITE_DMA ? DMA16_AUTO_PLAY : DMA16_AUTO_REC));
316*433d6423SLionel Sambuc 
317*433d6423SLionel Sambuc 		pv_set(pvb[3], DMA16_ADDR, (address >> 1) & 0xFF);  /* Low_byte of address */
318*433d6423SLionel Sambuc 		pv_set(pvb[4], DMA16_ADDR, (address >> 9) & 0xFF);  /* High byte of address */
319*433d6423SLionel Sambuc 		pv_set(pvb[5], DMA16_PAGE, (address >> 16) & 0xFE); /* 128K page number */
320*433d6423SLionel Sambuc 		pv_set(pvb[6], DMA16_COUNT, (u8_t)(count >> 1));    /* Low byte of count */
321*433d6423SLionel Sambuc 		pv_set(pvb[7], DMA16_COUNT, (u8_t)(count >> 9));    /* High byte of count */
322*433d6423SLionel Sambuc 		pv_set(pvb[8], DMA16_MASK, SB_DMA_16 & 3);          /* Enable DMA channel */
323*433d6423SLionel Sambuc 
324*433d6423SLionel Sambuc 		sys_voutb(pvb, 9);
325*433d6423SLionel Sambuc 	}
326*433d6423SLionel Sambuc }
327*433d6423SLionel Sambuc 
328*433d6423SLionel Sambuc 
329*433d6423SLionel Sambuc 
dsp_set_size(unsigned int size)330*433d6423SLionel Sambuc static int dsp_set_size(unsigned int size) {
331*433d6423SLionel Sambuc 	Dprint(("dsp_set_size(): set fragment size to %u\n", size));
332*433d6423SLionel Sambuc 
333*433d6423SLionel Sambuc 	/* Sanity checks */
334*433d6423SLionel Sambuc 	if(size < sub_dev[AUDIO].MinFragmentSize || size > sub_dev[AUDIO].DmaSize / sub_dev[AUDIO].NrOfDmaFragments || size % 2 != 0) {
335*433d6423SLionel Sambuc 		return EINVAL;
336*433d6423SLionel Sambuc 	}
337*433d6423SLionel Sambuc 
338*433d6423SLionel Sambuc 	DspFragmentSize = size;
339*433d6423SLionel Sambuc 
340*433d6423SLionel Sambuc 	return OK;
341*433d6423SLionel Sambuc }
342*433d6423SLionel Sambuc 
343*433d6423SLionel Sambuc 
344*433d6423SLionel Sambuc 
dsp_set_speed(unsigned int speed)345*433d6423SLionel Sambuc static int dsp_set_speed(unsigned int speed) {
346*433d6423SLionel Sambuc 	Dprint(("sb16: setting speed to %u, stereo = %d\n", speed, DspStereo));
347*433d6423SLionel Sambuc 
348*433d6423SLionel Sambuc 	if(speed < DSP_MIN_SPEED || speed > DSP_MAX_SPEED) {
349*433d6423SLionel Sambuc 		return EPERM;
350*433d6423SLionel Sambuc 	}
351*433d6423SLionel Sambuc 
352*433d6423SLionel Sambuc 	/* Soundblaster 16 can be programmed with real sample rates
353*433d6423SLionel Sambuc 	* instead of time constants
354*433d6423SLionel Sambuc 	*
355*433d6423SLionel Sambuc 	* Since you cannot sample and play at the same time
356*433d6423SLionel Sambuc 	* we set in- and output rate to the same value
357*433d6423SLionel Sambuc 	*/
358*433d6423SLionel Sambuc 
359*433d6423SLionel Sambuc 	dsp_command(DSP_INPUT_RATE);		/* set input rate */
360*433d6423SLionel Sambuc 	dsp_command(speed >> 8);			/* high byte of speed */
361*433d6423SLionel Sambuc 	dsp_command(speed);			 		/* low byte of speed */
362*433d6423SLionel Sambuc 	dsp_command(DSP_OUTPUT_RATE);		/* same for output rate */
363*433d6423SLionel Sambuc 	dsp_command(speed >> 8);
364*433d6423SLionel Sambuc 	dsp_command(speed);
365*433d6423SLionel Sambuc 
366*433d6423SLionel Sambuc 	DspSpeed = speed;
367*433d6423SLionel Sambuc 
368*433d6423SLionel Sambuc 	return OK;
369*433d6423SLionel Sambuc }
370*433d6423SLionel Sambuc 
371*433d6423SLionel Sambuc 
372*433d6423SLionel Sambuc 
dsp_set_stereo(unsigned int stereo)373*433d6423SLionel Sambuc static int dsp_set_stereo(unsigned int stereo) {
374*433d6423SLionel Sambuc 	if(stereo) {
375*433d6423SLionel Sambuc 		DspStereo = 1;
376*433d6423SLionel Sambuc 	} else {
377*433d6423SLionel Sambuc 		DspStereo = 0;
378*433d6423SLionel Sambuc 	}
379*433d6423SLionel Sambuc 
380*433d6423SLionel Sambuc 	return OK;
381*433d6423SLionel Sambuc }
382*433d6423SLionel Sambuc 
383*433d6423SLionel Sambuc 
384*433d6423SLionel Sambuc 
dsp_set_bits(unsigned int bits)385*433d6423SLionel Sambuc static int dsp_set_bits(unsigned int bits) {
386*433d6423SLionel Sambuc 	/* Sanity checks */
387*433d6423SLionel Sambuc 	if(bits != 8 && bits != 16) {
388*433d6423SLionel Sambuc 		return EINVAL;
389*433d6423SLionel Sambuc 	}
390*433d6423SLionel Sambuc 
391*433d6423SLionel Sambuc 	DspBits = bits;
392*433d6423SLionel Sambuc 
393*433d6423SLionel Sambuc 	return OK;
394*433d6423SLionel Sambuc }
395*433d6423SLionel Sambuc 
396*433d6423SLionel Sambuc 
397*433d6423SLionel Sambuc 
dsp_set_sign(unsigned int sign)398*433d6423SLionel Sambuc static int dsp_set_sign(unsigned int sign) {
399*433d6423SLionel Sambuc 	Dprint(("sb16: set sign to %u\n", sign));
400*433d6423SLionel Sambuc 
401*433d6423SLionel Sambuc 	DspSign = (sign > 0 ? 1 : 0);
402*433d6423SLionel Sambuc 
403*433d6423SLionel Sambuc 	return OK;
404*433d6423SLionel Sambuc }
405*433d6423SLionel Sambuc 
406*433d6423SLionel Sambuc 
407*433d6423SLionel Sambuc 
dsp_get_max_frag_size(u32_t * val,int * len)408*433d6423SLionel Sambuc static int dsp_get_max_frag_size(u32_t *val, int *len) {
409*433d6423SLionel Sambuc 	*len = sizeof(*val);
410*433d6423SLionel Sambuc 	*val = sub_dev[AUDIO].DmaSize / sub_dev[AUDIO].NrOfDmaFragments;
411*433d6423SLionel Sambuc 	return OK;
412*433d6423SLionel Sambuc }
413*433d6423SLionel Sambuc 
414*433d6423SLionel Sambuc 
415*433d6423SLionel Sambuc 
dsp_command(int value)416*433d6423SLionel Sambuc int dsp_command(int value) {
417*433d6423SLionel Sambuc 	int i;
418*433d6423SLionel Sambuc 
419*433d6423SLionel Sambuc 	for (i = 0; i < SB_TIMEOUT; i++) {
420*433d6423SLionel Sambuc 		if((sb16_inb(DSP_STATUS) & 0x80) == 0) {
421*433d6423SLionel Sambuc 			sb16_outb(DSP_COMMAND, value);
422*433d6423SLionel Sambuc 			return OK;
423*433d6423SLionel Sambuc 		}
424*433d6423SLionel Sambuc 	}
425*433d6423SLionel Sambuc 
426*433d6423SLionel Sambuc 	Dprint(("sb16: SoundBlaster: DSP Command(%x) timeout\n", value));
427*433d6423SLionel Sambuc 	return -1;
428*433d6423SLionel Sambuc }
429*433d6423SLionel Sambuc 
430*433d6423SLionel Sambuc 
431*433d6423SLionel Sambuc 
sb16_inb(int port)432*433d6423SLionel Sambuc int sb16_inb(int port) {
433*433d6423SLionel Sambuc 	int s;
434*433d6423SLionel Sambuc 	u32_t value;
435*433d6423SLionel Sambuc 
436*433d6423SLionel Sambuc 	if ((s=sys_inb(port, &value)) != OK)
437*433d6423SLionel Sambuc 		panic("sys_inb() failed: %d", s);
438*433d6423SLionel Sambuc 
439*433d6423SLionel Sambuc 	return (int) value;
440*433d6423SLionel Sambuc }
441*433d6423SLionel Sambuc 
442*433d6423SLionel Sambuc 
443*433d6423SLionel Sambuc 
sb16_outb(int port,int value)444*433d6423SLionel Sambuc void sb16_outb(int port, int value) {
445*433d6423SLionel Sambuc 	int s;
446*433d6423SLionel Sambuc 
447*433d6423SLionel Sambuc 	if ((s=sys_outb(port, value)) != OK)
448*433d6423SLionel Sambuc 		panic("sys_outb() failed: %d", s);
449*433d6423SLionel Sambuc }
450