xref: /illumos-gate/usr/src/uts/intel/io/pit_beep.c (revision 8b80e8cb6855118d46f605e91b5ed4ce83417395)
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 	ddi_quiesce_not_needed,		/* quiesce */
94 };
95 
96 
97 static struct modldrv modldrv = {
98 	&mod_driverops, 		/* This one is a driver */
99 	"Intel Pit_beep Driver",	/* Name of the module. */
100 	&pit_beep_ops,			/* Driver ops */
101 };
102 
103 
104 static struct modlinkage modlinkage = {
105 	MODREV_1, (void *)&modldrv, NULL
106 };
107 
108 
109 
110 int
111 _init(void)
112 {
113 	int error;
114 
115 	/* Initialize the soft state structures */
116 	if ((error = ddi_soft_state_init(&pit_beep_statep,
117 	    sizeof (pit_beep_state_t), 1)) != 0) {
118 
119 		return (error);
120 	}
121 
122 	/* Install the loadable module */
123 	if ((error = mod_install(&modlinkage)) != 0) {
124 		ddi_soft_state_fini(&pit_beep_statep);
125 	}
126 
127 	return (error);
128 }
129 
130 
131 int
132 _info(struct modinfo *modinfop)
133 {
134 	return (mod_info(&modlinkage, modinfop));
135 }
136 
137 int
138 _fini(void)
139 {
140 	int error;
141 
142 	error = mod_remove(&modlinkage);
143 
144 	if (error == 0) {
145 		/* Release per module resources */
146 		ddi_soft_state_fini(&pit_beep_statep);
147 	}
148 
149 	return (error);
150 }
151 
152 /*
153  * pit_beep_attach:
154  */
155 static int
156 pit_beep_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
157 {
158 	switch (cmd) {
159 		case DDI_ATTACH:
160 			break;
161 		case DDI_RESUME:
162 
163 			return (DDI_SUCCESS);
164 		default:
165 
166 			return (DDI_FAILURE);
167 	}
168 
169 	pit_beep_off(dip);
170 
171 	(void) beep_init((void *)dip, pit_beep_on, pit_beep_off,
172 	    pit_beep_freq);
173 
174 	/* Display information in the banner */
175 	ddi_report_dev(dip);
176 
177 	return (DDI_SUCCESS);
178 }
179 
180 
181 /*
182  * pit_beep_detach:
183  */
184 /* ARGSUSED */
185 static int
186 pit_beep_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
187 {
188 	switch (cmd) {
189 		case DDI_SUSPEND:
190 
191 			/*
192 			 * If a beep is in progress; fail suspend
193 			 */
194 			if (!beep_busy()) {
195 
196 				return (DDI_SUCCESS);
197 			} else {
198 
199 				return (DDI_FAILURE);
200 			}
201 		default:
202 
203 			return (DDI_FAILURE);
204 	}
205 }
206 
207 
208 /*
209  * pit_beep_info:
210  */
211 /* ARGSUSED */
212 static int
213 pit_beep_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
214     void *arg, void **result)
215 {
216 	dev_t dev;
217 	pit_beep_state_t  *statep;
218 	int instance, error;
219 
220 	switch (infocmd) {
221 	case DDI_INFO_DEVT2DEVINFO:
222 		dev = (dev_t)arg;
223 		instance = PIT_BEEP_UNIT(dev);
224 
225 		if ((statep = ddi_get_soft_state(pit_beep_statep,
226 		    instance)) == NULL) {
227 
228 			return (DDI_FAILURE);
229 		}
230 
231 		*result = (void *)statep->dip;
232 
233 		error = DDI_SUCCESS;
234 		break;
235 	case DDI_INFO_DEVT2INSTANCE:
236 		dev = (dev_t)arg;
237 		instance = PIT_BEEP_UNIT(dev);
238 
239 		*result = (void *)(uintptr_t)instance;
240 
241 		error = DDI_SUCCESS;
242 		break;
243 	default:
244 		error = DDI_FAILURE;
245 
246 	}
247 
248 	return (error);
249 }
250 
251 
252 /* ARGSUSED */
253 static void
254 pit_beep_freq(void *arg, int freq)
255 {
256 	int counter;
257 
258 	if (freq == 0)
259 		counter = 0;
260 	else {
261 		counter = PIT_HZ / freq;
262 		if (counter > UINT16_MAX)
263 			counter = UINT16_MAX;
264 		else if (counter < 1)
265 			counter = 1;
266 	}
267 
268 	outb(PITCTL_PORT, PIT_C2 | PIT_READMODE | PIT_RATEMODE);
269 	outb(PITCTR2_PORT, counter & 0xff);
270 	outb(PITCTR2_PORT, counter >> 8);
271 }
272 
273 
274 /* ARGSUSED */
275 static void
276 pit_beep_on(void *arg)
277 {
278 	outb(PITAUX_PORT, inb(PITAUX_PORT) | (PITAUX_OUT2 | PITAUX_GATE2));
279 }
280 
281 
282 /* ARGSUSED */
283 static void
284 pit_beep_off(void *arg)
285 {
286 	outb(PITAUX_PORT, inb(PITAUX_PORT) & ~(PITAUX_OUT2 | PITAUX_GATE2));
287 }
288