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 /* 22*7542SRichard.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 */ 925129Smarx NULL /* Power */ 935129Smarx }; 945129Smarx 955129Smarx 965129Smarx static struct modldrv modldrv = { 975129Smarx &mod_driverops, /* This one is a driver */ 98*7542SRichard.Bean@Sun.COM "Intel Pit_beep Driver", /* Name of the module. */ 995129Smarx &pit_beep_ops, /* Driver ops */ 1005129Smarx }; 1015129Smarx 1025129Smarx 1035129Smarx static struct modlinkage modlinkage = { 1045129Smarx MODREV_1, (void *)&modldrv, NULL 1055129Smarx }; 1065129Smarx 1075129Smarx 1085129Smarx 1095129Smarx int 1105129Smarx _init(void) 1115129Smarx { 1125129Smarx int error; 1135129Smarx 1145129Smarx /* Initialize the soft state structures */ 1155129Smarx if ((error = ddi_soft_state_init(&pit_beep_statep, 1165129Smarx sizeof (pit_beep_state_t), 1)) != 0) { 1175129Smarx 1185129Smarx return (error); 1195129Smarx } 1205129Smarx 1215129Smarx /* Install the loadable module */ 1225129Smarx if ((error = mod_install(&modlinkage)) != 0) { 1235129Smarx ddi_soft_state_fini(&pit_beep_statep); 1245129Smarx } 1255129Smarx 1265129Smarx return (error); 1275129Smarx } 1285129Smarx 1295129Smarx 1305129Smarx int 1315129Smarx _info(struct modinfo *modinfop) 1325129Smarx { 1335129Smarx return (mod_info(&modlinkage, modinfop)); 1345129Smarx } 1355129Smarx 1365129Smarx int 1375129Smarx _fini(void) 1385129Smarx { 1395129Smarx int error; 1405129Smarx 1415129Smarx error = mod_remove(&modlinkage); 1425129Smarx 1435129Smarx if (error == 0) { 1445129Smarx /* Release per module resources */ 1455129Smarx ddi_soft_state_fini(&pit_beep_statep); 1465129Smarx } 1475129Smarx 1485129Smarx return (error); 1495129Smarx } 1505129Smarx 1515129Smarx /* 1525129Smarx * pit_beep_attach: 1535129Smarx */ 1545129Smarx static int 1555129Smarx pit_beep_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1565129Smarx { 1575129Smarx switch (cmd) { 1585129Smarx case DDI_ATTACH: 1595129Smarx break; 1605129Smarx case DDI_RESUME: 1615129Smarx 1625129Smarx return (DDI_SUCCESS); 1635129Smarx default: 1645129Smarx 1655129Smarx return (DDI_FAILURE); 1665129Smarx } 1675129Smarx 1685129Smarx pit_beep_off(dip); 1695129Smarx 1705129Smarx (void) beep_init((void *)dip, pit_beep_on, pit_beep_off, 1715129Smarx pit_beep_freq); 1725129Smarx 1735129Smarx /* Display information in the banner */ 1745129Smarx ddi_report_dev(dip); 1755129Smarx 1765129Smarx return (DDI_SUCCESS); 1775129Smarx } 1785129Smarx 1795129Smarx 1805129Smarx /* 1815129Smarx * pit_beep_detach: 1825129Smarx */ 1835129Smarx /* ARGSUSED */ 1845129Smarx static int 1855129Smarx pit_beep_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 1865129Smarx { 1875129Smarx switch (cmd) { 1885129Smarx case DDI_SUSPEND: 1895129Smarx 1905129Smarx /* 1915129Smarx * If a beep is in progress; fail suspend 1925129Smarx */ 1935129Smarx if (!beep_busy()) { 1945129Smarx 1955129Smarx return (DDI_SUCCESS); 1965129Smarx } else { 1975129Smarx 1985129Smarx return (DDI_FAILURE); 1995129Smarx } 2005129Smarx default: 2015129Smarx 2025129Smarx return (DDI_FAILURE); 2035129Smarx } 2045129Smarx } 2055129Smarx 2065129Smarx 2075129Smarx /* 2085129Smarx * pit_beep_info: 2095129Smarx */ 2105129Smarx /* ARGSUSED */ 2115129Smarx static int 2125129Smarx pit_beep_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 2135129Smarx void *arg, void **result) 2145129Smarx { 2155129Smarx dev_t dev; 2165129Smarx pit_beep_state_t *statep; 2175129Smarx int instance, error; 2185129Smarx 2195129Smarx switch (infocmd) { 2205129Smarx case DDI_INFO_DEVT2DEVINFO: 2215129Smarx dev = (dev_t)arg; 2225129Smarx instance = PIT_BEEP_UNIT(dev); 2235129Smarx 2245129Smarx if ((statep = ddi_get_soft_state(pit_beep_statep, 2255129Smarx instance)) == NULL) { 2265129Smarx 2275129Smarx return (DDI_FAILURE); 2285129Smarx } 2295129Smarx 2305129Smarx *result = (void *)statep->dip; 2315129Smarx 2325129Smarx error = DDI_SUCCESS; 2335129Smarx break; 2345129Smarx case DDI_INFO_DEVT2INSTANCE: 2355129Smarx dev = (dev_t)arg; 2365129Smarx instance = PIT_BEEP_UNIT(dev); 2375129Smarx 2385129Smarx *result = (void *)(uintptr_t)instance; 2395129Smarx 2405129Smarx error = DDI_SUCCESS; 2415129Smarx break; 2425129Smarx default: 2435129Smarx error = DDI_FAILURE; 2445129Smarx 2455129Smarx } 2465129Smarx 2475129Smarx return (error); 2485129Smarx } 2495129Smarx 2505129Smarx 2515129Smarx /* ARGSUSED */ 2525129Smarx static void 2535129Smarx pit_beep_freq(void *arg, int freq) 2545129Smarx { 2555129Smarx int counter; 2565129Smarx 2575129Smarx if (freq == 0) 2585129Smarx counter = 0; 2595129Smarx else { 2605129Smarx counter = PIT_HZ / freq; 2615129Smarx if (counter > UINT16_MAX) 2625129Smarx counter = UINT16_MAX; 2635129Smarx else if (counter < 1) 2645129Smarx counter = 1; 2655129Smarx } 2665129Smarx 2675129Smarx outb(PITCTL_PORT, PIT_C2 | PIT_READMODE | PIT_RATEMODE); 2685129Smarx outb(PITCTR2_PORT, counter & 0xff); 2695129Smarx outb(PITCTR2_PORT, counter >> 8); 2705129Smarx } 2715129Smarx 2725129Smarx 2735129Smarx /* ARGSUSED */ 2745129Smarx static void 2755129Smarx pit_beep_on(void *arg) 2765129Smarx { 2775129Smarx outb(PITAUX_PORT, inb(PITAUX_PORT) | (PITAUX_OUT2 | PITAUX_GATE2)); 2785129Smarx } 2795129Smarx 2805129Smarx 2815129Smarx /* ARGSUSED */ 2825129Smarx static void 2835129Smarx pit_beep_off(void *arg) 2845129Smarx { 2855129Smarx outb(PITAUX_PORT, inb(PITAUX_PORT) & ~(PITAUX_OUT2 | PITAUX_GATE2)); 2865129Smarx } 287