FILE
harmony.c
File preview with syntax highlighting.
linux-6.19.14/sound/parisc/harmony.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* Hewlett-Packard Harmony audio driver 3 * 4 * This is a driver for the Harmony audio chipset found 5 * on the LASI ASIC of various early HP PA-RISC workstations. 6 * 7 * Copyright (C) 2004, Kyle McMartin <kyle@{debian.org,parisc-linux.org}> 8 * 9 * Based on the previous Harmony incarnations by, 10 * Copyright 2000 (c) Linuxcare Canada, Alex deVries 11 * Copyright 2000-2003 (c) Helge Deller 12 * Copyright 2001 (c) Matthieu Delahaye 13 * Copyright 2001 (c) Jean-Christophe Vaugeois 14 * Copyright 2003 (c) Laurent Canet 15 * Copyright 2004 (c) Stuart Brady 16 * 17 * Notes: 18 * - graveyard and silence buffers last for lifetime of 19 * the driver. playback and capture buffers are allocated 20 * per _open()/_close(). 21 * 22 * TODO: 23 */ 24 25#include <linux/init.h> 26#include <linux/slab.h> 27#include <linux/time.h> 28#include <linux/wait.h> 29#include <linux/delay.h> 30#include <linux/module.h> 31#include <linux/interrupt.h> 32#include <linux/spinlock.h> 33#include <linux/dma-mapping.h> 34#include <linux/io.h> 35 36#include <sound/core.h> 37#include <sound/pcm.h> 38#include <sound/control.h> 39#include <sound/rawmidi.h> 40#include <sound/initval.h> 41#include <sound/info.h> 42 43#include <asm/hardware.h> 44#include <asm/parisc-device.h> 45 46#include "harmony.h" 47 48static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ 49static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ 50module_param(index, int, 0444); 51MODULE_PARM_DESC(index, "Index value for Harmony driver."); 52module_param(id, charp, 0444); 53MODULE_PARM_DESC(id, "ID string for Harmony driver."); 54 55 56static const struct parisc_device_id snd_harmony_devtable[] __initconst = { 57 /* bushmaster / flounder */ 58 { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007A }, 59 /* 712 / 715 */ 60 { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007B }, 61 /* pace */ 62 { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007E }, 63 /* outfield / coral II */ 64 { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007F }, 65 { 0, } 66}; 67 68MODULE_DEVICE_TABLE(parisc, snd_harmony_devtable); 69 70#define NAME "harmony" 71#define PFX NAME ": " 72 73static const unsigned int snd_harmony_rates[] = { 74 5512, 6615, 8000, 9600, 75 11025, 16000, 18900, 22050, 76 27428, 32000, 33075, 37800, 77 44100, 48000 78}; 79 80static const unsigned int rate_bits[14] = { 81 HARMONY_SR_5KHZ, HARMONY_SR_6KHZ, HARMONY_SR_8KHZ, 82 HARMONY_SR_9KHZ, HARMONY_SR_11KHZ, HARMONY_SR_16KHZ, 83 HARMONY_SR_18KHZ, HARMONY_SR_22KHZ, HARMONY_SR_27KHZ, 84 HARMONY_SR_32KHZ, HARMONY_SR_33KHZ, HARMONY_SR_37KHZ, 85 HARMONY_SR_44KHZ, HARMONY_SR_48KHZ 86}; 87 88static const struct snd_pcm_hw_constraint_list hw_constraint_rates = { 89 .count = ARRAY_SIZE(snd_harmony_rates), 90 .list = snd_harmony_rates, 91 .mask = 0, 92}; 93 94static inline unsigned long 95harmony_read(struct snd_harmony *h, unsigned r) 96{ 97 return __raw_readl(h->iobase + r); 98} 99 100static inline void 101harmony_write(struct snd_harmony *h, unsigned r, unsigned long v) 102{ 103 __raw_writel(v, h->iobase + r); 104} 105 106static inline void 107harmony_wait_for_control(struct snd_harmony *h) 108{ 109 while (harmony_read(h, HARMONY_CNTL) & HARMONY_CNTL_C) ; 110} 111 112static inline void 113harmony_reset(struct snd_harmony *h) 114{ 115 harmony_write(h, HARMONY_RESET, 1); 116 mdelay(50); 117 harmony_write(h, HARMONY_RESET, 0); 118} 119 120static void 121harmony_disable_interrupts(struct snd_harmony *h) 122{ 123 u32 dstatus; 124 harmony_wait_for_control(h); 125 dstatus = harmony_read(h, HARMONY_DSTATUS); 126 dstatus &= ~HARMONY_DSTATUS_IE; 127 harmony_write(h, HARMONY_DSTATUS, dstatus); 128} 129 130static void 131harmony_enable_interrupts(struct snd_harmony *h) 132{ 133 u32 dstatus; 134 harmony_wait_for_control(h); 135 dstatus = harmony_read(h, HARMONY_DSTATUS); 136 dstatus |= HARMONY_DSTATUS_IE; 137 harmony_write(h, HARMONY_DSTATUS, dstatus); 138} 139 140static void 141harmony_mute(struct snd_harmony *h) 142{ 143 guard(spinlock_irqsave)(&h->mixer_lock); 144 harmony_wait_for_control(h); 145 harmony_write(h, HARMONY_GAINCTL, HARMONY_GAIN_SILENCE); 146} 147 148static void 149harmony_unmute(struct snd_harmony *h) 150{ 151 guard(spinlock_irqsave)(&h->mixer_lock); 152 harmony_wait_for_control(h); 153 harmony_write(h, HARMONY_GAINCTL, h->st.gain); 154} 155 156static void 157harmony_set_control(struct snd_harmony *h) 158{ 159 u32 ctrl; 160 161 guard(spinlock_irqsave)(&h->lock); 162 163 ctrl = (HARMONY_CNTL_C | 164 (h->st.format << 6) | 165 (h->st.stereo << 5) | 166 (h->st.rate)); 167 168 harmony_wait_for_control(h); 169 harmony_write(h, HARMONY_CNTL, ctrl); 170} 171 172static irqreturn_t 173snd_harmony_interrupt(int irq, void *dev) 174{ 175 u32 dstatus; 176 struct snd_harmony *h = dev; 177 178 scoped_guard(spinlock, &h->lock) { 179 harmony_disable_interrupts(h); 180 harmony_wait_for_control(h); 181 dstatus = harmony_read(h, HARMONY_DSTATUS); 182 } 183 184 if (dstatus & HARMONY_DSTATUS_PN) { 185 if (h->psubs && h->st.playing) { 186 scoped_guard(spinlock, &h->lock) { 187 h->pbuf.buf += h->pbuf.count; /* PAGE_SIZE */ 188 h->pbuf.buf %= h->pbuf.size; /* MAX_BUFS*PAGE_SIZE */ 189 190 harmony_write(h, HARMONY_PNXTADD, 191 h->pbuf.addr + h->pbuf.buf); 192 h->stats.play_intr++; 193 } 194 snd_pcm_period_elapsed(h->psubs); 195 } else { 196 scoped_guard(spinlock, &h->lock) { 197 harmony_write(h, HARMONY_PNXTADD, h->sdma.addr); 198 h->stats.silence_intr++; 199 } 200 } 201 } 202 203 if (dstatus & HARMONY_DSTATUS_RN) { 204 if (h->csubs && h->st.capturing) { 205 scoped_guard(spinlock, &h->lock) { 206 h->cbuf.buf += h->cbuf.count; 207 h->cbuf.buf %= h->cbuf.size; 208 209 harmony_write(h, HARMONY_RNXTADD, 210 h->cbuf.addr + h->cbuf.buf); 211 h->stats.rec_intr++; 212 } 213 snd_pcm_period_elapsed(h->csubs); 214 } else { 215 scoped_guard(spinlock, &h->lock) { 216 harmony_write(h, HARMONY_RNXTADD, h->gdma.addr); 217 h->stats.graveyard_intr++; 218 } 219 } 220 } 221 222 scoped_guard(spinlock, &h->lock) { 223 harmony_enable_interrupts(h); 224 } 225 226 return IRQ_HANDLED; 227} 228 229static unsigned int 230snd_harmony_rate_bits(int rate) 231{ 232 unsigned int i; 233 234 for (i = 0; i < ARRAY_SIZE(snd_harmony_rates); i++) 235 if (snd_harmony_rates[i] == rate) 236 return rate_bits[i]; 237 238 return HARMONY_SR_44KHZ; 239} 240 241static const struct snd_pcm_hardware snd_harmony_playback = 242{ 243 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 244 SNDRV_PCM_INFO_JOINT_DUPLEX | SNDRV_PCM_INFO_MMAP_VALID | 245 SNDRV_PCM_INFO_BLOCK_TRANSFER), 246 .formats = (SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_MU_LAW | 247 SNDRV_PCM_FMTBIT_A_LAW), 248 .rates = (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000 | 249 SNDRV_PCM_RATE_KNOT), 250 .rate_min = 5512, 251 .rate_max = 48000, 252 .channels_min = 1, 253 .channels_max = 2, 254 .buffer_bytes_max = MAX_BUF_SIZE, 255 .period_bytes_min = BUF_SIZE, 256 .period_bytes_max = BUF_SIZE, 257 .periods_min = 1, 258 .periods_max = MAX_BUFS, 259 .fifo_size = 0, 260}; 261 262static const struct snd_pcm_hardware snd_harmony_capture = 263{ 264 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 265 SNDRV_PCM_INFO_JOINT_DUPLEX | SNDRV_PCM_INFO_MMAP_VALID | 266 SNDRV_PCM_INFO_BLOCK_TRANSFER), 267 .formats = (SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_MU_LAW | 268 SNDRV_PCM_FMTBIT_A_LAW), 269 .rates = (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000 | 270 SNDRV_PCM_RATE_KNOT), 271 .rate_min = 5512, 272 .rate_max = 48000, 273 .channels_min = 1, 274 .channels_max = 2, 275 .buffer_bytes_max = MAX_BUF_SIZE, 276 .period_bytes_min = BUF_SIZE, 277 .period_bytes_max = BUF_SIZE, 278 .periods_min = 1, 279 .periods_max = MAX_BUFS, 280 .fifo_size = 0, 281}; 282 283static int 284snd_harmony_playback_trigger(struct snd_pcm_substream *ss, int cmd) 285{ 286 struct snd_harmony *h = snd_pcm_substream_chip(ss); 287 288 if (h->st.capturing) 289 return -EBUSY; 290 291 guard(spinlock)(&h->lock); 292 switch (cmd) { 293 case SNDRV_PCM_TRIGGER_START: 294 h->st.playing = 1; 295 harmony_write(h, HARMONY_PNXTADD, h->pbuf.addr); 296 harmony_write(h, HARMONY_RNXTADD, h->gdma.addr); 297 harmony_unmute(h); 298 harmony_enable_interrupts(h); 299 break; 300 case SNDRV_PCM_TRIGGER_STOP: 301 h->st.playing = 0; 302 harmony_mute(h); 303 harmony_write(h, HARMONY_PNXTADD, h->sdma.addr); 304 harmony_disable_interrupts(h); 305 break; 306 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 307 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 308 case SNDRV_PCM_TRIGGER_SUSPEND: 309 default: 310 snd_BUG(); 311 return -EINVAL; 312 } 313 314 return 0; 315} 316 317static int 318snd_harmony_capture_trigger(struct snd_pcm_substream *ss, int cmd) 319{ 320 struct snd_harmony *h = snd_pcm_substream_chip(ss); 321 322 if (h->st.playing) 323 return -EBUSY; 324 325 guard(spinlock)(&h->lock); 326 switch (cmd) { 327 case SNDRV_PCM_TRIGGER_START: 328 h->st.capturing = 1; 329 harmony_write(h, HARMONY_PNXTADD, h->sdma.addr); 330 harmony_write(h, HARMONY_RNXTADD, h->cbuf.addr); 331 harmony_unmute(h); 332 harmony_enable_interrupts(h); 333 break; 334 case SNDRV_PCM_TRIGGER_STOP: 335 h->st.capturing = 0; 336 harmony_mute(h); 337 harmony_write(h, HARMONY_RNXTADD, h->gdma.addr); 338 harmony_disable_interrupts(h); 339 break; 340 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 341 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 342 case SNDRV_PCM_TRIGGER_SUSPEND: 343 default: 344 snd_BUG(); 345 return -EINVAL; 346 } 347 348 return 0; 349} 350 351static int 352snd_harmony_set_data_format(struct snd_harmony *h, int fmt, int force) 353{ 354 int o = h->st.format; 355 int n; 356 357 switch(fmt) { 358 case SNDRV_PCM_FORMAT_S16_BE: 359 n = HARMONY_DF_16BIT_LINEAR; 360 break; 361 case SNDRV_PCM_FORMAT_A_LAW: 362 n = HARMONY_DF_8BIT_ALAW; 363 break; 364 case SNDRV_PCM_FORMAT_MU_LAW: 365 n = HARMONY_DF_8BIT_ULAW; 366 break; 367 default: 368 n = HARMONY_DF_16BIT_LINEAR; 369 break; 370 } 371 372 if (force || o != n) { 373 snd_pcm_format_set_silence(fmt, h->sdma.area, SILENCE_BUFSZ / 374 (snd_pcm_format_physical_width(fmt) 375 / 8)); 376 } 377 378 return n; 379} 380 381static int 382snd_harmony_playback_prepare(struct snd_pcm_substream *ss) 383{ 384 struct snd_harmony *h = snd_pcm_substream_chip(ss); 385 struct snd_pcm_runtime *rt = ss->runtime; 386 387 if (h->st.capturing) 388 return -EBUSY; 389 390 h->pbuf.size = snd_pcm_lib_buffer_bytes(ss); 391 h->pbuf.count = snd_pcm_lib_period_bytes(ss); 392 if (h->pbuf.buf >= h->pbuf.size) 393 h->pbuf.buf = 0; 394 h->st.playing = 0; 395 396 h->st.rate = snd_harmony_rate_bits(rt->rate); 397 h->st.format = snd_harmony_set_data_format(h, rt->format, 0); 398 399 if (rt->channels == 2) 400 h->st.stereo = HARMONY_SS_STEREO; 401 else 402 h->st.stereo = HARMONY_SS_MONO; 403 404 harmony_set_control(h); 405 406 h->pbuf.addr = rt->dma_addr; 407 408 return 0; 409} 410 411static int 412snd_harmony_capture_prepare(struct snd_pcm_substream *ss) 413{ 414 struct snd_harmony *h = snd_pcm_substream_chip(ss); 415 struct snd_pcm_runtime *rt = ss->runtime; 416 417 if (h->st.playing) 418 return -EBUSY; 419 420 h->cbuf.size = snd_pcm_lib_buffer_bytes(ss); 421 h->cbuf.count = snd_pcm_lib_period_bytes(ss); 422 if (h->cbuf.buf >= h->cbuf.size) 423 h->cbuf.buf = 0; 424 h->st.capturing = 0; 425 426 h->st.rate = snd_harmony_rate_bits(rt->rate); 427 h->st.format = snd_harmony_set_data_format(h, rt->format, 0); 428 429 if (rt->channels == 2) 430 h->st.stereo = HARMONY_SS_STEREO; 431 else 432 h->st.stereo = HARMONY_SS_MONO; 433 434 harmony_set_control(h); 435 436 h->cbuf.addr = rt->dma_addr; 437 438 return 0; 439} 440 441static snd_pcm_uframes_t 442snd_harmony_playback_pointer(struct snd_pcm_substream *ss) 443{ 444 struct snd_pcm_runtime *rt = ss->runtime; 445 struct snd_harmony *h = snd_pcm_substream_chip(ss); 446 unsigned long pcuradd; 447 unsigned long played; 448 449 if (!(h->st.playing) || (h->psubs == NULL)) 450 return 0; 451 452 if ((h->pbuf.addr == 0) || (h->pbuf.size == 0)) 453 return 0; 454 455 pcuradd = harmony_read(h, HARMONY_PCURADD); 456 played = pcuradd - h->pbuf.addr; 457 458#ifdef HARMONY_DEBUG 459 printk(KERN_DEBUG PFX "playback_pointer is 0x%lx-0x%lx = %d bytes\n", 460 pcuradd, h->pbuf.addr, played); 461#endif 462 463 if (pcuradd > h->pbuf.addr + h->pbuf.size) { 464 return 0; 465 } 466 467 return bytes_to_frames(rt, played); 468} 469 470static snd_pcm_uframes_t 471snd_harmony_capture_pointer(struct snd_pcm_substream *ss) 472{ 473 struct snd_pcm_runtime *rt = ss->runtime; 474 struct snd_harmony *h = snd_pcm_substream_chip(ss); 475 unsigned long rcuradd; 476 unsigned long caught; 477 478 if (!(h->st.capturing) || (h->csubs == NULL)) 479 return 0; 480 481 if ((h->cbuf.addr == 0) || (h->cbuf.size == 0)) 482 return 0; 483 484 rcuradd = harmony_read(h, HARMONY_RCURADD); 485 caught = rcuradd - h->cbuf.addr; 486 487#ifdef HARMONY_DEBUG 488 printk(KERN_DEBUG PFX "capture_pointer is 0x%lx-0x%lx = %d bytes\n", 489 rcuradd, h->cbuf.addr, caught); 490#endif 491 492 if (rcuradd > h->cbuf.addr + h->cbuf.size) { 493 return 0; 494 } 495 496 return bytes_to_frames(rt, caught); 497} 498 499static int 500snd_harmony_playback_open(struct snd_pcm_substream *ss) 501{ 502 struct snd_harmony *h = snd_pcm_substream_chip(ss); 503 struct snd_pcm_runtime *rt = ss->runtime; 504 int err; 505 506 h->psubs = ss; 507 rt->hw = snd_harmony_playback; 508 snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE, 509 &hw_constraint_rates); 510 511 err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS); 512 if (err < 0) 513 return err; 514 515 return 0; 516} 517 518static int 519snd_harmony_capture_open(struct snd_pcm_substream *ss) 520{ 521 struct snd_harmony *h = snd_pcm_substream_chip(ss); 522 struct snd_pcm_runtime *rt = ss->runtime; 523 int err; 524 525 h->csubs = ss; 526 rt->hw = snd_harmony_capture; 527 snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE, 528 &hw_constraint_rates); 529 530 err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS); 531 if (err < 0) 532 return err; 533 534 return 0; 535} 536 537static int 538snd_harmony_playback_close(struct snd_pcm_substream *ss) 539{ 540 struct snd_harmony *h = snd_pcm_substream_chip(ss); 541 h->psubs = NULL; 542 return 0; 543} 544 545static int 546snd_harmony_capture_close(struct snd_pcm_substream *ss) 547{ 548 struct snd_harmony *h = snd_pcm_substream_chip(ss); 549 h->csubs = NULL; 550 return 0; 551} 552 553static const struct snd_pcm_ops snd_harmony_playback_ops = { 554 .open = snd_harmony_playback_open, 555 .close = snd_harmony_playback_close, 556 .prepare = snd_harmony_playback_prepare, 557 .trigger = snd_harmony_playback_trigger, 558 .pointer = snd_harmony_playback_pointer, 559}; 560 561static const struct snd_pcm_ops snd_harmony_capture_ops = { 562 .open = snd_harmony_capture_open, 563 .close = snd_harmony_capture_close, 564 .prepare = snd_harmony_capture_prepare, 565 .trigger = snd_harmony_capture_trigger, 566 .pointer = snd_harmony_capture_pointer, 567}; 568 569static int 570snd_harmony_pcm_init(struct snd_harmony *h) 571{ 572 struct snd_pcm *pcm; 573 int err; 574 575 if (snd_BUG_ON(!h)) 576 return -EINVAL; 577 578 harmony_disable_interrupts(h); 579 580 err = snd_pcm_new(h->card, "harmony", 0, 1, 1, &pcm); 581 if (err < 0) 582 return err; 583 584 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 585 &snd_harmony_playback_ops); 586 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 587 &snd_harmony_capture_ops); 588 589 pcm->private_data = h; 590 pcm->info_flags = 0; 591 strscpy(pcm->name, "harmony"); 592 h->pcm = pcm; 593 594 h->psubs = NULL; 595 h->csubs = NULL; 596 597 /* initialize graveyard buffer */ 598 h->dma.type = SNDRV_DMA_TYPE_DEV; 599 h->dma.dev = &h->dev->dev; 600 err = snd_dma_alloc_pages(h->dma.type, 601 h->dma.dev, 602 BUF_SIZE*GRAVEYARD_BUFS, 603 &h->gdma); 604 if (err < 0) { 605 printk(KERN_ERR PFX "cannot allocate graveyard buffer!\n"); 606 return err; 607 } 608 609 /* initialize silence buffers */ 610 err = snd_dma_alloc_pages(h->dma.type, 611 h->dma.dev, 612 BUF_SIZE*SILENCE_BUFS, 613 &h->sdma); 614 if (err < 0) { 615 printk(KERN_ERR PFX "cannot allocate silence buffer!\n"); 616 return err; 617 } 618 619 /* pre-allocate space for DMA */ 620 snd_pcm_set_managed_buffer_all(pcm, h->dma.type, h->dma.dev, 621 MAX_BUF_SIZE, MAX_BUF_SIZE); 622 623 h->st.format = snd_harmony_set_data_format(h, 624 SNDRV_PCM_FORMAT_S16_BE, 1); 625 626 return 0; 627} 628 629static void 630snd_harmony_set_new_gain(struct snd_harmony *h) 631{ 632 harmony_wait_for_control(h); 633 harmony_write(h, HARMONY_GAINCTL, h->st.gain); 634} 635 636static int 637snd_harmony_mixercontrol_info(struct snd_kcontrol *kc, 638 struct snd_ctl_elem_info *uinfo) 639{ 640 int mask = (kc->private_value >> 16) & 0xff; 641 int left_shift = (kc->private_value) & 0xff; 642 int right_shift = (kc->private_value >> 8) & 0xff; 643 644 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : 645 SNDRV_CTL_ELEM_TYPE_INTEGER; 646 uinfo->count = left_shift == right_shift ? 1 : 2; 647 uinfo->value.integer.min = 0; 648 uinfo->value.integer.max = mask; 649 650 return 0; 651} 652 653static int 654snd_harmony_volume_get(struct snd_kcontrol *kc, 655 struct snd_ctl_elem_value *ucontrol) 656{ 657 struct snd_harmony *h = snd_kcontrol_chip(kc); 658 int shift_left = (kc->private_value) & 0xff; 659 int shift_right = (kc->private_value >> 8) & 0xff; 660 int mask = (kc->private_value >> 16) & 0xff; 661 int invert = (kc->private_value >> 24) & 0xff; 662 int left, right; 663 664 guard(spinlock_irq)(&h->mixer_lock); 665 666 left = (h->st.gain >> shift_left) & mask; 667 right = (h->st.gain >> shift_right) & mask; 668 if (invert) { 669 left = mask - left; 670 right = mask - right; 671 } 672 673 ucontrol->value.integer.value[0] = left; 674 if (shift_left != shift_right) 675 ucontrol->value.integer.value[1] = right; 676 677 return 0; 678} 679 680static int 681snd_harmony_volume_put(struct snd_kcontrol *kc, 682 struct snd_ctl_elem_value *ucontrol) 683{ 684 struct snd_harmony *h = snd_kcontrol_chip(kc); 685 int shift_left = (kc->private_value) & 0xff; 686 int shift_right = (kc->private_value >> 8) & 0xff; 687 int mask = (kc->private_value >> 16) & 0xff; 688 int invert = (kc->private_value >> 24) & 0xff; 689 int left, right; 690 int old_gain = h->st.gain; 691 692 guard(spinlock_irq)(&h->mixer_lock); 693 694 left = ucontrol->value.integer.value[0] & mask; 695 if (invert) 696 left = mask - left; 697 h->st.gain &= ~( (mask << shift_left ) ); 698 h->st.gain |= (left << shift_left); 699 700 if (shift_left != shift_right) { 701 right = ucontrol->value.integer.value[1] & mask; 702 if (invert) 703 right = mask - right; 704 h->st.gain &= ~( (mask << shift_right) ); 705 h->st.gain |= (right << shift_right); 706 } 707 708 snd_harmony_set_new_gain(h); 709 710 return h->st.gain != old_gain; 711} 712 713static int 714snd_harmony_captureroute_info(struct snd_kcontrol *kc, 715 struct snd_ctl_elem_info *uinfo) 716{ 717 static const char * const texts[2] = { "Line", "Mic" }; 718 719 return snd_ctl_enum_info(uinfo, 1, 2, texts); 720} 721 722static int 723snd_harmony_captureroute_get(struct snd_kcontrol *kc, 724 struct snd_ctl_elem_value *ucontrol) 725{ 726 struct snd_harmony *h = snd_kcontrol_chip(kc); 727 int value; 728 729 guard(spinlock_irq)(&h->mixer_lock); 730 731 value = (h->st.gain >> HARMONY_GAIN_IS_SHIFT) & 1; 732 ucontrol->value.enumerated.item[0] = value; 733 734 return 0; 735} 736 737static int 738snd_harmony_captureroute_put(struct snd_kcontrol *kc, 739 struct snd_ctl_elem_value *ucontrol) 740{ 741 struct snd_harmony *h = snd_kcontrol_chip(kc); 742 int value; 743 int old_gain = h->st.gain; 744 745 guard(spinlock_irq)(&h->mixer_lock); 746 747 value = ucontrol->value.enumerated.item[0] & 1; 748 h->st.gain &= ~HARMONY_GAIN_IS_MASK; 749 h->st.gain |= value << HARMONY_GAIN_IS_SHIFT; 750 751 snd_harmony_set_new_gain(h); 752 753 return h->st.gain != old_gain; 754} 755 756#define HARMONY_CONTROLS ARRAY_SIZE(snd_harmony_controls) 757 758#define HARMONY_VOLUME(xname, left_shift, right_shift, mask, invert) \ 759{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 760 .info = snd_harmony_mixercontrol_info, \ 761 .get = snd_harmony_volume_get, .put = snd_harmony_volume_put, \ 762 .private_value = ((left_shift) | ((right_shift) << 8) | \ 763 ((mask) << 16) | ((invert) << 24)) } 764 765static const struct snd_kcontrol_new snd_harmony_controls[] = { 766 HARMONY_VOLUME("Master Playback Volume", HARMONY_GAIN_LO_SHIFT, 767 HARMONY_GAIN_RO_SHIFT, HARMONY_GAIN_OUT, 1), 768 HARMONY_VOLUME("Capture Volume", HARMONY_GAIN_LI_SHIFT, 769 HARMONY_GAIN_RI_SHIFT, HARMONY_GAIN_IN, 0), 770 HARMONY_VOLUME("Monitor Volume", HARMONY_GAIN_MA_SHIFT, 771 HARMONY_GAIN_MA_SHIFT, HARMONY_GAIN_MA, 1), 772 { 773 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 774 .name = "Input Route", 775 .info = snd_harmony_captureroute_info, 776 .get = snd_harmony_captureroute_get, 777 .put = snd_harmony_captureroute_put 778 }, 779 HARMONY_VOLUME("Internal Speaker Switch", HARMONY_GAIN_SE_SHIFT, 780 HARMONY_GAIN_SE_SHIFT, 1, 0), 781 HARMONY_VOLUME("Line-Out Switch", HARMONY_GAIN_LE_SHIFT, 782 HARMONY_GAIN_LE_SHIFT, 1, 0), 783 HARMONY_VOLUME("Headphones Switch", HARMONY_GAIN_HE_SHIFT, 784 HARMONY_GAIN_HE_SHIFT, 1, 0), 785}; 786 787static void 788snd_harmony_mixer_reset(struct snd_harmony *h) 789{ 790 harmony_mute(h); 791 harmony_reset(h); 792 h->st.gain = HARMONY_GAIN_DEFAULT; 793 harmony_unmute(h); 794} 795 796static int 797snd_harmony_mixer_init(struct snd_harmony *h) 798{ 799 struct snd_card *card; 800 int idx, err; 801 802 if (snd_BUG_ON(!h)) 803 return -EINVAL; 804 card = h->card; 805 strscpy(card->mixername, "Harmony Gain control interface"); 806 807 for (idx = 0; idx < HARMONY_CONTROLS; idx++) { 808 err = snd_ctl_add(card, 809 snd_ctl_new1(&snd_harmony_controls[idx], h)); 810 if (err < 0) 811 return err; 812 } 813 814 snd_harmony_mixer_reset(h); 815 816 return 0; 817} 818 819static int 820snd_harmony_free(struct snd_harmony *h) 821{ 822 if (h->gdma.addr) 823 snd_dma_free_pages(&h->gdma); 824 if (h->sdma.addr) 825 snd_dma_free_pages(&h->sdma); 826 827 if (h->irq >= 0) 828 free_irq(h->irq, h); 829 830 iounmap(h->iobase); 831 kfree(h); 832 return 0; 833} 834 835static int 836snd_harmony_dev_free(struct snd_device *dev) 837{ 838 struct snd_harmony *h = dev->device_data; 839 return snd_harmony_free(h); 840} 841 842static int 843snd_harmony_create(struct snd_card *card, 844 struct parisc_device *padev, 845 struct snd_harmony **rchip) 846{ 847 int err; 848 struct snd_harmony *h; 849 static const struct snd_device_ops ops = { 850 .dev_free = snd_harmony_dev_free, 851 }; 852 853 *rchip = NULL; 854 855 h = kzalloc(sizeof(*h), GFP_KERNEL); 856 if (h == NULL) 857 return -ENOMEM; 858 859 h->hpa = padev->hpa.start; 860 h->card = card; 861 h->dev = padev; 862 h->irq = -1; 863 h->iobase = ioremap(padev->hpa.start, HARMONY_SIZE); 864 if (h->iobase == NULL) { 865 printk(KERN_ERR PFX "unable to remap hpa 0x%lx\n", 866 (unsigned long)padev->hpa.start); 867 err = -EBUSY; 868 goto free_and_ret; 869 } 870 871 err = request_irq(padev->irq, snd_harmony_interrupt, 0, 872 "harmony", h); 873 if (err) { 874 printk(KERN_ERR PFX "could not obtain interrupt %d", 875 padev->irq); 876 goto free_and_ret; 877 } 878 h->irq = padev->irq; 879 880 spin_lock_init(&h->mixer_lock); 881 spin_lock_init(&h->lock); 882 883 err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, h, &ops); 884 if (err < 0) 885 goto free_and_ret; 886 887 *rchip = h; 888 889 return 0; 890 891free_and_ret: 892 snd_harmony_free(h); 893 return err; 894} 895 896static int __init 897snd_harmony_probe(struct parisc_device *padev) 898{ 899 int err; 900 struct snd_card *card; 901 struct snd_harmony *h; 902 903 err = snd_card_new(&padev->dev, index, id, THIS_MODULE, 0, &card); 904 if (err < 0) 905 return err; 906 907 err = snd_harmony_create(card, padev, &h); 908 if (err < 0) 909 goto free_and_ret; 910 911 err = snd_harmony_pcm_init(h); 912 if (err < 0) 913 goto free_and_ret; 914 915 err = snd_harmony_mixer_init(h); 916 if (err < 0) 917 goto free_and_ret; 918 919 strscpy(card->driver, "harmony"); 920 strscpy(card->shortname, "Harmony"); 921 sprintf(card->longname, "%s at 0x%lx, irq %i", 922 card->shortname, h->hpa, h->irq); 923 924 err = snd_card_register(card); 925 if (err < 0) 926 goto free_and_ret; 927 928 parisc_set_drvdata(padev, card); 929 return 0; 930 931free_and_ret: 932 snd_card_free(card); 933 return err; 934} 935 936static void __exit 937snd_harmony_remove(struct parisc_device *padev) 938{ 939 snd_card_free(parisc_get_drvdata(padev)); 940} 941 942static struct parisc_driver snd_harmony_driver __refdata = { 943 .name = "harmony", 944 .id_table = snd_harmony_devtable, 945 .probe = snd_harmony_probe, 946 .remove = __exit_p(snd_harmony_remove), 947}; 948 949static int __init 950alsa_harmony_init(void) 951{ 952 return register_parisc_driver(&snd_harmony_driver); 953} 954 955static void __exit 956alsa_harmony_fini(void) 957{ 958 unregister_parisc_driver(&snd_harmony_driver); 959} 960 961MODULE_LICENSE("GPL"); 962MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>"); 963MODULE_DESCRIPTION("Harmony sound driver"); 964 965module_init(alsa_harmony_init); 966module_exit(alsa_harmony_fini);
~/
Read-only file preview.