📄 mixer.c
字号:
ret = -EFAULT; break; case CMD_GETCTLGPR: addr = emu10k1_find_control_gpr(&card->mgr, (char *) ctl->val, &((char *) ctl->val)[PATCH_NAME_SIZE]); ctl->val[0] = sblive_readptr(card, addr, 0); if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl))) ret = -EFAULT; break; case CMD_SETPATCH: if (ctl->val[0] == 0) memcpy(&card->mgr.rpatch, &ctl->val[1], sizeof(struct dsp_rpatch)); else { page = (ctl->val[0] - 1) / PATCHES_PER_PAGE; if (page > MAX_PATCHES_PAGES) { ret = -EINVAL; break; } if (page >= card->mgr.current_pages) { for (i = card->mgr.current_pages; i < page + 1; i++) { card->mgr.patch[i] = (void *)__get_free_page(GFP_KERNEL); if(card->mgr.patch[i] == NULL) { card->mgr.current_pages = i; ret = -ENOMEM; break; } memset(card->mgr.patch[i], 0, PAGE_SIZE); } card->mgr.current_pages = page + 1; } patch = PATCH(&card->mgr, ctl->val[0] - 1); memcpy(patch, &ctl->val[1], sizeof(struct dsp_patch)); if (patch->code_size == 0) { for(i = page + 1; i < card->mgr.current_pages; i++) free_page((unsigned long) card->mgr.patch[i]); card->mgr.current_pages = page + 1; } } break; case CMD_SETGPR: if (ctl->val[0] > NUM_GPRS) { ret = -EINVAL; break; } memcpy(&card->mgr.gpr[ctl->val[0]], &ctl->val[1], sizeof(struct dsp_gpr)); break; case CMD_SETCTLGPR: addr = emu10k1_find_control_gpr(&card->mgr, (char *) ctl->val, (char *) ctl->val + PATCH_NAME_SIZE); emu10k1_set_control_gpr(card, addr, *((s32 *)((char *) ctl->val + 2 * PATCH_NAME_SIZE)), 0); break; case CMD_SETGPOUT: if ( ((ctl->val[0] > 2) && (!card->is_audigy)) || (ctl->val[0] > 15) || ctl->val[1] > 1) { ret= -EINVAL; break; } if (card->is_audigy) emu10k1_writefn0(card, (1 << 24) | ((ctl->val[0]) << 16) | A_IOCFG, ctl->val[1]); else emu10k1_writefn0(card, (1 << 24) | (((ctl->val[0]) + 10) << 16) | HCFG, ctl->val[1]); break; case CMD_GETGPR2OSS: id = ctl->val[0]; ch = ctl->val[1]; if (id >= SOUND_MIXER_NRDEVICES || ch >= 2) { ret = -EINVAL; break; } ctl->val[2] = card->mgr.ctrl_gpr[id][ch]; if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl))) ret = -EFAULT; break; case CMD_SETGPR2OSS: id = ctl->val[0]; /* 0 == left, 1 == right */ ch = ctl->val[1]; addr = ctl->val[2]; if (id >= SOUND_MIXER_NRDEVICES || ch >= 2) { ret = -EINVAL; break; } card->mgr.ctrl_gpr[id][ch] = addr; if (card->is_aps) break; if (addr >= 0) { unsigned int state = card->ac97->mixer_state[id]; if (ch == 1) { state >>= 8; card->ac97->stereo_mixers |= (1 << id); } card->ac97->supported_mixers |= (1 << id); if (id == SOUND_MIXER_TREBLE) { set_treble(card, card->ac97->mixer_state[id] & 0xff, (card->ac97->mixer_state[id] >> 8) & 0xff); } else if (id == SOUND_MIXER_BASS) { set_bass(card, card->ac97->mixer_state[id] & 0xff, (card->ac97->mixer_state[id] >> 8) & 0xff); } else emu10k1_set_volume_gpr(card, addr, state & 0xff, volume_params[id]); } else { card->ac97->stereo_mixers &= ~(1 << id); card->ac97->stereo_mixers |= card->ac97_stereo_mixers; if (ch == 0) { card->ac97->supported_mixers &= ~(1 << id); card->ac97->supported_mixers |= card->ac97_supported_mixers; } } break; case CMD_SETPASSTHROUGH: card->pt.selected = ctl->val[0] ? 1 : 0; if (card->pt.state != PT_STATE_INACTIVE) break; card->pt.spcs_to_use = ctl->val[0] & 0x07; break; case CMD_PRIVATE3_VERSION: ctl->val[0] = PRIVATE3_VERSION; //private3 version ctl->val[1] = MAJOR_VER; //major driver version ctl->val[2] = MINOR_VER; //minor driver version ctl->val[3] = card->is_audigy; //1=card is audigy if (card->is_audigy) ctl->val[4]=emu10k1_readfn0(card, 0x18); if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl))) ret = -EFAULT; break; case CMD_AC97_BOOST: if (ctl->val[0]) emu10k1_ac97_write(card->ac97, 0x18, 0x0); else emu10k1_ac97_write(card->ac97, 0x18, 0x0808); break; default: ret = -EINVAL; break; } kfree(ctl); return ret; break; case SOUND_MIXER_PRIVATE4: if (copy_from_user(&size, argp, sizeof(size))) return -EFAULT; DPD(2, "External tram size %#x\n", size); if (size > 0x1fffff) return -EINVAL; size_reg = 0; if (size != 0) { size = (size - 1) >> 14; while (size) { size >>= 1; size_reg++; } size = 0x4000 << size_reg; } DPD(2, "External tram size %#x %#x\n", size, size_reg); if (size != card->tankmem.size) { if (card->tankmem.size > 0) { emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 1); sblive_writeptr_tag(card, 0, TCB, 0, TCBS, 0, TAGLIST_END); pci_free_consistent(card->pci_dev, card->tankmem.size, card->tankmem.addr, card->tankmem.dma_handle); card->tankmem.size = 0; } if (size != 0) { card->tankmem.addr = pci_alloc_consistent(card->pci_dev, size, &card->tankmem.dma_handle); if (card->tankmem.addr == NULL) return -ENOMEM; card->tankmem.size = size; sblive_writeptr_tag(card, 0, TCB, (u32) card->tankmem.dma_handle, TCBS,(u32) size_reg, TAGLIST_END); emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 0); } } return 0; break; default: break; } return -EINVAL;}static int emu10k1_dsp_mixer(struct emu10k1_card *card, unsigned int oss_mixer, unsigned long arg){ unsigned int left, right; int val; int scale; card->ac97->modcnt++; if (get_user(val, (int __user *)arg)) return -EFAULT; /* cleanse input a little */ right = ((val >> 8) & 0xff); left = (val & 0xff); if (right > 100) right = 100; if (left > 100) left = 100; card->ac97->mixer_state[oss_mixer] = (right << 8) | left; if (oss_mixer == SOUND_MIXER_TREBLE) { set_treble(card, left, right); return 0; } if (oss_mixer == SOUND_MIXER_BASS) { set_bass(card, left, right); return 0; } if (oss_mixer == SOUND_MIXER_VOLUME) scale = 1 << card->ac97->bit_resolution; else scale = volume_params[oss_mixer]; emu10k1_set_volume_gpr(card, card->mgr.ctrl_gpr[oss_mixer][0], left, scale); emu10k1_set_volume_gpr(card, card->mgr.ctrl_gpr[oss_mixer][1], right, scale); if (card->ac97_supported_mixers & (1 << oss_mixer)) card->ac97->write_mixer(card->ac97, oss_mixer, left, right); return 0;}static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int ret; struct emu10k1_card *card = file->private_data; unsigned int oss_mixer = _IOC_NR(cmd); ret = -EINVAL; if (!card->is_aps) { if (cmd == SOUND_MIXER_INFO) { mixer_info info; strlcpy(info.id, card->ac97->name, sizeof(info.id)); if (card->is_audigy) strlcpy(info.name, "Audigy - Emu10k1", sizeof(info.name)); else strlcpy(info.name, "Creative SBLive - Emu10k1", sizeof(info.name)); info.modify_counter = card->ac97->modcnt; if (copy_to_user((void __user *)arg, &info, sizeof(info))) return -EFAULT; return 0; } if ((_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) && oss_mixer <= SOUND_MIXER_NRDEVICES) ret = emu10k1_dsp_mixer(card, oss_mixer, arg); else ret = card->ac97->mixer_ioctl(card->ac97, cmd, arg); } if (ret < 0) ret = emu10k1_private_mixer(card, cmd, arg); return ret;}static int emu10k1_mixer_open(struct inode *inode, struct file *file){ int minor = iminor(inode); struct emu10k1_card *card = NULL; struct list_head *entry; DPF(4, "emu10k1_mixer_open()\n"); list_for_each(entry, &emu10k1_devs) { card = list_entry(entry, struct emu10k1_card, list); if (card->ac97->dev_mixer == minor) goto match; } return -ENODEV; match: file->private_data = card; return 0;}static int emu10k1_mixer_release(struct inode *inode, struct file *file){ DPF(4, "emu10k1_mixer_release()\n"); return 0;}struct file_operations emu10k1_mixer_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .ioctl = emu10k1_mixer_ioctl, .open = emu10k1_mixer_open, .release = emu10k1_mixer_release,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -