0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/module.h>
0011 #include <linux/gfp.h>
0012 #include <linux/moduleparam.h>
0013 #include <linux/interrupt.h>
0014 #include <linux/io.h>
0015 #include <sound/pcm.h>
0016 #include "pcsp.h"
0017
0018 static bool nforce_wa;
0019 module_param(nforce_wa, bool, 0444);
0020 MODULE_PARM_DESC(nforce_wa, "Apply NForce chipset workaround "
0021 "(expect bad sound)");
0022
0023 #define DMIX_WANTS_S16 1
0024
0025
0026
0027
0028
0029 static void pcsp_call_pcm_elapsed(struct work_struct *work)
0030 {
0031 if (atomic_read(&pcsp_chip.timer_active)) {
0032 struct snd_pcm_substream *substream;
0033 substream = pcsp_chip.playback_substream;
0034 if (substream)
0035 snd_pcm_period_elapsed(substream);
0036 }
0037 }
0038
0039 static DECLARE_WORK(pcsp_pcm_work, pcsp_call_pcm_elapsed);
0040
0041
0042
0043
0044 static u64 pcsp_timer_update(struct snd_pcsp *chip)
0045 {
0046 unsigned char timer_cnt, val;
0047 u64 ns;
0048 struct snd_pcm_substream *substream;
0049 struct snd_pcm_runtime *runtime;
0050 unsigned long flags;
0051
0052 if (chip->thalf) {
0053 outb(chip->val61, 0x61);
0054 chip->thalf = 0;
0055 return chip->ns_rem;
0056 }
0057
0058 substream = chip->playback_substream;
0059 if (!substream)
0060 return 0;
0061
0062 runtime = substream->runtime;
0063
0064 val = runtime->dma_area[chip->playback_ptr + chip->fmt_size - 1];
0065 if (chip->is_signed)
0066 val ^= 0x80;
0067 timer_cnt = val * CUR_DIV() / 256;
0068
0069 if (timer_cnt && chip->enable) {
0070 raw_spin_lock_irqsave(&i8253_lock, flags);
0071 if (!nforce_wa) {
0072 outb_p(chip->val61, 0x61);
0073 outb_p(timer_cnt, 0x42);
0074 outb(chip->val61 ^ 1, 0x61);
0075 } else {
0076 outb(chip->val61 ^ 2, 0x61);
0077 chip->thalf = 1;
0078 }
0079 raw_spin_unlock_irqrestore(&i8253_lock, flags);
0080 }
0081
0082 chip->ns_rem = PCSP_PERIOD_NS();
0083 ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem);
0084 chip->ns_rem -= ns;
0085 return ns;
0086 }
0087
0088 static void pcsp_pointer_update(struct snd_pcsp *chip)
0089 {
0090 struct snd_pcm_substream *substream;
0091 size_t period_bytes, buffer_bytes;
0092 int periods_elapsed;
0093 unsigned long flags;
0094
0095
0096 substream = chip->playback_substream;
0097 if (!substream)
0098 return;
0099
0100 period_bytes = snd_pcm_lib_period_bytes(substream);
0101 buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
0102
0103 spin_lock_irqsave(&chip->substream_lock, flags);
0104 chip->playback_ptr += PCSP_INDEX_INC() * chip->fmt_size;
0105 periods_elapsed = chip->playback_ptr - chip->period_ptr;
0106 if (periods_elapsed < 0) {
0107 #if PCSP_DEBUG
0108 printk(KERN_INFO "PCSP: buffer_bytes mod period_bytes != 0 ? "
0109 "(%zi %zi %zi)\n",
0110 chip->playback_ptr, period_bytes, buffer_bytes);
0111 #endif
0112 periods_elapsed += buffer_bytes;
0113 }
0114 periods_elapsed /= period_bytes;
0115
0116
0117 chip->playback_ptr %= buffer_bytes;
0118
0119 if (periods_elapsed) {
0120 chip->period_ptr += periods_elapsed * period_bytes;
0121 chip->period_ptr %= buffer_bytes;
0122 queue_work(system_highpri_wq, &pcsp_pcm_work);
0123 }
0124 spin_unlock_irqrestore(&chip->substream_lock, flags);
0125 }
0126
0127 enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
0128 {
0129 struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer);
0130 int pointer_update;
0131 u64 ns;
0132
0133 if (!atomic_read(&chip->timer_active) || !chip->playback_substream)
0134 return HRTIMER_NORESTART;
0135
0136 pointer_update = !chip->thalf;
0137 ns = pcsp_timer_update(chip);
0138 if (!ns) {
0139 printk(KERN_WARNING "PCSP: unexpected stop\n");
0140 return HRTIMER_NORESTART;
0141 }
0142
0143 if (pointer_update)
0144 pcsp_pointer_update(chip);
0145
0146 hrtimer_forward_now(handle, ns_to_ktime(ns));
0147
0148 return HRTIMER_RESTART;
0149 }
0150
0151 static int pcsp_start_playing(struct snd_pcsp *chip)
0152 {
0153 #if PCSP_DEBUG
0154 printk(KERN_INFO "PCSP: start_playing called\n");
0155 #endif
0156 if (atomic_read(&chip->timer_active)) {
0157 printk(KERN_ERR "PCSP: Timer already active\n");
0158 return -EIO;
0159 }
0160
0161 raw_spin_lock(&i8253_lock);
0162 chip->val61 = inb(0x61) | 0x03;
0163 outb_p(0x92, 0x43);
0164 raw_spin_unlock(&i8253_lock);
0165 atomic_set(&chip->timer_active, 1);
0166 chip->thalf = 0;
0167
0168 hrtimer_start(&pcsp_chip.timer, 0, HRTIMER_MODE_REL);
0169 return 0;
0170 }
0171
0172 static void pcsp_stop_playing(struct snd_pcsp *chip)
0173 {
0174 #if PCSP_DEBUG
0175 printk(KERN_INFO "PCSP: stop_playing called\n");
0176 #endif
0177 if (!atomic_read(&chip->timer_active))
0178 return;
0179
0180 atomic_set(&chip->timer_active, 0);
0181 raw_spin_lock(&i8253_lock);
0182
0183 outb_p(0xb6, 0x43);
0184 outb(chip->val61 & 0xFC, 0x61);
0185 raw_spin_unlock(&i8253_lock);
0186 }
0187
0188
0189
0190
0191 void pcsp_sync_stop(struct snd_pcsp *chip)
0192 {
0193 local_irq_disable();
0194 pcsp_stop_playing(chip);
0195 local_irq_enable();
0196 hrtimer_cancel(&chip->timer);
0197 cancel_work_sync(&pcsp_pcm_work);
0198 }
0199
0200 static int snd_pcsp_playback_close(struct snd_pcm_substream *substream)
0201 {
0202 struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
0203 #if PCSP_DEBUG
0204 printk(KERN_INFO "PCSP: close called\n");
0205 #endif
0206 pcsp_sync_stop(chip);
0207 chip->playback_substream = NULL;
0208 return 0;
0209 }
0210
0211 static int snd_pcsp_playback_hw_params(struct snd_pcm_substream *substream,
0212 struct snd_pcm_hw_params *hw_params)
0213 {
0214 struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
0215 pcsp_sync_stop(chip);
0216 return 0;
0217 }
0218
0219 static int snd_pcsp_playback_hw_free(struct snd_pcm_substream *substream)
0220 {
0221 struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
0222 #if PCSP_DEBUG
0223 printk(KERN_INFO "PCSP: hw_free called\n");
0224 #endif
0225 pcsp_sync_stop(chip);
0226 return 0;
0227 }
0228
0229 static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream)
0230 {
0231 struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
0232 pcsp_sync_stop(chip);
0233 chip->playback_ptr = 0;
0234 chip->period_ptr = 0;
0235 chip->fmt_size =
0236 snd_pcm_format_physical_width(substream->runtime->format) >> 3;
0237 chip->is_signed = snd_pcm_format_signed(substream->runtime->format);
0238 #if PCSP_DEBUG
0239 printk(KERN_INFO "PCSP: prepare called, "
0240 "size=%zi psize=%zi f=%zi f1=%i fsize=%i\n",
0241 snd_pcm_lib_buffer_bytes(substream),
0242 snd_pcm_lib_period_bytes(substream),
0243 snd_pcm_lib_buffer_bytes(substream) /
0244 snd_pcm_lib_period_bytes(substream),
0245 substream->runtime->periods,
0246 chip->fmt_size);
0247 #endif
0248 return 0;
0249 }
0250
0251 static int snd_pcsp_trigger(struct snd_pcm_substream *substream, int cmd)
0252 {
0253 struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
0254 #if PCSP_DEBUG
0255 printk(KERN_INFO "PCSP: trigger called\n");
0256 #endif
0257 switch (cmd) {
0258 case SNDRV_PCM_TRIGGER_START:
0259 case SNDRV_PCM_TRIGGER_RESUME:
0260 return pcsp_start_playing(chip);
0261 case SNDRV_PCM_TRIGGER_STOP:
0262 case SNDRV_PCM_TRIGGER_SUSPEND:
0263 pcsp_stop_playing(chip);
0264 break;
0265 default:
0266 return -EINVAL;
0267 }
0268 return 0;
0269 }
0270
0271 static snd_pcm_uframes_t snd_pcsp_playback_pointer(struct snd_pcm_substream
0272 *substream)
0273 {
0274 struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
0275 unsigned int pos;
0276 spin_lock(&chip->substream_lock);
0277 pos = chip->playback_ptr;
0278 spin_unlock(&chip->substream_lock);
0279 return bytes_to_frames(substream->runtime, pos);
0280 }
0281
0282 static const struct snd_pcm_hardware snd_pcsp_playback = {
0283 .info = (SNDRV_PCM_INFO_INTERLEAVED |
0284 SNDRV_PCM_INFO_HALF_DUPLEX |
0285 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
0286 .formats = (SNDRV_PCM_FMTBIT_U8
0287 #if DMIX_WANTS_S16
0288 | SNDRV_PCM_FMTBIT_S16_LE
0289 #endif
0290 ),
0291 .rates = SNDRV_PCM_RATE_KNOT,
0292 .rate_min = PCSP_DEFAULT_SRATE,
0293 .rate_max = PCSP_DEFAULT_SRATE,
0294 .channels_min = 1,
0295 .channels_max = 1,
0296 .buffer_bytes_max = PCSP_BUFFER_SIZE,
0297 .period_bytes_min = 64,
0298 .period_bytes_max = PCSP_MAX_PERIOD_SIZE,
0299 .periods_min = 2,
0300 .periods_max = PCSP_MAX_PERIODS,
0301 .fifo_size = 0,
0302 };
0303
0304 static int snd_pcsp_playback_open(struct snd_pcm_substream *substream)
0305 {
0306 struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
0307 struct snd_pcm_runtime *runtime = substream->runtime;
0308 #if PCSP_DEBUG
0309 printk(KERN_INFO "PCSP: open called\n");
0310 #endif
0311 if (atomic_read(&chip->timer_active)) {
0312 printk(KERN_ERR "PCSP: still active!!\n");
0313 return -EBUSY;
0314 }
0315 runtime->hw = snd_pcsp_playback;
0316 chip->playback_substream = substream;
0317 return 0;
0318 }
0319
0320 static const struct snd_pcm_ops snd_pcsp_playback_ops = {
0321 .open = snd_pcsp_playback_open,
0322 .close = snd_pcsp_playback_close,
0323 .hw_params = snd_pcsp_playback_hw_params,
0324 .hw_free = snd_pcsp_playback_hw_free,
0325 .prepare = snd_pcsp_playback_prepare,
0326 .trigger = snd_pcsp_trigger,
0327 .pointer = snd_pcsp_playback_pointer,
0328 };
0329
0330 int snd_pcsp_new_pcm(struct snd_pcsp *chip)
0331 {
0332 int err;
0333
0334 err = snd_pcm_new(chip->card, "pcspeaker", 0, 1, 0, &chip->pcm);
0335 if (err < 0)
0336 return err;
0337
0338 snd_pcm_set_ops(chip->pcm, SNDRV_PCM_STREAM_PLAYBACK,
0339 &snd_pcsp_playback_ops);
0340
0341 chip->pcm->private_data = chip;
0342 chip->pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
0343 strcpy(chip->pcm->name, "pcsp");
0344
0345 snd_pcm_set_managed_buffer_all(chip->pcm,
0346 SNDRV_DMA_TYPE_CONTINUOUS,
0347 NULL,
0348 PCSP_BUFFER_SIZE,
0349 PCSP_BUFFER_SIZE);
0350
0351 return 0;
0352 }