15129Smarx /*
25129Smarx * CDDL HEADER START
35129Smarx *
45129Smarx * The contents of this file are subject to the terms of the
55129Smarx * Common Development and Distribution License (the "License").
65129Smarx * You may not use this file except in compliance with the License.
75129Smarx *
85129Smarx * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95129Smarx * or http://www.opensolaris.org/os/licensing.
105129Smarx * See the License for the specific language governing permissions
115129Smarx * and limitations under the License.
125129Smarx *
135129Smarx * When distributing Covered Code, include this CDDL HEADER in each
145129Smarx * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155129Smarx * If applicable, add the following below this CDDL HEADER, with the
165129Smarx * fields enclosed by brackets "[]" replaced with your own identifying
175129Smarx * information: Portions Copyright [yyyy] [name of copyright owner]
185129Smarx *
195129Smarx * CDDL HEADER END
205129Smarx */
215129Smarx /*
227542SRichard.Bean@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
235129Smarx * Use is subject to license terms.
245129Smarx */
255129Smarx
265129Smarx /*
275129Smarx * Simple beeper support for PC platform, using standard timer 2 beeper.
285129Smarx */
295129Smarx
305129Smarx #include <sys/types.h>
315129Smarx #include <sys/conf.h>
325129Smarx #include <sys/beep.h>
335129Smarx #include <sys/ksynch.h>
345129Smarx #include <sys/ddi.h>
355129Smarx #include <sys/sunddi.h>
365129Smarx #include <sys/modctl.h>
375129Smarx #include <sys/pit.h>
385129Smarx #include <sys/inttypes.h>
395129Smarx
405129Smarx #define PIT_BEEP_UNIT(dev) (getminor((dev)))
415129Smarx
425129Smarx typedef struct pit_beep_state {
435129Smarx /* Dip of pit_beep device */
445129Smarx dev_info_t *dip;
455129Smarx
465129Smarx } pit_beep_state_t;
475129Smarx
485129Smarx #define PIT_BEEP_ON 1
495129Smarx #define PIT_BEEP_OFF 0
505129Smarx
515129Smarx /* Pointer to the state structure */
525129Smarx static void *pit_beep_statep;
535129Smarx
545129Smarx static int pit_beep_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
555129Smarx static int pit_beep_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
565129Smarx static int pit_beep_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
575129Smarx void *arg, void **result);
585129Smarx static void pit_beep_freq(void *arg, int freq);
595129Smarx static void pit_beep_on(void *arg);
605129Smarx static void pit_beep_off(void *arg);
615129Smarx
625129Smarx struct cb_ops pit_beep_cb_ops = {
635129Smarx nulldev, /* open */
645129Smarx nulldev, /* close */
655129Smarx nulldev, /* strategy */
665129Smarx nulldev, /* print */
675129Smarx nulldev, /* dump */
685129Smarx nulldev, /* read */
695129Smarx nulldev, /* write */
705129Smarx nulldev, /* ioctl */
715129Smarx nulldev, /* devmap */
725129Smarx nulldev, /* mmap */
735129Smarx nulldev, /* segmap */
745129Smarx nochpoll, /* poll */
755129Smarx ddi_prop_op, /* cb_prop_op */
765129Smarx NULL, /* streamtab */
775129Smarx D_MP | D_NEW
785129Smarx };
795129Smarx
805129Smarx
815129Smarx static struct dev_ops pit_beep_ops = {
825129Smarx DEVO_REV, /* Devo_rev */
835129Smarx 0, /* Refcnt */
845129Smarx pit_beep_info, /* Info */
855129Smarx nulldev, /* Identify */
865129Smarx nulldev, /* Probe */
875129Smarx pit_beep_attach, /* Attach */
885129Smarx pit_beep_detach, /* Detach */
895129Smarx nodev, /* Reset */
905129Smarx &pit_beep_cb_ops, /* Driver operations */
915129Smarx 0, /* Bus operations */
92*7656SSherry.Moore@Sun.COM NULL, /* Power */
93*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */
945129Smarx };
955129Smarx
965129Smarx
975129Smarx static struct modldrv modldrv = {
985129Smarx &mod_driverops, /* This one is a driver */
997542SRichard.Bean@Sun.COM "Intel Pit_beep Driver", /* Name of the module. */
1005129Smarx &pit_beep_ops, /* Driver ops */
1015129Smarx };
1025129Smarx
1035129Smarx
1045129Smarx static struct modlinkage modlinkage = {
1055129Smarx MODREV_1, (void *)&modldrv, NULL
1065129Smarx };
1075129Smarx
1085129Smarx
1095129Smarx
1105129Smarx int
_init(void)1115129Smarx _init(void)
1125129Smarx {
1135129Smarx int error;
1145129Smarx
1155129Smarx /* Initialize the soft state structures */
1165129Smarx if ((error = ddi_soft_state_init(&pit_beep_statep,
1175129Smarx sizeof (pit_beep_state_t), 1)) != 0) {
1185129Smarx
1195129Smarx return (error);
1205129Smarx }
1215129Smarx
1225129Smarx /* Install the loadable module */
1235129Smarx if ((error = mod_install(&modlinkage)) != 0) {
1245129Smarx ddi_soft_state_fini(&pit_beep_statep);
1255129Smarx }
1265129Smarx
1275129Smarx return (error);
1285129Smarx }
1295129Smarx
1305129Smarx
1315129Smarx int
_info(struct modinfo * modinfop)1325129Smarx _info(struct modinfo *modinfop)
1335129Smarx {
1345129Smarx return (mod_info(&modlinkage, modinfop));
1355129Smarx }
1365129Smarx
1375129Smarx int
_fini(void)1385129Smarx _fini(void)
1395129Smarx {
1405129Smarx int error;
1415129Smarx
1425129Smarx error = mod_remove(&modlinkage);
1435129Smarx
1445129Smarx if (error == 0) {
1455129Smarx /* Release per module resources */
1465129Smarx ddi_soft_state_fini(&pit_beep_statep);
1475129Smarx }
1485129Smarx
1495129Smarx return (error);
1505129Smarx }
1515129Smarx
1525129Smarx /*
1535129Smarx * pit_beep_attach:
1545129Smarx */
1555129Smarx static int
pit_beep_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1565129Smarx pit_beep_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1575129Smarx {
1585129Smarx switch (cmd) {
1595129Smarx case DDI_ATTACH:
1605129Smarx break;
1615129Smarx case DDI_RESUME:
1625129Smarx
1635129Smarx return (DDI_SUCCESS);
1645129Smarx default:
1655129Smarx
1665129Smarx return (DDI_FAILURE);
1675129Smarx }
1685129Smarx
1695129Smarx pit_beep_off(dip);
1705129Smarx
1715129Smarx (void) beep_init((void *)dip, pit_beep_on, pit_beep_off,
1725129Smarx pit_beep_freq);
1735129Smarx
1745129Smarx /* Display information in the banner */
1755129Smarx ddi_report_dev(dip);
1765129Smarx
1775129Smarx return (DDI_SUCCESS);
1785129Smarx }
1795129Smarx
1805129Smarx
1815129Smarx /*
1825129Smarx * pit_beep_detach:
1835129Smarx */
1845129Smarx /* ARGSUSED */
1855129Smarx static int
pit_beep_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)1865129Smarx pit_beep_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1875129Smarx {
1885129Smarx switch (cmd) {
1895129Smarx case DDI_SUSPEND:
1905129Smarx
1915129Smarx /*
1925129Smarx * If a beep is in progress; fail suspend
1935129Smarx */
1945129Smarx if (!beep_busy()) {
1955129Smarx
1965129Smarx return (DDI_SUCCESS);
1975129Smarx } else {
1985129Smarx
1995129Smarx return (DDI_FAILURE);
2005129Smarx }
2015129Smarx default:
2025129Smarx
2035129Smarx return (DDI_FAILURE);
2045129Smarx }
2055129Smarx }
2065129Smarx
2075129Smarx
2085129Smarx /*
2095129Smarx * pit_beep_info:
2105129Smarx */
2115129Smarx /* ARGSUSED */
2125129Smarx static int
pit_beep_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)2135129Smarx pit_beep_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
2145129Smarx void *arg, void **result)
2155129Smarx {
2165129Smarx dev_t dev;
2175129Smarx pit_beep_state_t *statep;
2185129Smarx int instance, error;
2195129Smarx
2205129Smarx switch (infocmd) {
2215129Smarx case DDI_INFO_DEVT2DEVINFO:
2225129Smarx dev = (dev_t)arg;
2235129Smarx instance = PIT_BEEP_UNIT(dev);
2245129Smarx
2255129Smarx if ((statep = ddi_get_soft_state(pit_beep_statep,
2265129Smarx instance)) == NULL) {
2275129Smarx
2285129Smarx return (DDI_FAILURE);
2295129Smarx }
2305129Smarx
2315129Smarx *result = (void *)statep->dip;
2325129Smarx
2335129Smarx error = DDI_SUCCESS;
2345129Smarx break;
2355129Smarx case DDI_INFO_DEVT2INSTANCE:
2365129Smarx dev = (dev_t)arg;
2375129Smarx instance = PIT_BEEP_UNIT(dev);
2385129Smarx
2395129Smarx *result = (void *)(uintptr_t)instance;
2405129Smarx
2415129Smarx error = DDI_SUCCESS;
2425129Smarx break;
2435129Smarx default:
2445129Smarx error = DDI_FAILURE;
2455129Smarx
2465129Smarx }
2475129Smarx
2485129Smarx return (error);
2495129Smarx }
2505129Smarx
2515129Smarx
2525129Smarx /* ARGSUSED */
2535129Smarx static void
pit_beep_freq(void * arg,int freq)2545129Smarx pit_beep_freq(void *arg, int freq)
2555129Smarx {
2565129Smarx int counter;
2575129Smarx
2585129Smarx if (freq == 0)
2595129Smarx counter = 0;
2605129Smarx else {
2615129Smarx counter = PIT_HZ / freq;
2625129Smarx if (counter > UINT16_MAX)
2635129Smarx counter = UINT16_MAX;
2645129Smarx else if (counter < 1)
2655129Smarx counter = 1;
2665129Smarx }
2675129Smarx
2685129Smarx outb(PITCTL_PORT, PIT_C2 | PIT_READMODE | PIT_RATEMODE);
2695129Smarx outb(PITCTR2_PORT, counter & 0xff);
2705129Smarx outb(PITCTR2_PORT, counter >> 8);
2715129Smarx }
2725129Smarx
2735129Smarx
2745129Smarx /* ARGSUSED */
2755129Smarx static void
pit_beep_on(void * arg)2765129Smarx pit_beep_on(void *arg)
2775129Smarx {
2785129Smarx outb(PITAUX_PORT, inb(PITAUX_PORT) | (PITAUX_OUT2 | PITAUX_GATE2));
2795129Smarx }
2805129Smarx
2815129Smarx
2825129Smarx /* ARGSUSED */
2835129Smarx static void
pit_beep_off(void * arg)2845129Smarx pit_beep_off(void *arg)
2855129Smarx {
2865129Smarx outb(PITAUX_PORT, inb(PITAUX_PORT) & ~(PITAUX_OUT2 | PITAUX_GATE2));
2875129Smarx }
288