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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Simple beeper support for PC platform, using standard timer 2 beeper. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/conf.h> 34 #include <sys/beep.h> 35 #include <sys/ksynch.h> 36 #include <sys/ddi.h> 37 #include <sys/sunddi.h> 38 #include <sys/modctl.h> 39 #include <sys/pit.h> 40 #include <sys/inttypes.h> 41 42 #define PIT_BEEP_UNIT(dev) (getminor((dev))) 43 44 typedef struct pit_beep_state { 45 /* Dip of pit_beep device */ 46 dev_info_t *dip; 47 48 } pit_beep_state_t; 49 50 #define PIT_BEEP_ON 1 51 #define PIT_BEEP_OFF 0 52 53 /* Pointer to the state structure */ 54 static void *pit_beep_statep; 55 56 static int pit_beep_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 57 static int pit_beep_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 58 static int pit_beep_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 59 void *arg, void **result); 60 static void pit_beep_freq(void *arg, int freq); 61 static void pit_beep_on(void *arg); 62 static void pit_beep_off(void *arg); 63 64 struct cb_ops pit_beep_cb_ops = { 65 nulldev, /* open */ 66 nulldev, /* close */ 67 nulldev, /* strategy */ 68 nulldev, /* print */ 69 nulldev, /* dump */ 70 nulldev, /* read */ 71 nulldev, /* write */ 72 nulldev, /* ioctl */ 73 nulldev, /* devmap */ 74 nulldev, /* mmap */ 75 nulldev, /* segmap */ 76 nochpoll, /* poll */ 77 ddi_prop_op, /* cb_prop_op */ 78 NULL, /* streamtab */ 79 D_MP | D_NEW 80 }; 81 82 83 static struct dev_ops pit_beep_ops = { 84 DEVO_REV, /* Devo_rev */ 85 0, /* Refcnt */ 86 pit_beep_info, /* Info */ 87 nulldev, /* Identify */ 88 nulldev, /* Probe */ 89 pit_beep_attach, /* Attach */ 90 pit_beep_detach, /* Detach */ 91 nodev, /* Reset */ 92 &pit_beep_cb_ops, /* Driver operations */ 93 0, /* Bus operations */ 94 NULL /* Power */ 95 }; 96 97 98 static struct modldrv modldrv = { 99 &mod_driverops, /* This one is a driver */ 100 "Intel Pit_beep Driver %I%", /* Name of the module. */ 101 &pit_beep_ops, /* Driver ops */ 102 }; 103 104 105 static struct modlinkage modlinkage = { 106 MODREV_1, (void *)&modldrv, NULL 107 }; 108 109 110 111 int 112 _init(void) 113 { 114 int error; 115 116 /* Initialize the soft state structures */ 117 if ((error = ddi_soft_state_init(&pit_beep_statep, 118 sizeof (pit_beep_state_t), 1)) != 0) { 119 120 return (error); 121 } 122 123 /* Install the loadable module */ 124 if ((error = mod_install(&modlinkage)) != 0) { 125 ddi_soft_state_fini(&pit_beep_statep); 126 } 127 128 return (error); 129 } 130 131 132 int 133 _info(struct modinfo *modinfop) 134 { 135 return (mod_info(&modlinkage, modinfop)); 136 } 137 138 int 139 _fini(void) 140 { 141 int error; 142 143 error = mod_remove(&modlinkage); 144 145 if (error == 0) { 146 /* Release per module resources */ 147 ddi_soft_state_fini(&pit_beep_statep); 148 } 149 150 return (error); 151 } 152 153 /* 154 * pit_beep_attach: 155 */ 156 static int 157 pit_beep_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 158 { 159 switch (cmd) { 160 case DDI_ATTACH: 161 break; 162 case DDI_RESUME: 163 164 return (DDI_SUCCESS); 165 default: 166 167 return (DDI_FAILURE); 168 } 169 170 pit_beep_off(dip); 171 172 (void) beep_init((void *)dip, pit_beep_on, pit_beep_off, 173 pit_beep_freq); 174 175 /* Display information in the banner */ 176 ddi_report_dev(dip); 177 178 return (DDI_SUCCESS); 179 } 180 181 182 /* 183 * pit_beep_detach: 184 */ 185 /* ARGSUSED */ 186 static int 187 pit_beep_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 188 { 189 switch (cmd) { 190 case DDI_SUSPEND: 191 192 /* 193 * If a beep is in progress; fail suspend 194 */ 195 if (!beep_busy()) { 196 197 return (DDI_SUCCESS); 198 } else { 199 200 return (DDI_FAILURE); 201 } 202 default: 203 204 return (DDI_FAILURE); 205 } 206 } 207 208 209 /* 210 * pit_beep_info: 211 */ 212 /* ARGSUSED */ 213 static int 214 pit_beep_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 215 void *arg, void **result) 216 { 217 dev_t dev; 218 pit_beep_state_t *statep; 219 int instance, error; 220 221 switch (infocmd) { 222 case DDI_INFO_DEVT2DEVINFO: 223 dev = (dev_t)arg; 224 instance = PIT_BEEP_UNIT(dev); 225 226 if ((statep = ddi_get_soft_state(pit_beep_statep, 227 instance)) == NULL) { 228 229 return (DDI_FAILURE); 230 } 231 232 *result = (void *)statep->dip; 233 234 error = DDI_SUCCESS; 235 break; 236 case DDI_INFO_DEVT2INSTANCE: 237 dev = (dev_t)arg; 238 instance = PIT_BEEP_UNIT(dev); 239 240 *result = (void *)(uintptr_t)instance; 241 242 error = DDI_SUCCESS; 243 break; 244 default: 245 error = DDI_FAILURE; 246 247 } 248 249 return (error); 250 } 251 252 253 /* ARGSUSED */ 254 static void 255 pit_beep_freq(void *arg, int freq) 256 { 257 int counter; 258 259 if (freq == 0) 260 counter = 0; 261 else { 262 counter = PIT_HZ / freq; 263 if (counter > UINT16_MAX) 264 counter = UINT16_MAX; 265 else if (counter < 1) 266 counter = 1; 267 } 268 269 outb(PITCTL_PORT, PIT_C2 | PIT_READMODE | PIT_RATEMODE); 270 outb(PITCTR2_PORT, counter & 0xff); 271 outb(PITCTR2_PORT, counter >> 8); 272 } 273 274 275 /* ARGSUSED */ 276 static void 277 pit_beep_on(void *arg) 278 { 279 outb(PITAUX_PORT, inb(PITAUX_PORT) | (PITAUX_OUT2 | PITAUX_GATE2)); 280 } 281 282 283 /* ARGSUSED */ 284 static void 285 pit_beep_off(void *arg) 286 { 287 outb(PITAUX_PORT, inb(PITAUX_PORT) & ~(PITAUX_OUT2 | PITAUX_GATE2)); 288 } 289