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