pcsp_lib.c 9.1 KB

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