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