8354 sync regcomp(3C) with upstream (fix make catalog)
[unleashed/tickless.git] / usr / src / uts / sun4u / io / grbeep.c
blobc7c88cbdbb84055b708f5abfaaa3b930b387d753
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * This is the Beep driver for SMBUS based beep mechanism.
29 * The driver exports the interfaces to set frequency,
30 * turn on beeper and turn off beeper to the generic beep
31 * module. If a beep is in progress, the driver discards a
32 * second beep. This driver uses the 8254 timer to program
33 * the beeper ports.
35 #include <sys/types.h>
36 #include <sys/conf.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39 #include <sys/modctl.h>
40 #include <sys/ddi_impldefs.h>
41 #include <sys/kmem.h>
42 #include <sys/devops.h>
43 #include <sys/grbeep.h>
44 #include <sys/beep.h>
47 /* Pointer to the state structure */
48 static void *grbeep_statep;
52 * Debug stuff
54 #ifdef DEBUG
55 int grbeep_debug = 0;
56 #define GRBEEP_DEBUG(args) if (grbeep_debug) cmn_err args
57 #define GRBEEP_DEBUG1(args) if (grbeep_debug > 1) cmn_err args
58 #else
59 #define GRBEEP_DEBUG(args)
60 #define GRBEEP_DEBUG1(args)
61 #endif
65 * Prototypes
67 static int grbeep_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
68 static int grbeep_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
69 static int grbeep_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
70 void **result);
71 static void grbeep_freq(void *arg, int freq);
72 static void grbeep_on(void *arg);
73 static void grbeep_off(void *arg);
74 static void grbeep_cleanup(grbeep_state_t *);
75 static int grbeep_map_regs(dev_info_t *, grbeep_state_t *);
76 static grbeep_state_t *grbeep_obtain_state(dev_info_t *);
79 struct cb_ops grbeep_cb_ops = {
80 nulldev, /* open */
81 nulldev, /* close */
82 nulldev, /* strategy */
83 nulldev, /* print */
84 nulldev, /* dump */
85 nulldev, /* read */
86 nulldev, /* write */
87 nulldev, /* ioctl */
88 nulldev, /* devmap */
89 nulldev, /* mmap */
90 nulldev, /* segmap */
91 nochpoll, /* poll */
92 ddi_prop_op, /* cb_prop_op */
93 NULL, /* streamtab */
94 D_MP | D_NEW
98 static struct dev_ops grbeep_ops = {
99 DEVO_REV, /* Devo_rev */
100 0, /* Refcnt */
101 grbeep_info, /* Info */
102 nulldev, /* Identify */
103 nulldev, /* Probe */
104 grbeep_attach, /* Attach */
105 grbeep_detach, /* Detach */
106 nodev, /* Reset */
107 &grbeep_cb_ops, /* Driver operations */
108 0, /* Bus operations */
109 NULL, /* Power */
110 ddi_quiesce_not_supported, /* devo_quiesce */
114 static struct modldrv modldrv = {
115 &mod_driverops, /* This one is a driver */
116 "SMBUS Beep Driver", /* Name of the module. */
117 &grbeep_ops, /* Driver ops */
121 static struct modlinkage modlinkage = {
122 MODREV_1, (void *)&modldrv, NULL
127 _init(void)
129 int error;
131 /* Initialize the soft state structures */
132 if ((error = ddi_soft_state_init(&grbeep_statep,
133 sizeof (grbeep_state_t), 1)) != 0) {
135 return (error);
138 /* Install the loadable module */
139 if ((error = mod_install(&modlinkage)) != 0) {
140 ddi_soft_state_fini(&grbeep_statep);
143 return (error);
148 _info(struct modinfo *modinfop)
150 return (mod_info(&modlinkage, modinfop));
155 _fini(void)
157 int error;
159 error = mod_remove(&modlinkage);
161 if (error == 0) {
162 /* Release per module resources */
163 ddi_soft_state_fini(&grbeep_statep);
166 return (error);
171 * Beep entry points
175 * grbeep_attach:
177 static int
178 grbeep_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
180 int instance;
182 /* Pointer to soft state */
183 grbeep_state_t *grbeeptr = NULL;
185 GRBEEP_DEBUG1((CE_CONT, "grbeep_attach: Start"));
187 switch (cmd) {
188 case DDI_ATTACH:
189 break;
190 case DDI_RESUME:
192 return (DDI_SUCCESS);
193 default:
195 return (DDI_FAILURE);
198 /* Get the instance and create soft state */
199 instance = ddi_get_instance(dip);
201 if (ddi_soft_state_zalloc(grbeep_statep, instance) != 0) {
203 return (DDI_FAILURE);
206 grbeeptr = ddi_get_soft_state(grbeep_statep, instance);
208 if (grbeeptr == NULL) {
210 return (DDI_FAILURE);
213 GRBEEP_DEBUG1((CE_CONT, "grbeeptr = 0x%p, instance %x",
214 (void *)grbeeptr, instance));
216 /* Save the dip */
217 grbeeptr->grbeep_dip = dip;
219 /* Initialize beeper mode */
220 grbeeptr->grbeep_mode = GRBEEP_OFF;
222 /* Map the Beep Control and Beep counter Registers */
223 if (grbeep_map_regs(dip, grbeeptr) != DDI_SUCCESS) {
225 GRBEEP_DEBUG((CE_WARN,
226 "grbeep_attach: Mapping of beep registers failed."));
228 grbeep_cleanup(grbeeptr);
230 return (DDI_FAILURE);
233 (void) beep_init((void *)dip, grbeep_on, grbeep_off, grbeep_freq);
235 /* Display information in the banner */
236 ddi_report_dev(dip);
238 GRBEEP_DEBUG1((CE_CONT, "grbeep_attach: dip = 0x%p done",
239 (void *)dip));
241 return (DDI_SUCCESS);
246 * grbeep_detach:
248 static int
249 grbeep_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
251 /* Pointer to soft state */
252 grbeep_state_t *grbeeptr = NULL;
254 GRBEEP_DEBUG1((CE_CONT, "grbeep_detach: Start"));
256 switch (cmd) {
257 case DDI_SUSPEND:
258 grbeeptr = grbeep_obtain_state(dip);
260 if (grbeeptr == NULL) {
262 return (DDI_FAILURE);
266 * If a beep is in progress; fail suspend
268 if (grbeeptr->grbeep_mode == GRBEEP_OFF) {
270 return (DDI_SUCCESS);
271 } else {
273 return (DDI_FAILURE);
275 default:
277 return (DDI_FAILURE);
283 * grbeep_info:
285 /* ARGSUSED */
286 static int
287 grbeep_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
288 void *arg, void **result)
290 dev_t dev;
291 grbeep_state_t *grbeeptr;
292 int instance, error;
294 switch (infocmd) {
295 case DDI_INFO_DEVT2DEVINFO:
296 dev = (dev_t)arg;
297 instance = GRBEEP_UNIT(dev);
299 if ((grbeeptr = ddi_get_soft_state(grbeep_statep,
300 instance)) == NULL) {
302 return (DDI_FAILURE);
305 *result = (void *)grbeeptr->grbeep_dip;
307 error = DDI_SUCCESS;
308 break;
309 case DDI_INFO_DEVT2INSTANCE:
310 dev = (dev_t)arg;
311 instance = GRBEEP_UNIT(dev);
313 *result = (void *)(uintptr_t)instance;
315 error = DDI_SUCCESS;
316 break;
317 default:
318 error = DDI_FAILURE;
322 return (error);
327 * grbeep_freq() :
328 * Set beep frequency
330 static void
331 grbeep_freq(void *arg, int freq)
333 dev_info_t *dip = (dev_info_t *)arg;
334 grbeep_state_t *grbeeptr = grbeep_obtain_state(dip);
335 int divisor = 0;
337 ASSERT(freq != 0);
339 GRBEEP_DEBUG1((CE_CONT, "grbeep_freq: dip=0x%p freq=%d mode=%d",
340 (void *)dip, freq, grbeeptr->grbeep_mode));
342 GRBEEP_WRITE_FREQ_CONTROL_REG(GRBEEP_CONTROL);
344 divisor = GRBEEP_INPUT_FREQ / freq;
346 if (divisor > GRBEEP_DIVISOR_MAX) {
347 divisor = GRBEEP_DIVISOR_MAX;
348 } else if (divisor < GRBEEP_DIVISOR_MIN) {
349 divisor = GRBEEP_DIVISOR_MIN;
352 GRBEEP_DEBUG1((CE_CONT, "grbeep_freq: first=0x%x second=0x%x",
353 (divisor & 0xff), ((divisor & 0xff00) >> 8)));
355 GRBEEP_WRITE_FREQ_DIVISOR_REG(divisor & 0xff);
356 GRBEEP_WRITE_FREQ_DIVISOR_REG((divisor & 0xff00) >> 8);
361 * grbeep_on() :
362 * Turn the beeper on
364 static void
365 grbeep_on(void *arg)
367 dev_info_t *dip = (dev_info_t *)arg;
368 grbeep_state_t *grbeeptr = grbeep_obtain_state(dip);
370 GRBEEP_DEBUG1((CE_CONT, "grbeep_on: dip = 0x%p mode=%d",
371 (void *)dip, grbeeptr->grbeep_mode));
373 if (grbeeptr->grbeep_mode == GRBEEP_OFF) {
375 grbeeptr->grbeep_mode = GRBEEP_ON;
376 GRBEEP_DEBUG1((CE_CONT, "grbeep_on: Starting beep"));
377 GRBEEP_WRITE_START_STOP_REG(GRBEEP_START);
381 GRBEEP_DEBUG1((CE_CONT, "grbeep_on: dip = 0x%p done", (void *)dip));
386 * grbeep_off() :
387 * Turn the beeper off
389 static void
390 grbeep_off(void *arg)
392 dev_info_t *dip = (dev_info_t *)arg;
393 grbeep_state_t *grbeeptr = grbeep_obtain_state(dip);
395 GRBEEP_DEBUG1((CE_CONT, "grbeep_off: dip = 0x%p mode=%d",
396 (void *)dip, grbeeptr->grbeep_mode));
398 if (grbeeptr->grbeep_mode == GRBEEP_ON) {
400 grbeeptr->grbeep_mode = GRBEEP_OFF;
401 GRBEEP_DEBUG1((CE_CONT, "grbeep_off: Stopping beep"));
402 GRBEEP_WRITE_START_STOP_REG(GRBEEP_STOP);
406 GRBEEP_DEBUG1((CE_CONT, "grbeep_off: dip = 0x%p done", (void *)dip));
410 * grbeep_map_regs() :
412 * The write beep port register and spkr control register
413 * should be mapped into a non-cacheable portion of the system
414 * addressable space.
416 static int
417 grbeep_map_regs(dev_info_t *dip, grbeep_state_t *grbeeptr)
419 ddi_device_acc_attr_t attr;
421 GRBEEP_DEBUG1((CE_CONT, "grbeep_map_regs: Start"));
423 /* The host controller will be little endian */
424 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
425 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
426 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
428 /* Map in operational registers */
429 if (ddi_regs_map_setup(dip, 2,
430 (caddr_t *)&grbeeptr->grbeep_freq_regs,
432 sizeof (grbeep_freq_regs_t),
433 &attr,
434 &grbeeptr->grbeep_freq_regs_handle)
435 != DDI_SUCCESS) {
437 GRBEEP_DEBUG((CE_CONT, "grbeep_map_regs: Failed to map"));
438 return (DDI_FAILURE);
441 /* Map in operational registers */
442 if (ddi_regs_map_setup(dip, 3,
443 (caddr_t *)&grbeeptr->grbeep_start_stop_reg,
446 &attr,
447 &grbeeptr->grbeep_start_stop_reg_handle)
448 != DDI_SUCCESS) {
450 GRBEEP_DEBUG((CE_CONT, "grbeep_map_regs: Failed to map"));
451 ddi_regs_map_free((void *)&grbeeptr->grbeep_freq_regs_handle);
453 return (DDI_FAILURE);
456 GRBEEP_DEBUG1((CE_CONT, "grbeep_map_regs: done"));
458 return (DDI_SUCCESS);
463 * grbeep_obtain_state:
465 static grbeep_state_t *
466 grbeep_obtain_state(dev_info_t *dip)
468 int instance = ddi_get_instance(dip);
470 grbeep_state_t *state = ddi_get_soft_state(grbeep_statep, instance);
472 ASSERT(state != NULL);
474 GRBEEP_DEBUG1((CE_CONT, "grbeep_obtain_state: done"));
476 return (state);
481 * grbeep_cleanup :
482 * Cleanup soft state
484 static void
485 grbeep_cleanup(grbeep_state_t *grbeeptr)
487 int instance = ddi_get_instance(grbeeptr->grbeep_dip);
489 ddi_soft_state_free(grbeep_statep, instance);
491 GRBEEP_DEBUG1((CE_CONT, "grbeep_cleanup: done"));