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