| .. | .. |
|---|
| 102 | 102 | case SND_BELL: |
|---|
| 103 | 103 | if (hz) |
|---|
| 104 | 104 | hz = 1000; |
|---|
| 105 | | - /* fallthru */ |
|---|
| 105 | + fallthrough; |
|---|
| 106 | 106 | case SND_TONE: |
|---|
| 107 | 107 | if (beep->linear_tone) |
|---|
| 108 | 108 | beep->tone = beep_linear_tone(beep, hz); |
|---|
| .. | .. |
|---|
| 118 | 118 | return 0; |
|---|
| 119 | 119 | } |
|---|
| 120 | 120 | |
|---|
| 121 | +static void turn_on_beep(struct hda_beep *beep) |
|---|
| 122 | +{ |
|---|
| 123 | + if (beep->keep_power_at_enable) |
|---|
| 124 | + snd_hda_power_up_pm(beep->codec); |
|---|
| 125 | +} |
|---|
| 126 | + |
|---|
| 121 | 127 | static void turn_off_beep(struct hda_beep *beep) |
|---|
| 122 | 128 | { |
|---|
| 123 | 129 | cancel_work_sync(&beep->beep_work); |
|---|
| .. | .. |
|---|
| 125 | 131 | /* turn off beep */ |
|---|
| 126 | 132 | generate_tone(beep, 0); |
|---|
| 127 | 133 | } |
|---|
| 128 | | -} |
|---|
| 129 | | - |
|---|
| 130 | | -static void snd_hda_do_detach(struct hda_beep *beep) |
|---|
| 131 | | -{ |
|---|
| 132 | | - if (beep->registered) |
|---|
| 133 | | - input_unregister_device(beep->dev); |
|---|
| 134 | | - else |
|---|
| 135 | | - input_free_device(beep->dev); |
|---|
| 136 | | - beep->dev = NULL; |
|---|
| 137 | | - turn_off_beep(beep); |
|---|
| 138 | | -} |
|---|
| 139 | | - |
|---|
| 140 | | -static int snd_hda_do_attach(struct hda_beep *beep) |
|---|
| 141 | | -{ |
|---|
| 142 | | - struct input_dev *input_dev; |
|---|
| 143 | | - struct hda_codec *codec = beep->codec; |
|---|
| 144 | | - |
|---|
| 145 | | - input_dev = input_allocate_device(); |
|---|
| 146 | | - if (!input_dev) |
|---|
| 147 | | - return -ENOMEM; |
|---|
| 148 | | - |
|---|
| 149 | | - /* setup digital beep device */ |
|---|
| 150 | | - input_dev->name = "HDA Digital PCBeep"; |
|---|
| 151 | | - input_dev->phys = beep->phys; |
|---|
| 152 | | - input_dev->id.bustype = BUS_PCI; |
|---|
| 153 | | - input_dev->dev.parent = &codec->card->card_dev; |
|---|
| 154 | | - |
|---|
| 155 | | - input_dev->id.vendor = codec->core.vendor_id >> 16; |
|---|
| 156 | | - input_dev->id.product = codec->core.vendor_id & 0xffff; |
|---|
| 157 | | - input_dev->id.version = 0x01; |
|---|
| 158 | | - |
|---|
| 159 | | - input_dev->evbit[0] = BIT_MASK(EV_SND); |
|---|
| 160 | | - input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); |
|---|
| 161 | | - input_dev->event = snd_hda_beep_event; |
|---|
| 162 | | - input_set_drvdata(input_dev, beep); |
|---|
| 163 | | - |
|---|
| 164 | | - beep->dev = input_dev; |
|---|
| 165 | | - return 0; |
|---|
| 134 | + if (beep->keep_power_at_enable) |
|---|
| 135 | + snd_hda_power_down_pm(beep->codec); |
|---|
| 166 | 136 | } |
|---|
| 167 | 137 | |
|---|
| 168 | 138 | /** |
|---|
| .. | .. |
|---|
| 178 | 148 | enable = !!enable; |
|---|
| 179 | 149 | if (beep->enabled != enable) { |
|---|
| 180 | 150 | beep->enabled = enable; |
|---|
| 181 | | - if (!enable) |
|---|
| 151 | + if (enable) |
|---|
| 152 | + turn_on_beep(beep); |
|---|
| 153 | + else |
|---|
| 182 | 154 | turn_off_beep(beep); |
|---|
| 183 | 155 | return 1; |
|---|
| 184 | 156 | } |
|---|
| 185 | 157 | return 0; |
|---|
| 186 | 158 | } |
|---|
| 187 | 159 | EXPORT_SYMBOL_GPL(snd_hda_enable_beep_device); |
|---|
| 160 | + |
|---|
| 161 | +static int beep_dev_register(struct snd_device *device) |
|---|
| 162 | +{ |
|---|
| 163 | + struct hda_beep *beep = device->device_data; |
|---|
| 164 | + int err; |
|---|
| 165 | + |
|---|
| 166 | + err = input_register_device(beep->dev); |
|---|
| 167 | + if (!err) |
|---|
| 168 | + beep->registered = true; |
|---|
| 169 | + return err; |
|---|
| 170 | +} |
|---|
| 171 | + |
|---|
| 172 | +static int beep_dev_disconnect(struct snd_device *device) |
|---|
| 173 | +{ |
|---|
| 174 | + struct hda_beep *beep = device->device_data; |
|---|
| 175 | + |
|---|
| 176 | + if (beep->registered) |
|---|
| 177 | + input_unregister_device(beep->dev); |
|---|
| 178 | + else |
|---|
| 179 | + input_free_device(beep->dev); |
|---|
| 180 | + if (beep->enabled) |
|---|
| 181 | + turn_off_beep(beep); |
|---|
| 182 | + return 0; |
|---|
| 183 | +} |
|---|
| 184 | + |
|---|
| 185 | +static int beep_dev_free(struct snd_device *device) |
|---|
| 186 | +{ |
|---|
| 187 | + struct hda_beep *beep = device->device_data; |
|---|
| 188 | + |
|---|
| 189 | + beep->codec->beep = NULL; |
|---|
| 190 | + kfree(beep); |
|---|
| 191 | + return 0; |
|---|
| 192 | +} |
|---|
| 188 | 193 | |
|---|
| 189 | 194 | /** |
|---|
| 190 | 195 | * snd_hda_attach_beep_device - Attach a beep input device |
|---|
| .. | .. |
|---|
| 194 | 199 | * Attach a beep object to the given widget. If beep hint is turned off |
|---|
| 195 | 200 | * explicitly or beep_mode of the codec is turned off, this doesn't nothing. |
|---|
| 196 | 201 | * |
|---|
| 197 | | - * The attached beep device has to be registered via |
|---|
| 198 | | - * snd_hda_register_beep_device() and released via snd_hda_detach_beep_device() |
|---|
| 199 | | - * appropriately. |
|---|
| 200 | | - * |
|---|
| 201 | 202 | * Currently, only one beep device is allowed to each codec. |
|---|
| 202 | 203 | */ |
|---|
| 203 | 204 | int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) |
|---|
| 204 | 205 | { |
|---|
| 206 | + static const struct snd_device_ops ops = { |
|---|
| 207 | + .dev_register = beep_dev_register, |
|---|
| 208 | + .dev_disconnect = beep_dev_disconnect, |
|---|
| 209 | + .dev_free = beep_dev_free, |
|---|
| 210 | + }; |
|---|
| 211 | + struct input_dev *input_dev; |
|---|
| 205 | 212 | struct hda_beep *beep; |
|---|
| 206 | 213 | int err; |
|---|
| 207 | 214 | |
|---|
| .. | .. |
|---|
| 226 | 233 | INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); |
|---|
| 227 | 234 | mutex_init(&beep->mutex); |
|---|
| 228 | 235 | |
|---|
| 229 | | - err = snd_hda_do_attach(beep); |
|---|
| 230 | | - if (err < 0) { |
|---|
| 231 | | - kfree(beep); |
|---|
| 232 | | - codec->beep = NULL; |
|---|
| 233 | | - return err; |
|---|
| 236 | + input_dev = input_allocate_device(); |
|---|
| 237 | + if (!input_dev) { |
|---|
| 238 | + err = -ENOMEM; |
|---|
| 239 | + goto err_free; |
|---|
| 234 | 240 | } |
|---|
| 235 | 241 | |
|---|
| 242 | + /* setup digital beep device */ |
|---|
| 243 | + input_dev->name = "HDA Digital PCBeep"; |
|---|
| 244 | + input_dev->phys = beep->phys; |
|---|
| 245 | + input_dev->id.bustype = BUS_PCI; |
|---|
| 246 | + input_dev->dev.parent = &codec->card->card_dev; |
|---|
| 247 | + |
|---|
| 248 | + input_dev->id.vendor = codec->core.vendor_id >> 16; |
|---|
| 249 | + input_dev->id.product = codec->core.vendor_id & 0xffff; |
|---|
| 250 | + input_dev->id.version = 0x01; |
|---|
| 251 | + |
|---|
| 252 | + input_dev->evbit[0] = BIT_MASK(EV_SND); |
|---|
| 253 | + input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); |
|---|
| 254 | + input_dev->event = snd_hda_beep_event; |
|---|
| 255 | + input_set_drvdata(input_dev, beep); |
|---|
| 256 | + |
|---|
| 257 | + beep->dev = input_dev; |
|---|
| 258 | + |
|---|
| 259 | + err = snd_device_new(codec->card, SNDRV_DEV_JACK, beep, &ops); |
|---|
| 260 | + if (err < 0) |
|---|
| 261 | + goto err_input; |
|---|
| 262 | + |
|---|
| 236 | 263 | return 0; |
|---|
| 264 | + |
|---|
| 265 | + err_input: |
|---|
| 266 | + input_free_device(beep->dev); |
|---|
| 267 | + err_free: |
|---|
| 268 | + kfree(beep); |
|---|
| 269 | + codec->beep = NULL; |
|---|
| 270 | + return err; |
|---|
| 237 | 271 | } |
|---|
| 238 | 272 | EXPORT_SYMBOL_GPL(snd_hda_attach_beep_device); |
|---|
| 239 | 273 | |
|---|
| .. | .. |
|---|
| 243 | 277 | */ |
|---|
| 244 | 278 | void snd_hda_detach_beep_device(struct hda_codec *codec) |
|---|
| 245 | 279 | { |
|---|
| 246 | | - struct hda_beep *beep = codec->beep; |
|---|
| 247 | | - if (beep) { |
|---|
| 248 | | - if (beep->dev) |
|---|
| 249 | | - snd_hda_do_detach(beep); |
|---|
| 250 | | - codec->beep = NULL; |
|---|
| 251 | | - kfree(beep); |
|---|
| 252 | | - } |
|---|
| 280 | + if (!codec->bus->shutdown && codec->beep) |
|---|
| 281 | + snd_device_free(codec->card, codec->beep); |
|---|
| 253 | 282 | } |
|---|
| 254 | 283 | EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device); |
|---|
| 255 | | - |
|---|
| 256 | | -/** |
|---|
| 257 | | - * snd_hda_register_beep_device - Register the beep device |
|---|
| 258 | | - * @codec: the HDA codec |
|---|
| 259 | | - */ |
|---|
| 260 | | -int snd_hda_register_beep_device(struct hda_codec *codec) |
|---|
| 261 | | -{ |
|---|
| 262 | | - struct hda_beep *beep = codec->beep; |
|---|
| 263 | | - int err; |
|---|
| 264 | | - |
|---|
| 265 | | - if (!beep || !beep->dev) |
|---|
| 266 | | - return 0; |
|---|
| 267 | | - |
|---|
| 268 | | - err = input_register_device(beep->dev); |
|---|
| 269 | | - if (err < 0) { |
|---|
| 270 | | - codec_err(codec, "hda_beep: unable to register input device\n"); |
|---|
| 271 | | - input_free_device(beep->dev); |
|---|
| 272 | | - codec->beep = NULL; |
|---|
| 273 | | - kfree(beep); |
|---|
| 274 | | - return err; |
|---|
| 275 | | - } |
|---|
| 276 | | - beep->registered = true; |
|---|
| 277 | | - return 0; |
|---|
| 278 | | -} |
|---|
| 279 | | -EXPORT_SYMBOL_GPL(snd_hda_register_beep_device); |
|---|
| 280 | 284 | |
|---|
| 281 | 285 | static bool ctl_has_mute(struct snd_kcontrol *kcontrol) |
|---|
| 282 | 286 | { |
|---|