Annotation of sys/dev/pci/maestro.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: maestro.c,v 1.21 2006/12/29 13:04:37 pedro Exp $ */
2: /* $FreeBSD: /c/ncvs/src/sys/dev/sound/pci/maestro.c,v 1.3 2000/11/21 12:22:11 julian Exp $ */
3: /*
4: * FreeBSD's ESS Agogo/Maestro driver
5: * Converted from FreeBSD's pcm to OpenBSD's audio.
6: * Copyright (c) 2000, 2001 David Leonard & Marc Espie
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28: * SUCH DAMAGE.
29: */
30: /*-
31: * (FreeBSD) Credits:
32: * Copyright (c) 2000 Taku YAMAMOTO <taku@cent.saitama-u.ac.jp>
33: *
34: * Part of this code (especially in many magic numbers) was heavily inspired
35: * by the Linux driver originally written by
36: * Alan Cox <alan.cox@linux.org>, modified heavily by
37: * Zach Brown <zab@zabbo.net>.
38: *
39: * busdma()-ize and buffer size reduction were suggested by
40: * Cameron Grant <gandalf@vilnya.demon.co.uk>.
41: * Also he showed me the way to use busdma() suite.
42: *
43: * Internal speaker problems on NEC VersaPro's and Dell Inspiron 7500
44: * were looked at by
45: * Munehiro Matsuda <haro@tk.kubota.co.jp>,
46: * who brought patches based on the Linux driver with some simplification.
47: */
48:
49: #include <sys/param.h>
50: #include <sys/systm.h>
51: #include <sys/kernel.h>
52: #include <sys/malloc.h>
53: #include <sys/device.h>
54: #include <sys/proc.h>
55: #include <sys/queue.h>
56: #include <sys/fcntl.h>
57:
58: #include <dev/pci/pcidevs.h>
59: #include <dev/pci/pcivar.h>
60:
61: #include <sys/audioio.h>
62: #include <dev/audio_if.h>
63: #include <dev/mulaw.h>
64: #include <dev/auconv.h>
65:
66: #include <dev/ic/ac97.h>
67:
68: /* -----------------------------
69: * PCI config registers
70: */
71:
72: /* Legacy emulation */
73: #define CONF_LEGACY 0x40
74:
75: #define LEGACY_DISABLED 0x8000
76:
77: /* Chip configurations */
78: #define CONF_MAESTRO 0x50
79: #define MAESTRO_CHIBUS 0x00100000
80: #define MAESTRO_POSTEDWRITE 0x00000080
81: #define MAESTRO_DMA_PCITIMING 0x00000040
82: #define MAESTRO_SWAP_LR 0x00000010
83:
84: /* ACPI configurations */
85: #define CONF_ACPI_STOPCLOCK 0x54
86: #define ACPI_PART_2ndC_CLOCK 15
87: #define ACPI_PART_CODEC_CLOCK 14
88: #define ACPI_PART_978 13 /* Docking station or something */
89: #define ACPI_PART_SPDIF 12
90: #define ACPI_PART_GLUE 11 /* What? */
91: #define ACPI_PART_DAA 10
92: #define ACPI_PART_PCI_IF 9
93: #define ACPI_PART_HW_VOL 8
94: #define ACPI_PART_GPIO 7
95: #define ACPI_PART_ASSP 6
96: #define ACPI_PART_SB 5
97: #define ACPI_PART_FM 4
98: #define ACPI_PART_RINGBUS 3
99: #define ACPI_PART_MIDI 2
100: #define ACPI_PART_GAME_PORT 1
101: #define ACPI_PART_WP 0
102:
103: /* Power management */
104: #define CONF_PM_PTR 0x34 /* BYTE R */
105: #define PM_CID 0 /* BYTE R */
106: #define PPMI_CID 1
107: #define PM_CTRL 4 /* BYTE RW */
108: #define PPMI_D0 0 /* Full power */
109: #define PPMI_D1 1 /* Medium power */
110: #define PPMI_D2 2 /* Low power */
111: #define PPMI_D3 3 /* Turned off */
112:
113:
114: /* -----------------------------
115: * I/O ports
116: */
117:
118: /* Direct Sound Processor (aka Wave Processor) */
119: #define PORT_DSP_DATA 0x00 /* WORD RW */
120: #define PORT_DSP_INDEX 0x02 /* WORD RW */
121: #define PORT_INT_STAT 0x04 /* WORD RW */
122: #define PORT_SAMPLE_CNT 0x06 /* WORD RO */
123:
124: /* WaveCache */
125: #define PORT_WAVCACHE_INDEX 0x10 /* WORD RW */
126: #define PORT_WAVCACHE_DATA 0x12 /* WORD RW */
127: #define WAVCACHE_PCMBAR 0x1fc
128: #define WAVCACHE_WTBAR 0x1f0
129: #define WAVCACHE_BASEADDR_SHIFT 12
130:
131: #define WAVCACHE_CHCTL_ADDRTAG_MASK 0xfff8
132: #define WAVCACHE_CHCTL_U8 0x0004
133: #define WAVCACHE_CHCTL_STEREO 0x0002
134: #define WAVCACHE_CHCTL_DECREMENTAL 0x0001
135:
136: #define PORT_WAVCACHE_CTRL 0x14 /* WORD RW */
137: #define WAVCACHE_EXTRA_CH_ENABLED 0x0200
138: #define WAVCACHE_ENABLED 0x0100
139: #define WAVCACHE_CH_60_ENABLED 0x0080
140: #define WAVCACHE_WTSIZE_MASK 0x0060
141: #define WAVCACHE_WTSIZE_1MB 0x0000
142: #define WAVCACHE_WTSIZE_2MB 0x0020
143: #define WAVCACHE_WTSIZE_4MB 0x0040
144: #define WAVCACHE_WTSIZE_8MB 0x0060
145: #define WAVCACHE_SGC_MASK 0x000c
146: #define WAVCACHE_SGC_DISABLED 0x0000
147: #define WAVCACHE_SGC_40_47 0x0004
148: #define WAVCACHE_SGC_32_47 0x0008
149: #define WAVCACHE_TESTMODE 0x0001
150:
151: /* Host Interruption */
152: #define PORT_HOSTINT_CTRL 0x18 /* WORD RW */
153: #define HOSTINT_CTRL_SOFT_RESET 0x8000
154: #define HOSTINT_CTRL_DSOUND_RESET 0x4000
155: #define HOSTINT_CTRL_HW_VOL_TO_PME 0x0400
156: #define HOSTINT_CTRL_CLKRUN_ENABLED 0x0100
157: #define HOSTINT_CTRL_HWVOL_ENABLED 0x0040
158: #define HOSTINT_CTRL_ASSP_INT_ENABLED 0x0010
159: #define HOSTINT_CTRL_ISDN_INT_ENABLED 0x0008
160: #define HOSTINT_CTRL_DSOUND_INT_ENABLED 0x0004
161: #define HOSTINT_CTRL_MPU401_INT_ENABLED 0x0002
162: #define HOSTINT_CTRL_SB_INT_ENABLED 0x0001
163:
164: #define PORT_HOSTINT_STAT 0x1a /* BYTE RW */
165: #define HOSTINT_STAT_HWVOL 0x40
166: #define HOSTINT_STAT_ASSP 0x10
167: #define HOSTINT_STAT_ISDN 0x08
168: #define HOSTINT_STAT_DSOUND 0x04
169: #define HOSTINT_STAT_MPU401 0x02
170: #define HOSTINT_STAT_SB 0x01
171:
172: /* Hardware volume */
173: #define PORT_HWVOL_VOICE_SHADOW 0x1c /* BYTE RW */
174: #define PORT_HWVOL_VOICE 0x1d /* BYTE RW */
175: #define PORT_HWVOL_MASTER_SHADOW 0x1e /* BYTE RW */
176: #define PORT_HWVOL_MASTER 0x1f /* BYTE RW */
177:
178: /* CODEC */
179: #define PORT_CODEC_CMD 0x30 /* BYTE W */
180: #define CODEC_CMD_READ 0x80
181: #define CODEC_CMD_WRITE 0x00
182: #define CODEC_CMD_ADDR_MASK 0x7f
183:
184: #define PORT_CODEC_STAT 0x30 /* BYTE R */
185: #define CODEC_STAT_MASK 0x01
186: #define CODEC_STAT_RW_DONE 0x00
187: #define CODEC_STAT_PROGLESS 0x01
188:
189: #define PORT_CODEC_REG 0x32 /* WORD RW */
190:
191: /* Ring bus control */
192: #define PORT_RINGBUS_CTRL 0x34 /* DWORD RW */
193: #define RINGBUS_CTRL_I2S_ENABLED 0x80000000
194: #define RINGBUS_CTRL_RINGBUS_ENABLED 0x20000000
195: #define RINGBUS_CTRL_ACLINK_ENABLED 0x10000000
196: #define RINGBUS_CTRL_AC97_SWRESET 0x08000000
197: #define RINGBUS_CTRL_IODMA_PLAYBACK_ENABLED 0x04000000
198: #define RINGBUS_CTRL_IODMA_RECORD_ENABLED 0x02000000
199:
200: #define RINGBUS_SRC_MIC 20
201: #define RINGBUS_SRC_I2S 16
202: #define RINGBUS_SRC_ADC 12
203: #define RINGBUS_SRC_MODEM 8
204: #define RINGBUS_SRC_DSOUND 4
205: #define RINGBUS_SRC_ASSP 0
206:
207: #define RINGBUS_DEST_MONORAL 000
208: #define RINGBUS_DEST_STEREO 010
209: #define RINGBUS_DEST_NONE 0
210: #define RINGBUS_DEST_DAC 1
211: #define RINGBUS_DEST_MODEM_IN 2
212: #define RINGBUS_DEST_RESERVED3 3
213: #define RINGBUS_DEST_DSOUND_IN 4
214: #define RINGBUS_DEST_ASSP_IN 5
215:
216: /* General Purpose I/O */
217: #define PORT_GPIO_DATA 0x60 /* WORD RW */
218: #define PORT_GPIO_MASK 0x64 /* WORD RW */
219: #define PORT_GPIO_DIR 0x68 /* WORD RW */
220:
221: /* Application Specific Signal Processor */
222: #define PORT_ASSP_MEM_INDEX 0x80 /* DWORD RW */
223: #define PORT_ASSP_MEM_DATA 0x84 /* WORD RW */
224: #define PORT_ASSP_CTRL_A 0xa2 /* BYTE RW */
225: #define PORT_ASSP_CTRL_B 0xa4 /* BYTE RW */
226: #define PORT_ASSP_CTRL_C 0xa6 /* BYTE RW */
227: #define PORT_ASSP_HOST_WR_INDEX 0xa8 /* BYTE W */
228: #define PORT_ASSP_HOST_WR_DATA 0xaa /* BYTE RW */
229: #define PORT_ASSP_INT_STAT 0xac /* BYTE RW */
230:
231:
232: /* -----------------------------
233: * Wave Processor Indexed Data Registers.
234: */
235:
236: #define WPREG_DATA_PORT 0
237: #define WPREG_CRAM_PTR 1
238: #define WPREG_CRAM_DATA 2
239: #define WPREG_WAVE_DATA 3
240: #define WPREG_WAVE_PTR_LOW 4
241: #define WPREG_WAVE_PTR_HIGH 5
242:
243: #define WPREG_TIMER_FREQ 6
244: #define WP_TIMER_FREQ_PRESCALE_MASK 0x00e0 /* actual - 9 */
245: #define WP_TIMER_FREQ_PRESCALE_SHIFT 5
246: #define WP_TIMER_FREQ_DIVIDE_MASK 0x001f
247: #define WP_TIMER_FREQ_DIVIDE_SHIFT 0
248:
249: #define WPREG_WAVE_ROMRAM 7
250: #define WP_WAVE_VIRTUAL_ENABLED 0x0400
251: #define WP_WAVE_8BITRAM_ENABLED 0x0200
252: #define WP_WAVE_DRAM_ENABLED 0x0100
253: #define WP_WAVE_RAMSPLIT_MASK 0x00ff
254: #define WP_WAVE_RAMSPLIT_SHIFT 0
255:
256: #define WPREG_BASE 12
257: #define WP_PARAOUT_BASE_MASK 0xf000
258: #define WP_PARAOUT_BASE_SHIFT 12
259: #define WP_PARAIN_BASE_MASK 0x0f00
260: #define WP_PARAIN_BASE_SHIFT 8
261: #define WP_SERIAL0_BASE_MASK 0x00f0
262: #define WP_SERIAL0_BASE_SHIFT 4
263: #define WP_SERIAL1_BASE_MASK 0x000f
264: #define WP_SERIAL1_BASE_SHIFT 0
265:
266: #define WPREG_TIMER_ENABLE 17
267: #define WPREG_TIMER_START 23
268:
269:
270: /* -----------------------------
271: * Audio Processing Unit.
272: */
273: #define APUREG_APUTYPE 0
274: #define APU_DMA_ENABLED 0x4000
275: #define APU_INT_ON_LOOP 0x2000
276: #define APU_ENDCURVE 0x1000
277: #define APU_APUTYPE_MASK 0x00f0
278: #define APU_FILTERTYPE_MASK 0x000c
279: #define APU_FILTERQ_MASK 0x0003
280:
281: /* APU types */
282: #define APU_APUTYPE_SHIFT 4
283:
284: #define APUTYPE_INACTIVE 0
285: #define APUTYPE_16BITLINEAR 1
286: #define APUTYPE_16BITSTEREO 2
287: #define APUTYPE_8BITLINEAR 3
288: #define APUTYPE_8BITSTEREO 4
289: #define APUTYPE_8BITDIFF 5
290: #define APUTYPE_DIGITALDELAY 6
291: #define APUTYPE_DUALTAP_READER 7
292: #define APUTYPE_CORRELATOR 8
293: #define APUTYPE_INPUTMIXER 9
294: #define APUTYPE_WAVETABLE 10
295: #define APUTYPE_RATECONV 11
296: #define APUTYPE_16BITPINGPONG 12
297: /* APU type 13 through 15 are reserved. */
298:
299: /* Filter types */
300: #define APU_FILTERTYPE_SHIFT 2
301:
302: #define FILTERTYPE_2POLE_LOPASS 0
303: #define FILTERTYPE_2POLE_BANDPASS 1
304: #define FILTERTYPE_2POLE_HIPASS 2
305: #define FILTERTYPE_1POLE_LOPASS 3
306: #define FILTERTYPE_1POLE_HIPASS 4
307: #define FILTERTYPE_PASSTHROUGH 5
308:
309: /* Filter Q */
310: #define APU_FILTERQ_SHIFT 0
311:
312: #define FILTERQ_LESSQ 0
313: #define FILTERQ_MOREQ 3
314:
315: /* APU register 2 */
316: #define APUREG_FREQ_LOBYTE 2
317: #define APU_FREQ_LOBYTE_MASK 0xff00
318: #define APU_plus6dB 0x0010
319:
320: /* APU register 3 */
321: #define APUREG_FREQ_HIWORD 3
322: #define APU_FREQ_HIWORD_MASK 0x0fff
323:
324: /* Frequency */
325: #define APU_FREQ_LOBYTE_SHIFT 8
326: #define APU_FREQ_HIWORD_SHIFT 0
327: #define FREQ_Hz2DIV(freq) (((u_int64_t)(freq) << 16) / 48000)
328:
329: /* APU register 4 */
330: #define APUREG_WAVESPACE 4
331: #define APU_STEREO 0x8000
332: #define APU_USE_SYSMEM 0x4000
333: #define APU_PCMBAR_MASK 0x6000
334: #define APU_64KPAGE_MASK 0xff00
335:
336: /* PCM Base Address Register selection */
337: #define APU_PCMBAR_SHIFT 13
338:
339: /* 64KW (==128KB) Page */
340: #define APU_64KPAGE_SHIFT 8
341:
342: /* APU register 5 - 7 */
343: #define APUREG_CURPTR 5
344: #define APUREG_ENDPTR 6
345: #define APUREG_LOOPLEN 7
346:
347: /* APU register 9 */
348: #define APUREG_AMPLITUDE 9
349: #define APU_AMPLITUDE_NOW_MASK 0xff00
350: #define APU_AMPLITUDE_DEST_MASK 0x00ff
351:
352: /* Amplitude now? */
353: #define APU_AMPLITUDE_NOW_SHIFT 8
354:
355: /* APU register 10 */
356: #define APUREG_POSITION 10
357: #define APU_RADIUS_MASK 0x00c0
358: #define APU_PAN_MASK 0x003f
359:
360: /* Radius control. */
361: #define APU_RADIUS_SHIFT 6
362: #define RADIUS_CENTERCIRCLE 0
363: #define RADIUS_MIDDLE 1
364: #define RADIUS_OUTSIDE 2
365:
366: /* Polar pan. */
367: #define APU_PAN_SHIFT 0
368: #define PAN_RIGHT 0x00
369: #define PAN_FRONT 0x08
370: #define PAN_LEFT 0x10
371:
372:
373: /* -----------------------------
374: * Limits.
375: */
376: #define WPWA_MAX ((1 << 22) - 1)
377: #define WPWA_MAXADDR ((1 << 23) - 1)
378: #define MAESTRO_MAXADDR ((1 << 28) - 1)
379:
380:
381:
382: #ifdef AUDIO_DEBUG
383: #define DPRINTF(x) if (maestrodebug) printf x
384: #define DLPRINTF(i, x) if (maestrodebug & i) printf x
385: int maestrodebug = 0;
386: u_long maestrointr_called;
387: u_long maestrodma_effective;
388:
389: #define MAESTRODEBUG_INTR 1
390: #define MAESTRODEBUG_TIMER 2
391: #else
392: #define DPRINTF(x)
393: #define DLPRINTF(i, x)
394: #endif
395:
396: #define MAESTRO_BUFSIZ 0x4000
397: #define lengthof(array) (sizeof (array) / sizeof (array)[0])
398:
399: #define STEP_VOLUME 0x22
400: #define MIDDLE_VOLUME (STEP_VOLUME * 4)
401:
402: typedef struct salloc_pool {
403: struct salloc_zone {
404: SLIST_ENTRY(salloc_zone) link;
405: caddr_t addr;
406: size_t size;
407: } *zones;
408: SLIST_HEAD(salloc_head, salloc_zone) free, used, spare;
409: } *salloc_t;
410:
411: struct maestro_softc;
412:
413: #define MAESTRO_PLAY 1
414: #define MAESTRO_STEREO 2
415: #define MAESTRO_8BIT 4
416: #define MAESTRO_UNSIGNED 8
417: #define MAESTRO_RUNNING 16
418:
419: struct maestro_channel {
420: struct maestro_softc *sc;
421: int num;
422: u_int32_t blocksize;
423: u_int16_t mode;
424: u_int32_t speed;
425: u_int32_t dv;
426: u_int16_t start;
427: u_int16_t threshold;
428: u_int16_t end;
429: u_int16_t current;
430: u_int wpwa;
431: void (*intr)(void *);
432: void *intr_arg;
433: };
434:
435: struct maestro_softc {
436: struct device dev;
437:
438: void *ih;
439: pci_chipset_tag_t pc;
440: pcitag_t pt;
441:
442: #define MAESTRO_FLAG_SETUPGPIO 0x0001
443: int flags;
444: bus_space_tag_t iot;
445: bus_space_handle_t ioh;
446: bus_dma_tag_t dmat;
447:
448: caddr_t dmabase;
449: bus_addr_t physaddr;
450: size_t dmasize;
451: bus_dmamap_t dmamap;
452: bus_dma_segment_t dmaseg;
453: salloc_t dmapool;
454:
455: struct ac97_codec_if *codec_if;
456: struct ac97_host_if host_if;
457: struct audio_device *sc_audev;
458:
459: void *powerhook;
460: int suspend;
461:
462: struct maestro_channel play;
463: struct maestro_channel record;
464: };
465:
466:
467: typedef u_int16_t wpreg_t;
468: typedef u_int16_t wcreg_t;
469:
470: salloc_t salloc_new(caddr_t, size_t, int);
471: void salloc_destroy(salloc_t);
472: caddr_t salloc_alloc(salloc_t, size_t);
473: void salloc_free(salloc_t, caddr_t);
474: void salloc_insert(salloc_t, struct salloc_head *,
475: struct salloc_zone *, int);
476:
477: int maestro_match(struct device *, void *, void *);
478: void maestro_attach(struct device *, struct device *, void *);
479: int maestro_intr(void *);
480:
481: int maestro_open(void *, int);
482: void maestro_close(void *);
483: int maestro_query_encoding(void *, struct audio_encoding *);
484: int maestro_set_params(void *, int, int, struct audio_params *,
485: struct audio_params *);
486: int maestro_round_blocksize(void *, int);
487: int maestro_halt_output(void *);
488: int maestro_halt_input(void *);
489: int maestro_getdev(void *, struct audio_device *);
490: int maestro_set_port(void *, mixer_ctrl_t *);
491: int maestro_get_port(void *, mixer_ctrl_t *);
492: int maestro_query_devinfo(void *, mixer_devinfo_t *);
493: void *maestro_malloc(void *, int, size_t, int, int);
494: void maestro_free(void *, void *, int);
495: paddr_t maestro_mappage(void *, void *, off_t, int);
496: int maestro_get_props(void *);
497: int maestro_trigger_output(void *, void *, void *, int, void (*)(void *),
498: void *, struct audio_params *);
499: int maestro_trigger_input(void *, void *, void *, int, void (*)(void *),
500: void *, struct audio_params *);
501:
502: int maestro_attach_codec(void *, struct ac97_codec_if *);
503: int maestro_read_codec(void *, u_int8_t, u_int16_t *);
504: int maestro_write_codec(void *, u_int8_t, u_int16_t);
505: void maestro_reset_codec(void *);
506:
507: void maestro_initcodec(void *);
508:
509: void maestro_set_speed(struct maestro_channel *, u_long *);
510: void maestro_init(struct maestro_softc *);
511: void maestro_power(struct maestro_softc *, int);
512: void maestro_powerhook(int, void *);
513:
514: void maestro_channel_start(struct maestro_channel *);
515: void maestro_channel_stop(struct maestro_channel *);
516: void maestro_channel_advance_dma(struct maestro_channel *);
517: void maestro_channel_suppress_jitter(struct maestro_channel *);
518:
519: int maestro_get_flags(struct pci_attach_args *);
520:
521: void ringbus_setdest(struct maestro_softc *, int, int);
522:
523: wpreg_t wp_reg_read(struct maestro_softc *, int);
524: void wp_reg_write(struct maestro_softc *, int, wpreg_t);
525: wpreg_t wp_apu_read(struct maestro_softc *, int, int);
526: void wp_apu_write(struct maestro_softc *, int, int, wpreg_t);
527: void wp_settimer(struct maestro_softc *, u_int);
528: void wp_starttimer(struct maestro_softc *);
529: void wp_stoptimer(struct maestro_softc *);
530:
531: wcreg_t wc_reg_read(struct maestro_softc *, int);
532: void wc_reg_write(struct maestro_softc *, int, wcreg_t);
533: wcreg_t wc_ctrl_read(struct maestro_softc *, int);
534: void wc_ctrl_write(struct maestro_softc *, int, wcreg_t);
535:
536: u_int maestro_calc_timer_freq(struct maestro_channel *);
537: void maestro_update_timer(struct maestro_softc *);
538:
539: struct cfdriver maestro_cd = {
540: NULL, "maestro", DV_DULL
541: };
542:
543: struct cfattach maestro_ca = {
544: sizeof (struct maestro_softc), maestro_match, maestro_attach
545: };
546:
547: struct audio_hw_if maestro_hw_if = {
548: maestro_open,
549: maestro_close,
550: NULL,
551: maestro_query_encoding,
552: maestro_set_params,
553: maestro_round_blocksize,
554: NULL,
555: NULL,
556: NULL,
557: NULL,
558: NULL,
559: maestro_halt_output,
560: maestro_halt_input,
561: NULL,
562: maestro_getdev,
563: NULL,
564: maestro_set_port,
565: maestro_get_port,
566: maestro_query_devinfo,
567: maestro_malloc,
568: maestro_free,
569: NULL,
570: maestro_mappage,
571: maestro_get_props,
572: maestro_trigger_output,
573: maestro_trigger_input
574: };
575:
576: struct audio_device maestro_audev = {
577: "ESS Maestro", "", "maestro"
578: };
579:
580: struct {
581: u_short vendor, product;
582: int flags;
583: } maestro_pcitab[] = {
584: { PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_MAESTROII, 0 },
585: { PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_MAESTRO2E, 0 },
586: { PCI_VENDOR_PLATFORM, PCI_PRODUCT_PLATFORM_ES1849, 0 },
587: { PCI_VENDOR_NEC, PCI_PRODUCT_NEC_VERSAMAESTRO, MAESTRO_FLAG_SETUPGPIO },
588: { PCI_VENDOR_NEC, PCI_PRODUCT_NEC_VERSAPRONXVA26D, MAESTRO_FLAG_SETUPGPIO }
589: };
590: #define NMAESTRO_PCITAB lengthof(maestro_pcitab)
591:
592: int
593: maestro_get_flags(pa)
594: struct pci_attach_args *pa;
595: {
596: int i;
597:
598: /* Distinguish audio devices from modems with the same manfid */
599: if (PCI_CLASS(pa->pa_class) != PCI_CLASS_MULTIMEDIA)
600: return (-1);
601: if (PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_MULTIMEDIA_AUDIO)
602: return (-1);
603: for (i = 0; i < NMAESTRO_PCITAB; i++)
604: if (PCI_VENDOR(pa->pa_id) == maestro_pcitab[i].vendor &&
605: PCI_PRODUCT(pa->pa_id) == maestro_pcitab[i].product)
606: return (maestro_pcitab[i].flags);
607: return (-1);
608: }
609:
610: /* -----------------------------
611: * Driver interface.
612: */
613:
614: int
615: maestro_match(parent, match, aux)
616: struct device *parent;
617: void *match;
618: void *aux;
619: {
620: struct pci_attach_args *pa = (struct pci_attach_args *)aux;
621:
622: if (maestro_get_flags(pa) == -1)
623: return (0);
624: else
625: return (1);
626: }
627:
628: void
629: maestro_attach(parent, self, aux)
630: struct device *parent;
631: struct device *self;
632: void *aux;
633: {
634: struct maestro_softc *sc = (struct maestro_softc *)self;
635: struct pci_attach_args *pa = (struct pci_attach_args *)aux;
636: pci_chipset_tag_t pc = pa->pa_pc;
637: char const *intrstr;
638: pci_intr_handle_t ih;
639: int error;
640: u_int16_t cdata;
641: int dmastage = 0;
642: int rseg;
643:
644: sc->sc_audev = &maestro_audev;
645: sc->flags = maestro_get_flags(pa);
646:
647: sc->pc = pa->pa_pc;
648: sc->pt = pa->pa_tag;
649: sc->dmat = pa->pa_dmat;
650:
651: /* Map interrupt */
652: if (pci_intr_map(pa, &ih)) {
653: printf(": couldn't map interrupt\n");
654: return;
655: }
656: intrstr = pci_intr_string(pc, ih);
657: sc->ih = pci_intr_establish(pc, ih, IPL_AUDIO, maestro_intr, sc,
658: sc->dev.dv_xname);
659: if (sc->ih == NULL) {
660: printf(": couldn't establish interrupt");
661: if (intrstr != NULL)
662: printf(" at %s\n", intrstr);
663: return;
664: }
665: printf(": %s", intrstr);
666:
667: /* Rangers, power up */
668: maestro_power(sc, PPMI_D0);
669: DELAY(100000);
670:
671: /* Map i/o */
672: if ((error = pci_mapreg_map(pa, PCI_MAPS, PCI_MAPREG_TYPE_IO,
673: 0, &sc->iot, &sc->ioh, NULL, NULL, 0)) != 0) {
674: printf(", couldn't map i/o space\n");
675: goto bad;
676: };
677:
678: /* Allocate fixed DMA segment :-( */
679: sc->dmasize = MAESTRO_BUFSIZ * 16;
680: if ((error = bus_dmamem_alloc(sc->dmat, sc->dmasize, NBPG, 0,
681: &sc->dmaseg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
682: printf(", unable to alloc dma, error %d\n", error);
683: goto bad;
684: }
685: dmastage = 1;
686: if ((error = bus_dmamem_map(sc->dmat, &sc->dmaseg, 1,
687: sc->dmasize, &sc->dmabase, BUS_DMA_NOWAIT |
688: BUS_DMA_COHERENT)) != 0) {
689: printf(", unable to map dma, error %d\n", error);
690: goto bad;
691: }
692: dmastage = 2;
693: if ((error = bus_dmamap_create(sc->dmat, sc->dmasize, 1,
694: sc->dmasize, 0, BUS_DMA_NOWAIT, &sc->dmamap)) != 0) {
695: printf(", unable to create dma map, error %d\n", error);
696: goto bad;
697: }
698: dmastage = 3;
699: if ((error = bus_dmamap_load(sc->dmat, sc->dmamap,
700: sc->dmabase, sc->dmasize, NULL, BUS_DMA_NOWAIT)) != 0) {
701: printf(", unable to load dma map, error %d\n", error);
702: goto bad;
703: }
704:
705: /* XXX
706: * The first byte of the allocated memory is not usable,
707: * the WP sometimes uses it to store status.
708: */
709: /* Make DMA memory pool */
710: if ((sc->dmapool = salloc_new(sc->dmabase+16, sc->dmasize-16,
711: 128/*overkill?*/)) == NULL) {
712: printf(", unable to make dma pool\n");
713: goto bad;
714: }
715:
716: sc->physaddr = sc->dmamap->dm_segs[0].ds_addr;
717:
718: printf("\n");
719:
720: /* Kick device */
721: maestro_init(sc);
722: maestro_read_codec(sc, 0, &cdata);
723: if (cdata == 0x80) {
724: printf("%s: PT101 codec unsupported, no mixer\n",
725: sc->dev.dv_xname);
726: /* Init values from Linux, no idea what this does. */
727: maestro_write_codec(sc, 0x2a, 0x0001);
728: maestro_write_codec(sc, 0x2C, 0x0000);
729: maestro_write_codec(sc, 0x2C, 0xFFFF);
730: maestro_write_codec(sc, 0x10, 0x9F1F);
731: maestro_write_codec(sc, 0x12, 0x0808);
732: maestro_write_codec(sc, 0x14, 0x9F1F);
733: maestro_write_codec(sc, 0x16, 0x9F1F);
734: maestro_write_codec(sc, 0x18, 0x0404);
735: maestro_write_codec(sc, 0x1A, 0x0000);
736: maestro_write_codec(sc, 0x1C, 0x0000);
737: maestro_write_codec(sc, 0x02, 0x0404);
738: maestro_write_codec(sc, 0x04, 0x0808);
739: maestro_write_codec(sc, 0x0C, 0x801F);
740: maestro_write_codec(sc, 0x0E, 0x801F);
741: /* no control over the mixer, sorry */
742: sc->codec_if = NULL;
743: } else {
744: /* Attach the AC'97 */
745: sc->host_if.arg = sc;
746: sc->host_if.attach = maestro_attach_codec;
747: sc->host_if.read = maestro_read_codec;
748: sc->host_if.write = maestro_write_codec;
749: sc->host_if.reset = maestro_reset_codec;
750: if (ac97_attach(&sc->host_if) != 0) {
751: printf("%s: couldn't attach codec\n", sc->dev.dv_xname);
752: goto bad;
753: }
754: }
755:
756: sc->play.mode = MAESTRO_PLAY;
757: sc->play.sc = sc;
758: sc->play.num = 0;
759: sc->record.sc = sc;
760: sc->record.num = 2;
761: sc->record.mode = 0;
762:
763: /* Attach audio */
764: audio_attach_mi(&maestro_hw_if, sc, &sc->dev);
765:
766: /* Hook power changes */
767: sc->suspend = PWR_RESUME;
768: sc->powerhook = powerhook_establish(maestro_powerhook, sc);
769:
770: return;
771:
772: bad:
773: /* Power down. */
774: maestro_power(sc, PPMI_D3);
775: if (sc->ih)
776: pci_intr_disestablish(pc, sc->ih);
777: printf("%s: disabled\n", sc->dev.dv_xname);
778: if (sc->dmapool)
779: salloc_destroy(sc->dmapool);
780: if (dmastage >= 3)
781: bus_dmamap_destroy(sc->dmat, sc->dmamap);
782: if (dmastage >= 2)
783: bus_dmamem_unmap(sc->dmat, sc->dmabase, sc->dmasize);
784: if (dmastage >= 1)
785: bus_dmamem_free(sc->dmat, &sc->dmaseg, 1);
786: }
787:
788: void
789: maestro_init(sc)
790: struct maestro_softc *sc;
791: {
792: int reg;
793: pcireg_t data;
794:
795: /* Disable all legacy emulations. */
796: data = pci_conf_read(sc->pc, sc->pt, CONF_LEGACY);
797: data |= LEGACY_DISABLED;
798: pci_conf_write(sc->pc, sc->pt, CONF_LEGACY, data);
799:
800: /* Disconnect from CHI. (Makes Dell inspiron 7500 work?)
801: * Enable posted write.
802: * Prefer PCI timing rather than that of ISA.
803: * Don't swap L/R. */
804: data = pci_conf_read(sc->pc, sc->pt, CONF_MAESTRO);
805: data |= MAESTRO_CHIBUS | MAESTRO_POSTEDWRITE | MAESTRO_DMA_PCITIMING;
806: data &= ~MAESTRO_SWAP_LR;
807: pci_conf_write(sc->pc, sc->pt, CONF_MAESTRO, data);
808: /* Reset direct sound. */
809: bus_space_write_2(sc->iot, sc->ioh, PORT_HOSTINT_CTRL,
810: HOSTINT_CTRL_DSOUND_RESET);
811: DELAY(10000); /* XXX - too long? */
812: bus_space_write_2(sc->iot, sc->ioh, PORT_HOSTINT_CTRL, 0);
813: DELAY(10000);
814:
815: /* Enable direct sound and hardware volume control interruptions. */
816: bus_space_write_2(sc->iot, sc->ioh, PORT_HOSTINT_CTRL,
817: HOSTINT_CTRL_DSOUND_INT_ENABLED | HOSTINT_CTRL_HWVOL_ENABLED);
818:
819: /* Setup Wave Processor. */
820:
821: /* Enable WaveCache, set DMA base address. */
822: wp_reg_write(sc, WPREG_WAVE_ROMRAM,
823: WP_WAVE_VIRTUAL_ENABLED | WP_WAVE_DRAM_ENABLED);
824: bus_space_write_2(sc->iot, sc->ioh, PORT_WAVCACHE_CTRL,
825: WAVCACHE_ENABLED | WAVCACHE_WTSIZE_4MB);
826:
827: for (reg = WAVCACHE_PCMBAR; reg < WAVCACHE_PCMBAR + 4; reg++)
828: wc_reg_write(sc, reg,
829: sc->physaddr >> WAVCACHE_BASEADDR_SHIFT);
830:
831: /* Setup Codec/Ringbus. */
832: maestro_initcodec(sc);
833: bus_space_write_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL,
834: RINGBUS_CTRL_RINGBUS_ENABLED | RINGBUS_CTRL_ACLINK_ENABLED);
835:
836: wp_reg_write(sc, WPREG_BASE, 0x8500); /* Parallel I/O */
837: ringbus_setdest(sc, RINGBUS_SRC_ADC,
838: RINGBUS_DEST_STEREO | RINGBUS_DEST_DSOUND_IN);
839: ringbus_setdest(sc, RINGBUS_SRC_DSOUND,
840: RINGBUS_DEST_STEREO | RINGBUS_DEST_DAC);
841:
842: /* Setup ASSP. Needed for Dell Inspiron 7500? */
843: bus_space_write_1(sc->iot, sc->ioh, PORT_ASSP_CTRL_B, 0x00);
844: bus_space_write_1(sc->iot, sc->ioh, PORT_ASSP_CTRL_A, 0x03);
845: bus_space_write_1(sc->iot, sc->ioh, PORT_ASSP_CTRL_C, 0x00);
846:
847: /*
848: * Reset hw volume to a known value so that we may handle diffs
849: * off to AC'97.
850: */
851:
852: bus_space_write_1(sc->iot, sc->ioh, PORT_HWVOL_MASTER, MIDDLE_VOLUME);
853: /* Setup GPIO if needed (NEC systems) */
854: if (sc->flags & MAESTRO_FLAG_SETUPGPIO) {
855: /* Matthew Braithwaite <matt@braithwaite.net> reported that
856: * NEC Versa LX doesn't need GPIO operation. */
857: bus_space_write_2(sc->iot, sc->ioh,
858: PORT_GPIO_MASK, 0x9ff);
859: bus_space_write_2(sc->iot, sc->ioh, PORT_GPIO_DIR,
860: bus_space_read_2(sc->iot, sc->ioh, PORT_GPIO_DIR) | 0x600);
861: bus_space_write_2(sc->iot, sc->ioh,
862: PORT_GPIO_DATA, 0x200);
863: }
864: }
865:
866: /* -----------------------------
867: * Audio interface
868: */
869:
870: int
871: maestro_round_blocksize(self, blk)
872: void *self;
873: int blk;
874: {
875: return ((blk + 0xf) & ~0xf);
876: }
877:
878: void *
879: maestro_malloc(arg, dir, size, pool, flags)
880: void *arg;
881: int dir;
882: size_t size;
883: int pool, flags;
884: {
885: struct maestro_softc *sc = (struct maestro_softc *)arg;
886:
887: return (salloc_alloc(sc->dmapool, size));
888: }
889:
890: void
891: maestro_free(self, ptr, pool)
892: void *self, *ptr;
893: int pool;
894: {
895: struct maestro_softc *sc = (struct maestro_softc *)self;
896:
897: salloc_free(sc->dmapool, ptr);
898: }
899:
900: paddr_t
901: maestro_mappage(self, mem, off, prot)
902: void *self, *mem;
903: off_t off;
904: int prot;
905: {
906: struct maestro_softc *sc = (struct maestro_softc *)self;
907:
908: if (off < 0)
909: return -1;
910: return bus_dmamem_mmap(sc->dmat, &sc->dmaseg, 1,
911: off, prot, BUS_DMA_WAITOK);
912: }
913:
914: int
915: maestro_get_props(self)
916: void *self;
917: {
918: /* struct maestro_softc *sc = (struct maestro_softc *)self; */
919:
920: return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT); /* XXX */
921: }
922:
923: int
924: maestro_getdev(self, retp)
925: void *self;
926: struct audio_device *retp;
927: {
928: struct maestro_softc *sc = (struct maestro_softc *)self;
929:
930: *retp = *sc->sc_audev;
931: return 0;
932: }
933:
934: int
935: maestro_set_port(self, cp)
936: void *self;
937: mixer_ctrl_t *cp;
938: {
939: struct ac97_codec_if *c = ((struct maestro_softc *)self)->codec_if;
940:
941: if (c)
942: return (c->vtbl->mixer_set_port(c, cp));
943: else
944: return (ENXIO);
945: }
946:
947: int
948: maestro_get_port(self, cp)
949: void *self;
950: mixer_ctrl_t *cp;
951: {
952: struct ac97_codec_if *c = ((struct maestro_softc *)self)->codec_if;
953:
954: if (c)
955: return (c->vtbl->mixer_get_port(c, cp));
956: else
957: return (ENXIO);
958: }
959:
960: int
961: maestro_query_devinfo(self, cp)
962: void *self;
963: mixer_devinfo_t *cp;
964: {
965: struct ac97_codec_if *c = ((struct maestro_softc *)self)->codec_if;
966:
967: if (c)
968: return (c->vtbl->query_devinfo(c, cp));
969: else
970: return (ENXIO);
971: }
972:
973: struct audio_encoding maestro_tab[] = {
974: {0, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 16, 0},
975: {1, AudioEslinear, AUDIO_ENCODING_SLINEAR, 8, 0},
976: {2, AudioEulinear, AUDIO_ENCODING_ULINEAR, 8, 0},
977: {3, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16,
978: AUDIO_ENCODINGFLAG_EMULATED},
979: {4, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 16,
980: AUDIO_ENCODINGFLAG_EMULATED},
981: {5, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 16,
982: AUDIO_ENCODINGFLAG_EMULATED},
983: {6, AudioEmulaw, AUDIO_ENCODING_ULAW, 8,
984: AUDIO_ENCODINGFLAG_EMULATED},
985: {7, AudioEalaw, AUDIO_ENCODING_ALAW, 8,
986: AUDIO_ENCODINGFLAG_EMULATED}
987: };
988:
989: int
990: maestro_query_encoding(hdl, fp)
991: void *hdl;
992: struct audio_encoding *fp;
993: {
994: if (fp->index < 0 || fp->index >= lengthof(maestro_tab))
995: return (EINVAL);
996: *fp = maestro_tab[fp->index];
997: return (0);
998: }
999:
1000: #define UNUSED __attribute__((unused))
1001:
1002: void
1003: maestro_set_speed(ch, prate)
1004: struct maestro_channel *ch;
1005: u_long *prate;
1006: {
1007: ch->speed = *prate;
1008: if ((ch->mode & (MAESTRO_8BIT | MAESTRO_STEREO)) == MAESTRO_8BIT)
1009: ch->speed /= 2;
1010:
1011: /* special common case */
1012: if (ch->speed == 48000) {
1013: ch->dv = 0x10000;
1014: } else {
1015: /* compute 16 bits fixed point value of speed/48000,
1016: * being careful not to overflow */
1017: ch->dv = (((ch->speed % 48000) << 16U) + 24000) / 48000
1018: + ((ch->speed / 48000) << 16U);
1019: /* And this is the real rate obtained */
1020: ch->speed = (ch->dv >> 16U) * 48000 +
1021: (((ch->dv & 0xffff)*48000)>>16U);
1022: }
1023: *prate = ch->speed;
1024: if ((ch->mode & (MAESTRO_8BIT | MAESTRO_STEREO)) == MAESTRO_8BIT)
1025: *prate *= 2;
1026: }
1027:
1028: u_int
1029: maestro_calc_timer_freq(ch)
1030: struct maestro_channel *ch;
1031: {
1032: u_int ss = 2;
1033:
1034: if (ch->mode & MAESTRO_8BIT)
1035: ss = 1;
1036: return (ch->speed * ss) / ch->blocksize;
1037: }
1038:
1039: void
1040: maestro_update_timer(sc)
1041: struct maestro_softc *sc;
1042: {
1043: u_int freq = 0;
1044: u_int n;
1045:
1046: if (sc->play.mode & MAESTRO_RUNNING)
1047: freq = maestro_calc_timer_freq(&sc->play);
1048: if (sc->record.mode & MAESTRO_RUNNING) {
1049: n = maestro_calc_timer_freq(&sc->record);
1050: if (freq < n)
1051: freq = n;
1052: }
1053: if (freq) {
1054: wp_settimer(sc, freq);
1055: wp_starttimer(sc);
1056: } else
1057: wp_stoptimer(sc);
1058: }
1059:
1060:
1061: int
1062: maestro_set_params(hdl, setmode, usemode, play, rec)
1063: void *hdl;
1064: int setmode, usemode;
1065: struct audio_params *play, *rec;
1066: {
1067: struct maestro_softc *sc = (struct maestro_softc *)hdl;
1068:
1069: if ((setmode & AUMODE_PLAY) == 0)
1070: return (0);
1071:
1072: /* Disallow parameter change on a running audio for now */
1073: if (sc->play.mode & MAESTRO_RUNNING)
1074: return (EINVAL);
1075:
1076: if (play->sample_rate < 4000)
1077: play->sample_rate = 4000;
1078: else if (play->sample_rate > 48000)
1079: play->sample_rate = 48000;
1080:
1081: play->factor = 1;
1082: play->sw_code = NULL;
1083: if (play->channels != 1 && play->channels != 2)
1084: return (EINVAL);
1085:
1086:
1087: sc->play.mode = MAESTRO_PLAY;
1088: if (play->channels == 2)
1089: sc->play.mode |= MAESTRO_STEREO;
1090:
1091: if (play->encoding == AUDIO_ENCODING_ULAW) {
1092: play->factor = 2;
1093: play->sw_code = mulaw_to_slinear16_le;
1094: } else if (play->encoding == AUDIO_ENCODING_ALAW) {
1095: play->factor = 2;
1096: play->sw_code = alaw_to_slinear16_le;
1097: } else if (play->precision == 8) {
1098: sc->play.mode |= MAESTRO_8BIT;
1099: if (play->encoding == AUDIO_ENCODING_ULINEAR_LE ||
1100: play->encoding == AUDIO_ENCODING_ULINEAR_BE)
1101: sc->play.mode |= MAESTRO_UNSIGNED;
1102: }
1103: else if (play->encoding == AUDIO_ENCODING_ULINEAR_LE)
1104: play->sw_code = change_sign16_le;
1105: else if (play->encoding == AUDIO_ENCODING_SLINEAR_BE)
1106: play->sw_code = swap_bytes;
1107: else if (play->encoding == AUDIO_ENCODING_ULINEAR_BE)
1108: play->sw_code = change_sign16_swap_bytes_le;
1109: else if (play->encoding != AUDIO_ENCODING_SLINEAR_LE)
1110: return (EINVAL);
1111:
1112: maestro_set_speed(&sc->play, &play->sample_rate);
1113: return (0);
1114: }
1115:
1116: int
1117: maestro_open(hdl, flags)
1118: void *hdl;
1119: int flags;
1120: {
1121: struct maestro_softc *sc = (struct maestro_softc *)hdl;
1122: DPRINTF(("%s: open(%d)\n", sc->dev.dv_xname, flags));
1123:
1124: /* XXX work around VM brokeness */
1125: #if 0
1126: if ((OFLAGS(flags) & O_ACCMODE) != O_WRONLY)
1127: return (EINVAL);
1128: #endif
1129: sc->play.mode = MAESTRO_PLAY;
1130: sc->record.mode = 0;
1131: #ifdef AUDIO_DEBUG
1132: maestrointr_called = 0;
1133: maestrodma_effective = 0;
1134: #endif
1135: return (0);
1136: }
1137:
1138: void
1139: maestro_close(hdl)
1140: void *hdl;
1141: {
1142: struct maestro_softc *sc UNUSED = (struct maestro_softc *)hdl;
1143: /* nothing to do */
1144: }
1145:
1146:
1147: void
1148: maestro_channel_stop(ch)
1149: struct maestro_channel *ch;
1150: {
1151: wp_apu_write(ch->sc, ch->num, APUREG_APUTYPE,
1152: APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
1153: if (ch->mode & MAESTRO_STEREO)
1154: wp_apu_write(ch->sc, ch->num+1, APUREG_APUTYPE,
1155: APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
1156: /* four channels for record... */
1157: if (ch->mode & MAESTRO_PLAY)
1158: return;
1159: wp_apu_write(ch->sc, ch->num+2, APUREG_APUTYPE,
1160: APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
1161: if (ch->mode & MAESTRO_STEREO)
1162: wp_apu_write(ch->sc, ch->num+3, APUREG_APUTYPE,
1163: APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
1164:
1165: }
1166:
1167: int
1168: maestro_halt_input(hdl)
1169: void *hdl;
1170: {
1171: struct maestro_softc *sc = (struct maestro_softc *)hdl;
1172: maestro_channel_stop(&sc->record);
1173: sc->record.mode &= ~MAESTRO_RUNNING;
1174: maestro_update_timer(sc);
1175: return 0;
1176: }
1177:
1178: int
1179: maestro_halt_output(hdl)
1180: void *hdl;
1181: {
1182: struct maestro_softc *sc = (struct maestro_softc *)hdl;
1183:
1184: maestro_channel_stop(&sc->play);
1185: sc->play.mode &= ~MAESTRO_RUNNING;
1186: maestro_update_timer(sc);
1187: return 0;
1188: }
1189:
1190: int
1191: maestro_trigger_input(hdl, start, end, blksize, intr, arg, param)
1192: void *hdl;
1193: void *start, *end;
1194: int blksize;
1195: void (*intr)(void *);
1196: void *arg;
1197: struct audio_params *param;
1198: {
1199: struct maestro_softc *sc = (struct maestro_softc *)hdl;
1200:
1201: sc->record.mode |= MAESTRO_RUNNING;
1202: sc->record.blocksize = blksize;
1203:
1204: maestro_channel_start(&sc->record);
1205:
1206: sc->record.threshold = sc->record.start;
1207: maestro_update_timer(sc);
1208: return 0;
1209: }
1210:
1211: void
1212: maestro_channel_start(ch)
1213: struct maestro_channel *ch;
1214: {
1215: struct maestro_softc *sc = ch->sc;
1216: int n = ch->num;
1217: int aputype;
1218: wcreg_t wcreg = (sc->physaddr - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK;
1219:
1220: switch(ch->mode & (MAESTRO_STEREO | MAESTRO_8BIT)) {
1221: case 0:
1222: aputype = APUTYPE_16BITLINEAR;
1223: break;
1224: case MAESTRO_STEREO:
1225: aputype = APUTYPE_16BITSTEREO;
1226: break;
1227: case MAESTRO_8BIT:
1228: aputype = APUTYPE_8BITLINEAR;
1229: break;
1230: case MAESTRO_8BIT|MAESTRO_STEREO:
1231: aputype = APUTYPE_8BITSTEREO;
1232: break;
1233: }
1234: if (ch->mode & MAESTRO_UNSIGNED)
1235: wcreg |= WAVCACHE_CHCTL_U8;
1236: if ((ch->mode & MAESTRO_STEREO) == 0) {
1237: DPRINTF(("Setting mono parameters\n"));
1238: wp_apu_write(sc, n, APUREG_WAVESPACE, ch->wpwa & 0xff00);
1239: wp_apu_write(sc, n, APUREG_CURPTR, ch->current);
1240: wp_apu_write(sc, n, APUREG_ENDPTR, ch->end);
1241: wp_apu_write(sc, n, APUREG_LOOPLEN, ch->end - ch->start);
1242: wp_apu_write(sc, n, APUREG_AMPLITUDE, 0xe800);
1243: wp_apu_write(sc, n, APUREG_POSITION, 0x8f00
1244: | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT)
1245: | (PAN_FRONT << APU_PAN_SHIFT));
1246: wp_apu_write(sc, n, APUREG_FREQ_LOBYTE, APU_plus6dB
1247: | ((ch->dv & 0xff) << APU_FREQ_LOBYTE_SHIFT));
1248: wp_apu_write(sc, n, APUREG_FREQ_HIWORD, ch->dv >> 8);
1249: wc_ctrl_write(sc, n, wcreg);
1250: wp_apu_write(sc, n, APUREG_APUTYPE,
1251: (aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
1252: } else {
1253: wcreg |= WAVCACHE_CHCTL_STEREO;
1254: DPRINTF(("Setting stereo parameters\n"));
1255: wp_apu_write(sc, n+1, APUREG_WAVESPACE, ch->wpwa & 0xff00);
1256: wp_apu_write(sc, n+1, APUREG_CURPTR, ch->current);
1257: wp_apu_write(sc, n+1, APUREG_ENDPTR, ch->end);
1258: wp_apu_write(sc, n+1, APUREG_LOOPLEN, ch->end - ch->start);
1259: wp_apu_write(sc, n+1, APUREG_AMPLITUDE, 0xe800);
1260: wp_apu_write(sc, n+1, APUREG_POSITION, 0x8f00
1261: | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT)
1262: | (PAN_LEFT << APU_PAN_SHIFT));
1263: wp_apu_write(sc, n+1, APUREG_FREQ_LOBYTE, APU_plus6dB
1264: | ((ch->dv & 0xff) << APU_FREQ_LOBYTE_SHIFT));
1265: wp_apu_write(sc, n+1, APUREG_FREQ_HIWORD, ch->dv >> 8);
1266: if (ch->mode & MAESTRO_8BIT)
1267: wp_apu_write(sc, n, APUREG_WAVESPACE,
1268: ch->wpwa & 0xff00);
1269: else
1270: wp_apu_write(sc, n, APUREG_WAVESPACE,
1271: (ch->wpwa|(APU_STEREO >> 1)) & 0xff00);
1272: wp_apu_write(sc, n, APUREG_CURPTR, ch->current);
1273: wp_apu_write(sc, n, APUREG_ENDPTR, ch->end);
1274: wp_apu_write(sc, n, APUREG_LOOPLEN, ch->end - ch->start);
1275: wp_apu_write(sc, n, APUREG_AMPLITUDE, 0xe800);
1276: wp_apu_write(sc, n, APUREG_POSITION, 0x8f00
1277: | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT)
1278: | (PAN_RIGHT << APU_PAN_SHIFT));
1279: wp_apu_write(sc, n, APUREG_FREQ_LOBYTE, APU_plus6dB
1280: | ((ch->dv & 0xff) << APU_FREQ_LOBYTE_SHIFT));
1281: wp_apu_write(sc, n, APUREG_FREQ_HIWORD, ch->dv >> 8);
1282: wc_ctrl_write(sc, n, wcreg);
1283: wc_ctrl_write(sc, n+1, wcreg);
1284: wp_apu_write(sc, n, APUREG_APUTYPE,
1285: (aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
1286: wp_apu_write(sc, n+1, APUREG_APUTYPE,
1287: (aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
1288: }
1289: }
1290:
1291: int
1292: maestro_trigger_output(hdl, start, end, blksize, intr, arg, param)
1293: void *hdl;
1294: void *start, *end;
1295: int blksize;
1296: void (*intr)(void *);
1297: void *arg;
1298: struct audio_params *param;
1299: {
1300: struct maestro_softc *sc = (struct maestro_softc *)hdl;
1301:
1302: u_int offset = ((caddr_t)start - sc->dmabase) >> 1;
1303: u_int size = ((char *)end - (char *)start) >> 1;
1304: sc->play.mode |= MAESTRO_RUNNING;
1305: sc->play.wpwa = APU_USE_SYSMEM | (offset >> 8);
1306: DPRINTF(("maestro_trigger_output: start=%x, end=%x, blksize=%x ",
1307: start, end, blksize));
1308: DPRINTF(("offset = %x, size=%x\n", offset, size));
1309:
1310: sc->play.intr = intr;
1311: sc->play.intr_arg = arg;
1312: sc->play.blocksize = blksize;
1313: sc->play.end = offset+size;
1314: sc->play.start = offset;
1315: sc->play.current = sc->play.start;
1316: if ((sc->play.mode & (MAESTRO_STEREO | MAESTRO_8BIT)) == MAESTRO_STEREO) {
1317: sc->play.wpwa >>= 1;
1318: sc->play.start >>= 1;
1319: sc->play.end >>= 1;
1320: sc->play.blocksize >>= 1;
1321: }
1322: maestro_channel_start(&sc->play);
1323:
1324: sc->play.threshold = sc->play.start;
1325: maestro_update_timer(sc);
1326:
1327: return 0;
1328: }
1329:
1330: /* -----------------------------
1331: * Codec interface
1332: */
1333:
1334: int
1335: maestro_read_codec(self, regno, datap)
1336: void *self;
1337: u_int8_t regno;
1338: u_int16_t *datap;
1339: {
1340: struct maestro_softc *sc = (struct maestro_softc *)self;
1341: int t;
1342:
1343: /* We have to wait for a SAFE time to write addr/data */
1344: for (t = 0; t < 20; t++) {
1345: if ((bus_space_read_1(sc->iot, sc->ioh, PORT_CODEC_STAT)
1346: & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS)
1347: break;
1348: DELAY(2); /* 20.8us / 13 */
1349: }
1350: if (t == 20)
1351: printf("%s: maestro_read_codec() PROGLESS timed out.\n",
1352: sc->dev.dv_xname);
1353: /* XXX return 1 */
1354:
1355: bus_space_write_1(sc->iot, sc->ioh, PORT_CODEC_CMD,
1356: CODEC_CMD_READ | regno);
1357: DELAY(21); /* AC97 cycle = 20.8usec */
1358:
1359: /* Wait for data retrieve */
1360: for (t = 0; t < 20; t++) {
1361: if ((bus_space_read_1(sc->iot, sc->ioh, PORT_CODEC_STAT)
1362: & CODEC_STAT_MASK) == CODEC_STAT_RW_DONE)
1363: break;
1364: DELAY(2); /* 20.8us / 13 */
1365: }
1366: if (t == 20)
1367: /* Timed out, but perform dummy read. */
1368: printf("%s: maestro_read_codec() RW_DONE timed out.\n",
1369: sc->dev.dv_xname);
1370:
1371: *datap = bus_space_read_2(sc->iot, sc->ioh, PORT_CODEC_REG);
1372: return 0;
1373: }
1374:
1375: int
1376: maestro_write_codec(self, regno, data)
1377: void *self;
1378: u_int8_t regno;
1379: u_int16_t data;
1380: {
1381: struct maestro_softc *sc = (struct maestro_softc *)self;
1382: int t;
1383:
1384: /* We have to wait for a SAFE time to write addr/data */
1385: for (t = 0; t < 20; t++) {
1386: if ((bus_space_read_1(sc->iot, sc->ioh, PORT_CODEC_STAT)
1387: & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS)
1388: break;
1389: DELAY(2); /* 20.8us / 13 */
1390: }
1391: if (t == 20) {
1392: /* Timed out. Abort writing. */
1393: printf("%s: maestro_write_codec() PROGLESS timed out.\n",
1394: sc->dev.dv_xname);
1395: return 1;
1396: }
1397:
1398: bus_space_write_2(sc->iot, sc->ioh, PORT_CODEC_REG, data);
1399: bus_space_write_1(sc->iot, sc->ioh, PORT_CODEC_CMD,
1400: CODEC_CMD_WRITE | regno);
1401:
1402: return 0;
1403: }
1404:
1405: int
1406: maestro_attach_codec(self, cif)
1407: void *self;
1408: struct ac97_codec_if *cif;
1409: {
1410: struct maestro_softc *sc = (struct maestro_softc *)self;
1411:
1412: sc->codec_if = cif;
1413: return 0;
1414: }
1415:
1416: void
1417: maestro_reset_codec(self)
1418: void *self UNUSED;
1419: {
1420: }
1421:
1422: void
1423: maestro_initcodec(self)
1424: void *self;
1425: {
1426: struct maestro_softc *sc = (struct maestro_softc *)self;
1427: u_int16_t data;
1428:
1429: if (bus_space_read_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL)
1430: & RINGBUS_CTRL_ACLINK_ENABLED) {
1431: bus_space_write_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL, 0);
1432: DELAY(104); /* 20.8us * (4 + 1) */
1433: }
1434: /* XXX - 2nd codec should be looked at. */
1435: bus_space_write_4(sc->iot, sc->ioh,
1436: PORT_RINGBUS_CTRL, RINGBUS_CTRL_AC97_SWRESET);
1437: DELAY(2);
1438: bus_space_write_4(sc->iot, sc->ioh,
1439: PORT_RINGBUS_CTRL, RINGBUS_CTRL_ACLINK_ENABLED);
1440: DELAY(21);
1441:
1442: maestro_read_codec(sc, 0, &data);
1443: if ((bus_space_read_1(sc->iot, sc->ioh, PORT_CODEC_STAT)
1444: & CODEC_STAT_MASK) != 0) {
1445: bus_space_write_4(sc->iot, sc->ioh,
1446: PORT_RINGBUS_CTRL, 0);
1447: DELAY(21);
1448:
1449: /* Try cold reset. */
1450: printf("%s: resetting codec\n", sc->dev.dv_xname);
1451:
1452: data = bus_space_read_2(sc->iot, sc->ioh, PORT_GPIO_DIR);
1453: if (pci_conf_read(sc->pc, sc->pt, 0x58) & 1)
1454: data |= 0x10;
1455: data |= 0x009 &
1456: ~bus_space_read_2(sc->iot, sc->ioh, PORT_GPIO_DATA);
1457: bus_space_write_2(sc->iot, sc->ioh,
1458: PORT_GPIO_MASK, 0xff6);
1459: bus_space_write_2(sc->iot, sc->ioh,
1460: PORT_GPIO_DIR, data | 0x009);
1461: bus_space_write_2(sc->iot, sc->ioh,
1462: PORT_GPIO_DATA, 0x000);
1463: DELAY(2);
1464: bus_space_write_2(sc->iot, sc->ioh,
1465: PORT_GPIO_DATA, 0x001);
1466: DELAY(1);
1467: bus_space_write_2(sc->iot, sc->ioh,
1468: PORT_GPIO_DATA, 0x009);
1469: DELAY(500000);
1470: bus_space_write_2(sc->iot, sc->ioh,
1471: PORT_GPIO_DIR, data);
1472: DELAY(84); /* 20.8us * 4 */
1473: bus_space_write_4(sc->iot, sc->ioh,
1474: PORT_RINGBUS_CTRL, RINGBUS_CTRL_ACLINK_ENABLED);
1475: DELAY(21);
1476: }
1477:
1478: /* Check the codec to see is still busy */
1479: if ((bus_space_read_1(sc->iot, sc->ioh, PORT_CODEC_STAT) &
1480: CODEC_STAT_MASK) != 0) {
1481: printf("%s: codec failure\n", sc->dev.dv_xname);
1482: }
1483: }
1484:
1485: /* -----------------------------
1486: * Power management interface
1487: */
1488:
1489: void
1490: maestro_powerhook(why, self)
1491: int why;
1492: void *self;
1493: {
1494: struct maestro_softc *sc = (struct maestro_softc *)self;
1495:
1496: if (why != PWR_RESUME) {
1497: /* Power down device on shutdown. */
1498: DPRINTF(("maestro: power down\n"));
1499: sc->suspend = why;
1500: if (sc->record.mode & MAESTRO_RUNNING) {
1501: sc->record.current = wp_apu_read(sc, sc->record.num, APUREG_CURPTR);
1502: maestro_channel_stop(&sc->record);
1503: }
1504: if (sc->play.mode & MAESTRO_RUNNING) {
1505: sc->play.current = wp_apu_read(sc, sc->play.num, APUREG_CURPTR);
1506: maestro_channel_stop(&sc->play);
1507: }
1508:
1509: wp_stoptimer(sc);
1510:
1511: /* Power down everything except clock. */
1512: bus_space_write_2(sc->iot, sc->ioh, PORT_HOSTINT_CTRL, 0);
1513: maestro_write_codec(sc, AC97_REG_POWER, 0xdf00);
1514: DELAY(20);
1515: bus_space_write_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL, 0);
1516: DELAY(1);
1517: maestro_power(sc, PPMI_D3);
1518: } else {
1519: /* Power up device on resume. */
1520: DPRINTF(("maestro: power resume\n"));
1521: if (sc->suspend == PWR_RESUME) {
1522: printf("%s: resume without suspend?\n",
1523: sc->dev.dv_xname);
1524: sc->suspend = why;
1525: return;
1526: }
1527: sc->suspend = why;
1528: maestro_power(sc, PPMI_D0);
1529: DELAY(100000);
1530: maestro_init(sc);
1531: /* Restore codec settings */
1532: if (sc->codec_if)
1533: sc->codec_if->vtbl->restore_ports(sc->codec_if);
1534: if (sc->play.mode & MAESTRO_RUNNING)
1535: maestro_channel_start(&sc->play);
1536: if (sc->record.mode & MAESTRO_RUNNING)
1537: maestro_channel_start(&sc->record);
1538: maestro_update_timer(sc);
1539: }
1540: }
1541:
1542: void
1543: maestro_power(sc, status)
1544: struct maestro_softc *sc;
1545: int status;
1546: {
1547: int data;
1548:
1549: /* Set the power state of the device. */
1550: data = pci_conf_read(sc->pc, sc->pt, CONF_PM_PTR);
1551: data = pci_conf_read(sc->pc, sc->pt, data);
1552: if (data == PPMI_CID)
1553: pci_conf_write(sc->pc, sc->pt, data + PM_CTRL, status);
1554: }
1555:
1556: void
1557: maestro_channel_advance_dma(ch)
1558: struct maestro_channel *ch;
1559: {
1560: wpreg_t pos;
1561: #ifdef AUDIO_DEBUG
1562: maestrointr_called++;
1563: #endif
1564: for (;;) {
1565: pos = wp_apu_read(ch->sc, ch->num, APUREG_CURPTR);
1566: /* Are we still processing the current dma block ? */
1567: if (pos >= ch->threshold &&
1568: pos < ch->threshold + ch->blocksize/2)
1569: break;
1570: ch->threshold += ch->blocksize/2;
1571: if (ch->threshold >= ch->end)
1572: ch->threshold = ch->start;
1573: (*ch->intr)(ch->intr_arg);
1574: #ifdef AUDIO_DEBUG
1575: maestrodma_effective++;
1576: #endif
1577: }
1578:
1579: #ifdef AUDIO_DEBUG
1580: if (maestrodebug && maestrointr_called % 64 == 0)
1581: printf("maestro: dma advanced %lu for %lu calls\n",
1582: maestrodma_effective, maestrointr_called);
1583: #endif
1584: }
1585:
1586: /* Some maestro makes sometimes get desynchronized in stereo mode. */
1587: void
1588: maestro_channel_suppress_jitter(ch)
1589: struct maestro_channel *ch;
1590: {
1591: int cp, diff;
1592:
1593: /* Verify that both channels are not too far off. */
1594: cp = wp_apu_read(ch->sc, ch->num, APUREG_CURPTR);
1595: diff = wp_apu_read(ch->sc, ch->num+1, APUREG_CURPTR) - cp;
1596: if (diff > 4 || diff < -4)
1597: /* Otherwise, directly resynch the 2nd channel. */
1598: bus_space_write_2(ch->sc->iot, ch->sc->ioh,
1599: PORT_DSP_DATA, cp);
1600: }
1601:
1602: /* -----------------------------
1603: * Interrupt handler interface
1604: */
1605: int
1606: maestro_intr(arg)
1607: void *arg;
1608: {
1609: struct maestro_softc *sc = (struct maestro_softc *)arg;
1610: u_int16_t status;
1611:
1612: status = bus_space_read_1(sc->iot, sc->ioh, PORT_HOSTINT_STAT);
1613: if (status == 0)
1614: return 0; /* Not for us? */
1615:
1616: /* Acknowledge all. */
1617: bus_space_write_2(sc->iot, sc->ioh, PORT_INT_STAT, 1);
1618: bus_space_write_1(sc->iot, sc->ioh, PORT_HOSTINT_STAT, status);
1619:
1620: /* Hardware volume support */
1621: if (status & HOSTINT_STAT_HWVOL && sc->codec_if != NULL) {
1622: int n, i, delta, v;
1623: mixer_ctrl_t hwvol;
1624:
1625: n = bus_space_read_1(sc->iot, sc->ioh, PORT_HWVOL_MASTER);
1626: /* Special case: Mute key */
1627: if (n & 0x11) {
1628: hwvol.type = AUDIO_MIXER_ENUM;
1629: hwvol.dev =
1630: sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
1631: AudioCoutputs, AudioNmaster, AudioNmute);
1632: sc->codec_if->vtbl->mixer_get_port(sc->codec_if, &hwvol);
1633: hwvol.un.ord = !hwvol.un.ord;
1634: } else {
1635: hwvol.type = AUDIO_MIXER_VALUE;
1636: hwvol.un.value.num_channels = 2;
1637: hwvol.dev =
1638: sc->codec_if->vtbl->get_portnum_by_name(
1639: sc->codec_if, AudioCoutputs, AudioNmaster,
1640: NULL);
1641: sc->codec_if->vtbl->mixer_get_port(sc->codec_if, &hwvol);
1642: /* XXX AC'97 yields five bits for master volume. */
1643: delta = (n - MIDDLE_VOLUME)/STEP_VOLUME * 8;
1644: for (i = 0; i < hwvol.un.value.num_channels; i++) {
1645: v = ((int)hwvol.un.value.level[i]) + delta;
1646: if (v < 0)
1647: v = 0;
1648: else if (v > 255)
1649: v = 255;
1650: hwvol.un.value.level[i] = v;
1651: }
1652: }
1653: sc->codec_if->vtbl->mixer_set_port(sc->codec_if, &hwvol);
1654: /* Reset to compute next diffs */
1655: bus_space_write_1(sc->iot, sc->ioh, PORT_HWVOL_MASTER,
1656: MIDDLE_VOLUME);
1657: }
1658:
1659: if (sc->play.mode & MAESTRO_RUNNING) {
1660: maestro_channel_advance_dma(&sc->play);
1661: if (sc->play.mode & MAESTRO_STEREO)
1662: maestro_channel_suppress_jitter(&sc->play);
1663: }
1664:
1665: if (sc->record.mode & MAESTRO_RUNNING)
1666: maestro_channel_advance_dma(&sc->record);
1667:
1668: return 1;
1669: }
1670:
1671: /* -----------------------------
1672: * Hardware interface
1673: */
1674:
1675: /* Codec/Ringbus */
1676:
1677: void
1678: ringbus_setdest(struct maestro_softc *sc, int src, int dest)
1679: {
1680: u_int32_t data;
1681:
1682: data = bus_space_read_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL);
1683: data &= ~(0xfU << src);
1684: data |= (0xfU & dest) << src;
1685: bus_space_write_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL, data);
1686: }
1687:
1688: /* Wave Processor */
1689:
1690: wpreg_t
1691: wp_reg_read(struct maestro_softc *sc, int reg)
1692: {
1693: bus_space_write_2(sc->iot, sc->ioh, PORT_DSP_INDEX, reg);
1694: return bus_space_read_2(sc->iot, sc->ioh, PORT_DSP_DATA);
1695: }
1696:
1697: void
1698: wp_reg_write(struct maestro_softc *sc, int reg, wpreg_t data)
1699: {
1700: bus_space_write_2(sc->iot, sc->ioh, PORT_DSP_INDEX, reg);
1701: bus_space_write_2(sc->iot, sc->ioh, PORT_DSP_DATA, data);
1702: }
1703:
1704: static void
1705: apu_setindex(struct maestro_softc *sc, int reg)
1706: {
1707: int t;
1708:
1709: wp_reg_write(sc, WPREG_CRAM_PTR, reg);
1710: /* Sometimes WP fails to set apu register index. */
1711: for (t = 0; t < 1000; t++) {
1712: if (bus_space_read_2(sc->iot, sc->ioh,
1713: PORT_DSP_DATA) == reg)
1714: break;
1715: bus_space_write_2(sc->iot, sc->ioh, PORT_DSP_DATA, reg);
1716: }
1717: if (t == 1000)
1718: printf("%s: apu_setindex() timeout\n", sc->dev.dv_xname);
1719: }
1720:
1721: wpreg_t
1722: wp_apu_read(struct maestro_softc *sc, int ch, int reg)
1723: {
1724: wpreg_t ret;
1725:
1726: apu_setindex(sc, ((unsigned)ch << 4) + reg);
1727: ret = wp_reg_read(sc, WPREG_DATA_PORT);
1728: return ret;
1729: }
1730:
1731: void
1732: wp_apu_write(struct maestro_softc *sc, int ch, int reg, wpreg_t data)
1733: {
1734: int t;
1735:
1736: apu_setindex(sc, ((unsigned)ch << 4) + reg);
1737: wp_reg_write(sc, WPREG_DATA_PORT, data);
1738: for (t = 0; t < 1000; t++) {
1739: if (bus_space_read_2(sc->iot, sc->ioh, PORT_DSP_DATA) == data)
1740: break;
1741: bus_space_write_2(sc->iot, sc->ioh, PORT_DSP_DATA, data);
1742: }
1743: if (t == 1000)
1744: printf("%s: wp_apu_write() timeout\n", sc->dev.dv_xname);
1745: }
1746:
1747: void
1748: wp_settimer(struct maestro_softc *sc, u_int freq)
1749: {
1750: u_int clock = 48000 << 2;
1751: u_int prescale = 0, divide = (freq != 0) ? (clock / freq) : ~0;
1752:
1753: if (divide < 4)
1754: divide = 4;
1755: else if (divide > 32 << 8)
1756: divide = 32 << 8;
1757:
1758: for (; divide > 32 << 1; divide >>= 1)
1759: prescale++;
1760: divide = (divide + 1) >> 1;
1761:
1762: for (; prescale < 7 && divide > 2 && !(divide & 1); divide >>= 1)
1763: prescale++;
1764:
1765: wp_reg_write(sc, WPREG_TIMER_ENABLE, 0);
1766: wp_reg_write(sc, WPREG_TIMER_FREQ,
1767: (prescale << WP_TIMER_FREQ_PRESCALE_SHIFT) | (divide - 1));
1768: wp_reg_write(sc, WPREG_TIMER_ENABLE, 1);
1769: }
1770:
1771: void
1772: wp_starttimer(struct maestro_softc *sc)
1773: {
1774: wp_reg_write(sc, WPREG_TIMER_START, 1);
1775: }
1776:
1777: void
1778: wp_stoptimer(struct maestro_softc *sc)
1779: {
1780: wp_reg_write(sc, WPREG_TIMER_START, 0);
1781: bus_space_write_2(sc->iot, sc->ioh, PORT_INT_STAT, 1);
1782: }
1783:
1784: /* WaveCache */
1785:
1786: wcreg_t
1787: wc_reg_read(struct maestro_softc *sc, int reg)
1788: {
1789: bus_space_write_2(sc->iot, sc->ioh, PORT_WAVCACHE_INDEX, reg);
1790: return bus_space_read_2(sc->iot, sc->ioh, PORT_WAVCACHE_DATA);
1791: }
1792:
1793: void
1794: wc_reg_write(struct maestro_softc *sc, int reg, wcreg_t data)
1795: {
1796: bus_space_write_2(sc->iot, sc->ioh, PORT_WAVCACHE_INDEX, reg);
1797: bus_space_write_2(sc->iot, sc->ioh, PORT_WAVCACHE_DATA, data);
1798: }
1799:
1800: u_int16_t
1801: wc_ctrl_read(struct maestro_softc *sc, int ch)
1802: {
1803: return wc_reg_read(sc, ch << 3);
1804: }
1805:
1806: void
1807: wc_ctrl_write(struct maestro_softc *sc, int ch, wcreg_t data)
1808: {
1809: wc_reg_write(sc, ch << 3, data);
1810: }
1811:
1812: /* -----------------------------
1813: * Simple zone allocator.
1814: * (All memory allocated in advance)
1815: */
1816:
1817: salloc_t
1818: salloc_new(addr, size, nzones)
1819: caddr_t addr;
1820: size_t size;
1821: int nzones;
1822: {
1823: struct salloc_pool *pool;
1824: struct salloc_zone *space;
1825: int i;
1826:
1827: MALLOC(pool, salloc_t, sizeof *pool + nzones * sizeof pool->zones[0],
1828: M_TEMP, M_NOWAIT);
1829: if (pool == NULL)
1830: return NULL;
1831: SLIST_INIT(&pool->free);
1832: SLIST_INIT(&pool->used);
1833: SLIST_INIT(&pool->spare);
1834: /* Espie says the following line is obvious */
1835: pool->zones = (struct salloc_zone *)(pool + 1);
1836: for (i = 1; i < nzones; i++)
1837: SLIST_INSERT_HEAD(&pool->spare, &pool->zones[i], link);
1838: space = &pool->zones[0];
1839: space->addr = addr;
1840: space->size = size;
1841: SLIST_INSERT_HEAD(&pool->free, space, link);
1842: return pool;
1843: }
1844:
1845: void
1846: salloc_destroy(pool)
1847: salloc_t pool;
1848: {
1849: FREE(pool, M_TEMP);
1850: }
1851:
1852: void
1853: salloc_insert(pool, head, zone, merge)
1854: salloc_t pool;
1855: struct salloc_head *head;
1856: struct salloc_zone *zone;
1857: int merge;
1858: {
1859: struct salloc_zone *prev, *next;
1860:
1861: /*
1862: * Insert a zone into an ordered list of zones, possibly
1863: * merging adjacent zones.
1864: */
1865: prev = NULL;
1866: SLIST_FOREACH(next, head, link) {
1867: if (next->addr > zone->addr)
1868: break;
1869: prev = next;
1870: }
1871:
1872: if (merge && prev && prev->addr + prev->size == zone->addr) {
1873: prev->size += zone->size;
1874: SLIST_INSERT_HEAD(&pool->spare, zone, link);
1875: zone = prev;
1876: } else if (prev)
1877: SLIST_INSERT_AFTER(prev, zone, link);
1878: else
1879: SLIST_INSERT_HEAD(head, zone, link);
1880: if (merge && next && zone->addr + zone->size == next->addr) {
1881: zone->size += next->size;
1882: SLIST_REMOVE(head, next, salloc_zone, link);
1883: SLIST_INSERT_HEAD(&pool->spare, next, link);
1884: }
1885: }
1886:
1887: caddr_t
1888: salloc_alloc(pool, size)
1889: salloc_t pool;
1890: size_t size;
1891: {
1892: struct salloc_zone *zone, *uzone;
1893:
1894: SLIST_FOREACH(zone, &pool->free, link)
1895: if (zone->size >= size)
1896: break;
1897: if (zone == SLIST_END(&pool->free))
1898: return NULL;
1899: if (zone->size == size) {
1900: SLIST_REMOVE(&pool->free, zone, salloc_zone, link);
1901: uzone = zone;
1902: } else {
1903: uzone = SLIST_FIRST(&pool->spare);
1904: if (uzone == NULL)
1905: return NULL; /* XXX */
1906: SLIST_REMOVE_HEAD(&pool->spare, link);
1907: uzone->size = size;
1908: uzone->addr = zone->addr;
1909: zone->size -= size;
1910: zone->addr += size;
1911: }
1912: salloc_insert(pool, &pool->used, uzone, 0);
1913: return uzone->addr;
1914: }
1915:
1916: void
1917: salloc_free(pool, addr)
1918: salloc_t pool;
1919: caddr_t addr;
1920: {
1921: struct salloc_zone *zone;
1922:
1923: SLIST_FOREACH(zone, &pool->used, link)
1924: if (zone->addr == addr)
1925: break;
1926: #ifdef DIAGNOSTIC
1927: if (zone == SLIST_END(&pool->used))
1928: panic("salloc_free: freeing unallocated memory");
1929: #endif
1930: SLIST_REMOVE(&pool->used, zone, salloc_zone, link);
1931: salloc_insert(pool, &pool->free, zone, 1);
1932: }
CVSweb