1 /* Extended Module Player
2  * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr
3  *
4  * This file is part of the Extended Module Player and is distributed
5  * under the terms of the GNU General Public License. See the COPYING
6  * file for more information.
7  */
8 
9 /* Based on bsd.c and solaris.c */
10 
11 #include <sys/types.h>
12 #include <sys/param.h>
13 #include <sys/audioio.h>
14 #include <sys/mman.h>
15 #include <sys/ioctl.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include "sound.h"
22 
23 static int audio_fd;
24 static int audioctl_fd;
25 
26 
27 static int init(struct options *options)
28 {
29 	char **parm = options->driver_parm;
30 	audio_info_t ainfo;
31 	int gain = 128;
32 	int bsize = 32 * 1024;
33 
34 	parm_init(parm);
35 	chkparm1("gain", gain = strtoul(token, NULL, 0));
36 	chkparm1("buffer", bsize = strtoul(token, NULL, 0));
37 	parm_end();
38 
39 	if ((audio_fd = open("/dev/sound", O_WRONLY)) == -1)
40 		return -1;
41 
42 	/* try to open audioctldevice */
43 	if ((audioctl_fd = open("/dev/audioctl", O_RDWR)) < 0) {
44 		fprintf(stderr, "couldn't open audioctldevice\n");
45 		close(audio_fd);
46 		return -1;
47 	}
48 
49 	/* empty buffers before change config */
50 	ioctl(audio_fd, AUDIO_DRAIN, 0);	/* drain everything out */
51 	ioctl(audio_fd, AUDIO_FLUSH);		/* flush audio */
52 	ioctl(audioctl_fd, AUDIO_FLUSH);	/* flush audioctl */
53 
OS2_Dart_UpdateBuffers(ULONG ulStatus,PMCI_MIX_BUFFER pBuffer,ULONG ulFlags)54 	/* get audio parameters. */
55 	if (ioctl(audioctl_fd, AUDIO_GETINFO, &ainfo) < 0) {
56 		fprintf(stderr, "AUDIO_GETINFO failed!\n");
57 		close(audio_fd);
58 		close(audioctl_fd);
59 		return -1;
60 	}
61 
62 	close(audioctl_fd);
63 
64 	if (gain < AUDIO_MIN_GAIN)
65 		gain = AUDIO_MIN_GAIN;
66 	if (gain > AUDIO_MAX_GAIN)
67 		gain = AUDIO_MAX_GAIN;
68 
init(struct options * options)69 	AUDIO_INITINFO(&ainfo);
70 
71 	ainfo.mode = AUMODE_PLAY_ALL;
72 	ainfo.play.sample_rate = options->rate;
73 	ainfo.play.channels = options->format & XMP_FORMAT_MONO ? 1 : 2;
74 
75 	if (options->format & XMP_FORMAT_8BIT) {
76 		ainfo.play.precision = 8;
77 		ainfo.play.encoding = AUDIO_ENCODING_ULINEAR;
78 		options->format |= XMP_FORMAT_UNSIGNED;
79 	} else {
80 		ainfo.play.precision = 16;
81 		ainfo.play.encoding = AUDIO_ENCODING_SLINEAR;
82 		options->format &= ~XMP_FORMAT_UNSIGNED;
83 	}
84 
85 	ainfo.play.gain = gain;
86 	ainfo.play.buffer_size = bsize;
87 	ainfo.blocksize = 0;
88 
89 	if (ioctl(audio_fd, AUDIO_SETINFO, &ainfo) == -1) {
90 		close(audio_fd);
91 		return -1;
92 	}
93 
94 	return 0;
95 }
96 
97 static void play(void *b, int i)
98 {
99 	int j;
100 
101 	while (i) {
102 		if ((j = write(audio_fd, b, i)) > 0) {
103 			i -= j;
104 			(char *)b += j;
105 		} else
106 			break;
107 	}
108 }
109 
110 static void deinit(void)
111 {
112 	close(audio_fd);
113 }
114 
115 static void flush(void)
116 {
117 }
118 
119 static void onpause(void)
120 {
121 }
122 
123 static void onresume(void)
124 {
125 }
126 
127 static const char *const help[] = {
128 	"gain=val", "Audio output gain (0 to 255)",
129 	"buffer=val", "Audio buffer size (default is 32768)",
130 	NULL
131 };
132 
133 struct sound_driver sound_netbsd = {
134 	"netbsd",
135 	"NetBSD PCM audio",
136 	help,
137 	init,
138 	deinit,
139 	play,
140 	flush,
141 	onpause,
142 	onresume
143 };
144