1 /* 2 * PC-Speaker driver for Linux 3 * 4 * Copyright (C) 1993-1997 Michael Beck 5 * Copyright (C) 1997-2001 David Woodhouse 6 * Copyright (C) 2001-2008 Stas Sergeev 7 */ 8 9 #include <linux/module.h> 10 #include <linux/moduleparam.h> 11 #include <linux/interrupt.h> 12 #include <sound/pcm.h> 13 #include <asm/io.h> 14 #include "pcsp.h" 15 16 static int nforce_wa; 17 module_param(nforce_wa, bool, 0444); 18 MODULE_PARM_DESC(nforce_wa, "Apply NForce chipset workaround " 19 "(expect bad sound)"); 20 21 #define DMIX_WANTS_S16 1 22 23 /* 24 * Call snd_pcm_period_elapsed in a tasklet 25 * This avoids spinlock messes and long-running irq contexts 26 */ 27 static void pcsp_call_pcm_elapsed(unsigned long priv) 28 { 29 if (atomic_read(&pcsp_chip.timer_active)) { 30 struct snd_pcm_substream *substream; 31 substream = pcsp_chip.playback_substream; 32 if (substream) 33 snd_pcm_period_elapsed(substream); 34 } 35 } 36 37 static DECLARE_TASKLET(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed, 0); 38 39 /* write the port and returns the next expire time in ns; 40 * called at the trigger-start and in hrtimer callback 41 */ 42 static unsigned long pcsp_timer_update(struct hrtimer *handle) 43 { 44 unsigned char timer_cnt, val; 45 u64 ns; 46 struct snd_pcm_substream *substream; 47 struct snd_pcm_runtime *runtime; 48 struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer); 49 unsigned long flags; 50 51 if (chip->thalf) { 52 outb(chip->val61, 0x61); 53 chip->thalf = 0; 54 if (!atomic_read(&chip->timer_active)) 55 return 0; 56 return chip->ns_rem; 57 } 58 59 if (!atomic_read(&chip->timer_active)) 60 return 0; 61 substream = chip->playback_substream; 62 if (!substream) 63 return 0; 64 65 runtime = substream->runtime; 66 /* assume it is mono! */ 67 val = runtime->dma_area[chip->playback_ptr + chip->fmt_size - 1]; 68 if (chip->is_signed) 69 val ^= 0x80; 70 timer_cnt = val * CUR_DIV() / 256; 71 72 if (timer_cnt && chip->enable) { 73 spin_lock_irqsave(&i8253_lock, flags); 74 if (!nforce_wa) { 75 outb_p(chip->val61, 0x61); 76 outb_p(timer_cnt, 0x42); 77 outb(chip->val61 ^ 1, 0x61); 78 } else { 79 outb(chip->val61 ^ 2, 0x61); 80 chip->thalf = 1; 81 } 82 spin_unlock_irqrestore(&i8253_lock, flags); 83 } 84 85 chip->ns_rem = PCSP_PERIOD_NS(); 86 ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem); 87 chip->ns_rem -= ns; 88 return ns; 89 } 90 91 enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) 92 { 93 struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer); 94 struct snd_pcm_substream *substream; 95 int periods_elapsed, pointer_update; 96 size_t period_bytes, buffer_bytes; 97 unsigned long ns; 98 unsigned long flags; 99 100 pointer_update = !chip->thalf; 101 ns = pcsp_timer_update(handle); 102 if (!ns) 103 return HRTIMER_NORESTART; 104 105 /* update the playback position */ 106 substream = chip->playback_substream; 107 if (!substream) 108 return HRTIMER_NORESTART; 109 110 period_bytes = snd_pcm_lib_period_bytes(substream); 111 buffer_bytes = snd_pcm_lib_buffer_bytes(substream); 112 113 spin_lock_irqsave(&chip->substream_lock, flags); 114 chip->playback_ptr += PCSP_INDEX_INC() * chip->fmt_size; 115 periods_elapsed = chip->playback_ptr - chip->period_ptr; 116 if (periods_elapsed < 0) { 117 #if PCSP_DEBUG 118 printk(KERN_INFO "PCSP: buffer_bytes mod period_bytes != 0 ? " 119 "(%zi %zi %zi)\n", 120 chip->playback_ptr, period_bytes, buffer_bytes); 121 #endif 122 periods_elapsed += buffer_bytes; 123 } 124 periods_elapsed /= period_bytes; 125 /* wrap the pointer _before_ calling snd_pcm_period_elapsed(), 126 * or ALSA will BUG on us. */ 127 chip->playback_ptr %= buffer_bytes; 128 129 if (periods_elapsed) { 130 chip->period_ptr += periods_elapsed * period_bytes; 131 chip->period_ptr %= buffer_bytes; 132 } 133 spin_unlock_irqrestore(&chip->substream_lock, flags); 134 135 if (periods_elapsed) 136 tasklet_schedule(&pcsp_pcm_tasklet); 137 138 hrtimer_forward(handle, hrtimer_get_expires(handle), ns_to_ktime(ns)); 139 140 return HRTIMER_RESTART; 141 } 142 143 static int pcsp_start_playing(struct snd_pcsp *chip) 144 { 145 unsigned long ns; 146 147 #if PCSP_DEBUG 148 printk(KERN_INFO "PCSP: start_playing called\n"); 149 #endif 150 if (atomic_read(&chip->timer_active)) { 151 printk(KERN_ERR "PCSP: Timer already active\n"); 152 return -EIO; 153 } 154 155 spin_lock(&i8253_lock); 156 chip->val61 = inb(0x61) | 0x03; 157 outb_p(0x92, 0x43); /* binary, mode 1, LSB only, ch 2 */ 158 spin_unlock(&i8253_lock); 159 atomic_set(&chip->timer_active, 1); 160 chip->thalf = 0; 161 162 ns = pcsp_timer_update(&pcsp_chip.timer); 163 if (!ns) 164 return -EIO; 165 166 hrtimer_start(&pcsp_chip.timer, ktime_set(0, ns), HRTIMER_MODE_REL); 167 return 0; 168 } 169 170 static void pcsp_stop_playing(struct snd_pcsp *chip) 171 { 172 #if PCSP_DEBUG 173 printk(KERN_INFO "PCSP: stop_playing called\n"); 174 #endif 175 if (!atomic_read(&chip->timer_active)) 176 return; 177 178 atomic_set(&chip->timer_active, 0); 179 spin_lock(&i8253_lock); 180 /* restore the timer */ 181 outb_p(0xb6, 0x43); /* binary, mode 3, LSB/MSB, ch 2 */ 182 outb(chip->val61 & 0xFC, 0x61); 183 spin_unlock(&i8253_lock); 184 } 185 186 /* 187 * Force to stop and sync the stream 188 */ 189 void pcsp_sync_stop(struct snd_pcsp *chip) 190 { 191 local_irq_disable(); 192 pcsp_stop_playing(chip); 193 local_irq_enable(); 194 hrtimer_cancel(&chip->timer); 195 tasklet_kill(&pcsp_pcm_tasklet); 196 } 197 198 static int snd_pcsp_playback_close(struct snd_pcm_substream *substream) 199 { 200 struct snd_pcsp *chip = snd_pcm_substream_chip(substream); 201 #if PCSP_DEBUG 202 printk(KERN_INFO "PCSP: close called\n"); 203 #endif 204 pcsp_sync_stop(chip); 205 chip->playback_substream = NULL; 206 return 0; 207 } 208 209 static int snd_pcsp_playback_hw_params(struct snd_pcm_substream *substream, 210 struct snd_pcm_hw_params *hw_params) 211 { 212 struct snd_pcsp *chip = snd_pcm_substream_chip(substream); 213 int err; 214 pcsp_sync_stop(chip); 215 err = snd_pcm_lib_malloc_pages(substream, 216 params_buffer_bytes(hw_params)); 217 if (err < 0) 218 return err; 219 return 0; 220 } 221 222 static int snd_pcsp_playback_hw_free(struct snd_pcm_substream *substream) 223 { 224 struct snd_pcsp *chip = snd_pcm_substream_chip(substream); 225 #if PCSP_DEBUG 226 printk(KERN_INFO "PCSP: hw_free called\n"); 227 #endif 228 pcsp_sync_stop(chip); 229 return snd_pcm_lib_free_pages(substream); 230 } 231 232 static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream) 233 { 234 struct snd_pcsp *chip = snd_pcm_substream_chip(substream); 235 #if PCSP_DEBUG 236 printk(KERN_INFO "PCSP: prepare called, " 237 "size=%zi psize=%zi f=%zi f1=%i\n", 238 snd_pcm_lib_buffer_bytes(substream), 239 snd_pcm_lib_period_bytes(substream), 240 snd_pcm_lib_buffer_bytes(substream) / 241 snd_pcm_lib_period_bytes(substream), 242 substream->runtime->periods); 243 #endif 244 pcsp_sync_stop(chip); 245 chip->playback_ptr = 0; 246 chip->period_ptr = 0; 247 chip->fmt_size = 248 snd_pcm_format_physical_width(substream->runtime->format) >> 3; 249 chip->is_signed = snd_pcm_format_signed(substream->runtime->format); 250 return 0; 251 } 252 253 static int snd_pcsp_trigger(struct snd_pcm_substream *substream, int cmd) 254 { 255 struct snd_pcsp *chip = snd_pcm_substream_chip(substream); 256 #if PCSP_DEBUG 257 printk(KERN_INFO "PCSP: trigger called\n"); 258 #endif 259 switch (cmd) { 260 case SNDRV_PCM_TRIGGER_START: 261 case SNDRV_PCM_TRIGGER_RESUME: 262 return pcsp_start_playing(chip); 263 case SNDRV_PCM_TRIGGER_STOP: 264 case SNDRV_PCM_TRIGGER_SUSPEND: 265 pcsp_stop_playing(chip); 266 break; 267 default: 268 return -EINVAL; 269 } 270 return 0; 271 } 272 273 static snd_pcm_uframes_t snd_pcsp_playback_pointer(struct snd_pcm_substream 274 *substream) 275 { 276 struct snd_pcsp *chip = snd_pcm_substream_chip(substream); 277 unsigned int pos; 278 spin_lock(&chip->substream_lock); 279 pos = chip->playback_ptr; 280 spin_unlock(&chip->substream_lock); 281 return bytes_to_frames(substream->runtime, pos); 282 } 283 284 static struct snd_pcm_hardware snd_pcsp_playback = { 285 .info = (SNDRV_PCM_INFO_INTERLEAVED | 286 SNDRV_PCM_INFO_HALF_DUPLEX | 287 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), 288 .formats = (SNDRV_PCM_FMTBIT_U8 289 #if DMIX_WANTS_S16 290 | SNDRV_PCM_FMTBIT_S16_LE 291 #endif 292 ), 293 .rates = SNDRV_PCM_RATE_KNOT, 294 .rate_min = PCSP_DEFAULT_SRATE, 295 .rate_max = PCSP_DEFAULT_SRATE, 296 .channels_min = 1, 297 .channels_max = 1, 298 .buffer_bytes_max = PCSP_BUFFER_SIZE, 299 .period_bytes_min = 64, 300 .period_bytes_max = PCSP_MAX_PERIOD_SIZE, 301 .periods_min = 2, 302 .periods_max = PCSP_MAX_PERIODS, 303 .fifo_size = 0, 304 }; 305 306 static int snd_pcsp_playback_open(struct snd_pcm_substream *substream) 307 { 308 struct snd_pcsp *chip = snd_pcm_substream_chip(substream); 309 struct snd_pcm_runtime *runtime = substream->runtime; 310 #if PCSP_DEBUG 311 printk(KERN_INFO "PCSP: open called\n"); 312 #endif 313 if (atomic_read(&chip->timer_active)) { 314 printk(KERN_ERR "PCSP: still active!!\n"); 315 return -EBUSY; 316 } 317 runtime->hw = snd_pcsp_playback; 318 chip->playback_substream = substream; 319 return 0; 320 } 321 322 static struct snd_pcm_ops snd_pcsp_playback_ops = { 323 .open = snd_pcsp_playback_open, 324 .close = snd_pcsp_playback_close, 325 .ioctl = snd_pcm_lib_ioctl, 326 .hw_params = snd_pcsp_playback_hw_params, 327 .hw_free = snd_pcsp_playback_hw_free, 328 .prepare = snd_pcsp_playback_prepare, 329 .trigger = snd_pcsp_trigger, 330 .pointer = snd_pcsp_playback_pointer, 331 }; 332 333 int __devinit snd_pcsp_new_pcm(struct snd_pcsp *chip) 334 { 335 int err; 336 337 err = snd_pcm_new(chip->card, "pcspeaker", 0, 1, 0, &chip->pcm); 338 if (err < 0) 339 return err; 340 341 snd_pcm_set_ops(chip->pcm, SNDRV_PCM_STREAM_PLAYBACK, 342 &snd_pcsp_playback_ops); 343 344 chip->pcm->private_data = chip; 345 chip->pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; 346 strcpy(chip->pcm->name, "pcsp"); 347 348 snd_pcm_lib_preallocate_pages_for_all(chip->pcm, 349 SNDRV_DMA_TYPE_CONTINUOUS, 350 snd_dma_continuous_data 351 (GFP_KERNEL), PCSP_BUFFER_SIZE, 352 PCSP_BUFFER_SIZE); 353 354 return 0; 355 } 356