xref: /illumos-gate/usr/src/uts/intel/io/pit_beep.c (revision f6f4cb8ada400367a1921f6b93fb9e02f53ac5e6)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Simple beeper support for PC platform, using standard timer 2 beeper.
28  */
29 
30 #include <sys/types.h>
31 #include <sys/conf.h>
32 #include <sys/beep.h>
33 #include <sys/ksynch.h>
34 #include <sys/ddi.h>
35 #include <sys/sunddi.h>
36 #include <sys/modctl.h>
37 #include <sys/pit.h>
38 #include <sys/inttypes.h>
39 
40 #define	PIT_BEEP_UNIT(dev)	(getminor((dev)))
41 
42 typedef struct pit_beep_state {
43 	/* Dip of pit_beep device */
44 	dev_info_t	*dip;
45 
46 } pit_beep_state_t;
47 
48 #define	PIT_BEEP_ON	1
49 #define	PIT_BEEP_OFF	0
50 
51 /* Pointer to the state structure */
52 static void *pit_beep_statep;
53 
54 static int pit_beep_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
55 static int pit_beep_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
56 static int pit_beep_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
57     void *arg, void **result);
58 static void pit_beep_freq(void *arg, int freq);
59 static void pit_beep_on(void *arg);
60 static void pit_beep_off(void *arg);
61 
62 struct cb_ops pit_beep_cb_ops = {
63 	nulldev,	/* open  */
64 	nulldev,	/* close */
65 	nulldev,	/* strategy */
66 	nulldev,	/* print */
67 	nulldev,	/* dump */
68 	nulldev,	/* read */
69 	nulldev,	/* write */
70 	nulldev,	/* ioctl */
71 	nulldev,	/* devmap */
72 	nulldev,	/* mmap */
73 	nulldev,	/* segmap */
74 	nochpoll,	/* poll */
75 	ddi_prop_op,	/* cb_prop_op */
76 	NULL,		/* streamtab  */
77 	D_MP | D_NEW
78 };
79 
80 
81 static struct dev_ops pit_beep_ops = {
82 	DEVO_REV,		/* Devo_rev */
83 	0,			/* Refcnt */
84 	pit_beep_info,		/* Info */
85 	nulldev,		/* Identify */
86 	nulldev,		/* Probe */
87 	pit_beep_attach,	/* Attach */
88 	pit_beep_detach,	/* Detach */
89 	nodev,			/* Reset */
90 	&pit_beep_cb_ops,	/* Driver operations */
91 	0,			/* Bus operations */
92 	NULL			/* Power */
93 };
94 
95 
96 static struct modldrv modldrv = {
97 	&mod_driverops, 		/* This one is a driver */
98 	"Intel Pit_beep Driver",	/* Name of the module. */
99 	&pit_beep_ops,			/* Driver ops */
100 };
101 
102 
103 static struct modlinkage modlinkage = {
104 	MODREV_1, (void *)&modldrv, NULL
105 };
106 
107 
108 
109 int
110 _init(void)
111 {
112 	int error;
113 
114 	/* Initialize the soft state structures */
115 	if ((error = ddi_soft_state_init(&pit_beep_statep,
116 	    sizeof (pit_beep_state_t), 1)) != 0) {
117 
118 		return (error);
119 	}
120 
121 	/* Install the loadable module */
122 	if ((error = mod_install(&modlinkage)) != 0) {
123 		ddi_soft_state_fini(&pit_beep_statep);
124 	}
125 
126 	return (error);
127 }
128 
129 
130 int
131 _info(struct modinfo *modinfop)
132 {
133 	return (mod_info(&modlinkage, modinfop));
134 }
135 
136 int
137 _fini(void)
138 {
139 	int error;
140 
141 	error = mod_remove(&modlinkage);
142 
143 	if (error == 0) {
144 		/* Release per module resources */
145 		ddi_soft_state_fini(&pit_beep_statep);
146 	}
147 
148 	return (error);
149 }
150 
151 /*
152  * pit_beep_attach:
153  */
154 static int
155 pit_beep_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
156 {
157 	switch (cmd) {
158 		case DDI_ATTACH:
159 			break;
160 		case DDI_RESUME:
161 
162 			return (DDI_SUCCESS);
163 		default:
164 
165 			return (DDI_FAILURE);
166 	}
167 
168 	pit_beep_off(dip);
169 
170 	(void) beep_init((void *)dip, pit_beep_on, pit_beep_off,
171 	    pit_beep_freq);
172 
173 	/* Display information in the banner */
174 	ddi_report_dev(dip);
175 
176 	return (DDI_SUCCESS);
177 }
178 
179 
180 /*
181  * pit_beep_detach:
182  */
183 /* ARGSUSED */
184 static int
185 pit_beep_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
186 {
187 	switch (cmd) {
188 		case DDI_SUSPEND:
189 
190 			/*
191 			 * If a beep is in progress; fail suspend
192 			 */
193 			if (!beep_busy()) {
194 
195 				return (DDI_SUCCESS);
196 			} else {
197 
198 				return (DDI_FAILURE);
199 			}
200 		default:
201 
202 			return (DDI_FAILURE);
203 	}
204 }
205 
206 
207 /*
208  * pit_beep_info:
209  */
210 /* ARGSUSED */
211 static int
212 pit_beep_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
213     void *arg, void **result)
214 {
215 	dev_t dev;
216 	pit_beep_state_t  *statep;
217 	int instance, error;
218 
219 	switch (infocmd) {
220 	case DDI_INFO_DEVT2DEVINFO:
221 		dev = (dev_t)arg;
222 		instance = PIT_BEEP_UNIT(dev);
223 
224 		if ((statep = ddi_get_soft_state(pit_beep_statep,
225 		    instance)) == NULL) {
226 
227 			return (DDI_FAILURE);
228 		}
229 
230 		*result = (void *)statep->dip;
231 
232 		error = DDI_SUCCESS;
233 		break;
234 	case DDI_INFO_DEVT2INSTANCE:
235 		dev = (dev_t)arg;
236 		instance = PIT_BEEP_UNIT(dev);
237 
238 		*result = (void *)(uintptr_t)instance;
239 
240 		error = DDI_SUCCESS;
241 		break;
242 	default:
243 		error = DDI_FAILURE;
244 
245 	}
246 
247 	return (error);
248 }
249 
250 
251 /* ARGSUSED */
252 static void
253 pit_beep_freq(void *arg, int freq)
254 {
255 	int counter;
256 
257 	if (freq == 0)
258 		counter = 0;
259 	else {
260 		counter = PIT_HZ / freq;
261 		if (counter > UINT16_MAX)
262 			counter = UINT16_MAX;
263 		else if (counter < 1)
264 			counter = 1;
265 	}
266 
267 	outb(PITCTL_PORT, PIT_C2 | PIT_READMODE | PIT_RATEMODE);
268 	outb(PITCTR2_PORT, counter & 0xff);
269 	outb(PITCTR2_PORT, counter >> 8);
270 }
271 
272 
273 /* ARGSUSED */
274 static void
275 pit_beep_on(void *arg)
276 {
277 	outb(PITAUX_PORT, inb(PITAUX_PORT) | (PITAUX_OUT2 | PITAUX_GATE2));
278 }
279 
280 
281 /* ARGSUSED */
282 static void
283 pit_beep_off(void *arg)
284 {
285 	outb(PITAUX_PORT, inb(PITAUX_PORT) & ~(PITAUX_OUT2 | PITAUX_GATE2));
286 }
287