📄 riptide.c
字号:
/* * Driver for the Conexant Riptide Soundchip * * Copyright (c) 2004 Peter Gruber <nokos@gmx.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *//* History: - 02/15/2004 first release This Driver is based on the OSS Driver version from Linuxant (riptide-0.6lnxtbeta03111100) credits from the original files: MODULE NAME: cnxt_rt.h AUTHOR: K. Lazarev (Transcribed by KNL) HISTORY: Major Revision Date By ----------------------------- -------- ----- Created 02/1/2000 KNL MODULE NAME: int_mdl.c AUTHOR: Konstantin Lazarev (Transcribed by KNL) HISTORY: Major Revision Date By ----------------------------- -------- ----- Created 10/01/99 KNL MODULE NAME: riptide.h AUTHOR: O. Druzhinin (Transcribed by OLD) HISTORY: Major Revision Date By ----------------------------- -------- ----- Created 10/16/97 OLD MODULE NAME: Rp_Cmdif.cpp AUTHOR: O. Druzhinin (Transcribed by OLD) K. Lazarev (Transcribed by KNL) HISTORY: Major Revision Date By ----------------------------- -------- ----- Adopted from NT4 driver 6/22/99 OLD Ported to Linux 9/01/99 KNL MODULE NAME: rt_hw.c AUTHOR: O. Druzhinin (Transcribed by OLD) C. Lazarev (Transcribed by CNL) HISTORY: Major Revision Date By ----------------------------- -------- ----- Created 11/18/97 OLD Hardware functions for RipTide 11/24/97 CNL (ES1) are coded Hardware functions for RipTide 12/24/97 CNL (A0) are coded Hardware functions for RipTide 03/20/98 CNL (A1) are coded Boot loader is included 05/07/98 CNL Redesigned for WDM 07/27/98 CNL Redesigned for Linux 09/01/99 CNL MODULE NAME: rt_hw.h AUTHOR: C. Lazarev (Transcribed by CNL) HISTORY: Major Revision Date By ----------------------------- -------- ----- Created 11/18/97 CNL MODULE NAME: rt_mdl.c AUTHOR: Konstantin Lazarev (Transcribed by KNL) HISTORY: Major Revision Date By ----------------------------- -------- ----- Created 10/01/99 KNL MODULE NAME: mixer.h AUTHOR: K. Kenney HISTORY: Major Revision Date By ----------------------------- -------- ----- Created from MS W95 Sample 11/28/95 KRS RipTide 10/15/97 KRS Adopted for Windows NT driver 01/20/98 CNL*/#include <sound/driver.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/slab.h>#include <linux/wait.h>#include <linux/gameport.h>#include <linux/device.h>#include <linux/firmware.h>#include <asm/io.h>#include <sound/core.h>#include <sound/info.h>#include <sound/control.h>#include <sound/pcm.h>#include <sound/pcm_params.h>#include <sound/ac97_codec.h>#include <sound/mpu401.h>#include <sound/opl3.h>#include <sound/initval.h>#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))#define SUPPORT_JOYSTICK 1#endifMODULE_AUTHOR("Peter Gruber <nokos@gmx.net>");MODULE_DESCRIPTION("riptide");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{Conexant,Riptide}}");static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;#ifdef SUPPORT_JOYSTICKstatic int joystick_port[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS - 1)] = 0x200 };#endifstatic int mpu_port[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS - 1)] = 0x330 };static int opl3_port[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS - 1)] = 0x388 };module_param_array(index, int, NULL, 0444);MODULE_PARM_DESC(index, "Index value for Riptide soundcard.");module_param_array(id, charp, NULL, 0444);MODULE_PARM_DESC(id, "ID string for Riptide soundcard.");module_param_array(enable, bool, NULL, 0444);MODULE_PARM_DESC(enable, "Enable Riptide soundcard.");#ifdef SUPPORT_JOYSTICKmodule_param_array(joystick_port, int, NULL, 0444);MODULE_PARM_DESC(joystick_port, "Joystick port # for Riptide soundcard.");#endifmodule_param_array(mpu_port, int, NULL, 0444);MODULE_PARM_DESC(mpu_port, "MPU401 port # for Riptide driver.");module_param_array(opl3_port, int, NULL, 0444);MODULE_PARM_DESC(opl3_port, "OPL3 port # for Riptide driver.");/* */#define MPU401_HW_RIPTIDE MPU401_HW_MPU401#define OPL3_HW_RIPTIDE OPL3_HW_OPL3#define PCI_EXT_CapId 0x40#define PCI_EXT_NextCapPrt 0x41#define PCI_EXT_PWMC 0x42#define PCI_EXT_PWSCR 0x44#define PCI_EXT_Data00 0x46#define PCI_EXT_PMSCR_BSE 0x47#define PCI_EXT_SB_Base 0x48#define PCI_EXT_FM_Base 0x4a#define PCI_EXT_MPU_Base 0x4C#define PCI_EXT_Game_Base 0x4E#define PCI_EXT_Legacy_Mask 0x50#define PCI_EXT_AsicRev 0x52#define PCI_EXT_Reserved3 0x53#define LEGACY_ENABLE_ALL 0x8000 /* legacy device options */#define LEGACY_ENABLE_SB 0x4000#define LEGACY_ENABLE_FM 0x2000#define LEGACY_ENABLE_MPU_INT 0x1000#define LEGACY_ENABLE_MPU 0x0800#define LEGACY_ENABLE_GAMEPORT 0x0400#define MAX_WRITE_RETRY 10 /* cmd interface limits */#define MAX_ERROR_COUNT 10#define CMDIF_TIMEOUT 500000#define RESET_TRIES 5#define READ_PORT_ULONG(p) inl((unsigned long)&(p))#define WRITE_PORT_ULONG(p,x) outl(x,(unsigned long)&(p))#define READ_AUDIO_CONTROL(p) READ_PORT_ULONG(p->audio_control)#define WRITE_AUDIO_CONTROL(p,x) WRITE_PORT_ULONG(p->audio_control,x)#define UMASK_AUDIO_CONTROL(p,x) WRITE_PORT_ULONG(p->audio_control,READ_PORT_ULONG(p->audio_control)|x)#define MASK_AUDIO_CONTROL(p,x) WRITE_PORT_ULONG(p->audio_control,READ_PORT_ULONG(p->audio_control)&x)#define READ_AUDIO_STATUS(p) READ_PORT_ULONG(p->audio_status)#define SET_GRESET(p) UMASK_AUDIO_CONTROL(p,0x0001) /* global reset switch */#define UNSET_GRESET(p) MASK_AUDIO_CONTROL(p,~0x0001)#define SET_AIE(p) UMASK_AUDIO_CONTROL(p,0x0004) /* interrupt enable */#define UNSET_AIE(p) MASK_AUDIO_CONTROL(p,~0x0004)#define SET_AIACK(p) UMASK_AUDIO_CONTROL(p,0x0008) /* interrupt acknowledge */#define UNSET_AIACKT(p) MASKAUDIO_CONTROL(p,~0x0008)#define SET_ECMDAE(p) UMASK_AUDIO_CONTROL(p,0x0010)#define UNSET_ECMDAE(p) MASK_AUDIO_CONTROL(p,~0x0010)#define SET_ECMDBE(p) UMASK_AUDIO_CONTROL(p,0x0020)#define UNSET_ECMDBE(p) MASK_AUDIO_CONTROL(p,~0x0020)#define SET_EDATAF(p) UMASK_AUDIO_CONTROL(p,0x0040)#define UNSET_EDATAF(p) MASK_AUDIO_CONTROL(p,~0x0040)#define SET_EDATBF(p) UMASK_AUDIO_CONTROL(p,0x0080)#define UNSET_EDATBF(p) MASK_AUDIO_CONTROL(p,~0x0080)#define SET_ESBIRQON(p) UMASK_AUDIO_CONTROL(p,0x0100)#define UNSET_ESBIRQON(p) MASK_AUDIO_CONTROL(p,~0x0100)#define SET_EMPUIRQ(p) UMASK_AUDIO_CONTROL(p,0x0200)#define UNSET_EMPUIRQ(p) MASK_AUDIO_CONTROL(p,~0x0200)#define IS_CMDE(a) (READ_PORT_ULONG(a->stat)&0x1) /* cmd empty */#define IS_DATF(a) (READ_PORT_ULONG(a->stat)&0x2) /* data filled */#define IS_READY(p) (READ_AUDIO_STATUS(p)&0x0001)#define IS_DLREADY(p) (READ_AUDIO_STATUS(p)&0x0002)#define IS_DLERR(p) (READ_AUDIO_STATUS(p)&0x0004)#define IS_GERR(p) (READ_AUDIO_STATUS(p)&0x0008) /* error ! */#define IS_CMDAEIRQ(p) (READ_AUDIO_STATUS(p)&0x0010)#define IS_CMDBEIRQ(p) (READ_AUDIO_STATUS(p)&0x0020)#define IS_DATAFIRQ(p) (READ_AUDIO_STATUS(p)&0x0040)#define IS_DATBFIRQ(p) (READ_AUDIO_STATUS(p)&0x0080)#define IS_EOBIRQ(p) (READ_AUDIO_STATUS(p)&0x0100) /* interrupt status */#define IS_EOSIRQ(p) (READ_AUDIO_STATUS(p)&0x0200)#define IS_EOCIRQ(p) (READ_AUDIO_STATUS(p)&0x0400)#define IS_UNSLIRQ(p) (READ_AUDIO_STATUS(p)&0x0800)#define IS_SBIRQ(p) (READ_AUDIO_STATUS(p)&0x1000)#define IS_MPUIRQ(p) (READ_AUDIO_STATUS(p)&0x2000)#define RESP 0x00000001 /* command flags */#define PARM 0x00000002#define CMDA 0x00000004#define CMDB 0x00000008#define NILL 0x00000000#define LONG0(a) ((u32)a) /* shifts and masks */#define BYTE0(a) (LONG0(a)&0xff)#define BYTE1(a) (BYTE0(a)<<8)#define BYTE2(a) (BYTE0(a)<<16)#define BYTE3(a) (BYTE0(a)<<24)#define WORD0(a) (LONG0(a)&0xffff)#define WORD1(a) (WORD0(a)<<8)#define WORD2(a) (WORD0(a)<<16)#define TRINIB0(a) (LONG0(a)&0xffffff)#define TRINIB1(a) (TRINIB0(a)<<8)#define RET(a) ((union cmdret *)(a))#define SEND_GETV(p,b) sendcmd(p,RESP,GETV,0,RET(b)) /* get version */#define SEND_GETC(p,b,c) sendcmd(p,PARM|RESP,GETC,c,RET(b))#define SEND_GUNS(p,b) sendcmd(p,RESP,GUNS,0,RET(b))#define SEND_SCID(p,b) sendcmd(p,RESP,SCID,0,RET(b))#define SEND_RMEM(p,b,c,d) sendcmd(p,PARM|RESP,RMEM|BYTE1(b),LONG0(c),RET(d)) /* memory access for firmware write */#define SEND_SMEM(p,b,c) sendcmd(p,PARM,SMEM|BYTE1(b),LONG0(c),RET(0)) /* memory access for firmware write */#define SEND_WMEM(p,b,c) sendcmd(p,PARM,WMEM|BYTE1(b),LONG0(c),RET(0)) /* memory access for firmware write */#define SEND_SDTM(p,b,c) sendcmd(p,PARM|RESP,SDTM|TRINIB1(b),0,RET(c)) /* memory access for firmware write */#define SEND_GOTO(p,b) sendcmd(p,PARM,GOTO,LONG0(b),RET(0)) /* memory access for firmware write */#define SEND_SETDPLL(p) sendcmd(p,0,ARM_SETDPLL,0,RET(0))#define SEND_SSTR(p,b,c) sendcmd(p,PARM,SSTR|BYTE3(b),LONG0(c),RET(0)) /* start stream */#define SEND_PSTR(p,b) sendcmd(p,PARM,PSTR,BYTE3(b),RET(0)) /* pause stream */#define SEND_KSTR(p,b) sendcmd(p,PARM,KSTR,BYTE3(b),RET(0)) /* stop stream */#define SEND_KDMA(p) sendcmd(p,0,KDMA,0,RET(0)) /* stop all dma */#define SEND_GPOS(p,b,c,d) sendcmd(p,PARM|RESP,GPOS,BYTE3(c)|BYTE2(b),RET(d)) /* get position in dma */#define SEND_SETF(p,b,c,d,e,f,g) sendcmd(p,PARM,SETF|WORD1(b)|BYTE3(c),d|BYTE1(e)|BYTE2(f)|BYTE3(g),RET(0)) /* set sample format at mixer */#define SEND_GSTS(p,b,c,d) sendcmd(p,PARM|RESP,GSTS,BYTE3(c)|BYTE2(b),RET(d))#define SEND_NGPOS(p,b,c,d) sendcmd(p,PARM|RESP,NGPOS,BYTE3(c)|BYTE2(b),RET(d))#define SEND_PSEL(p,b,c) sendcmd(p,PARM,PSEL,BYTE2(b)|BYTE3(c),RET(0)) /* activate lbus path */#define SEND_PCLR(p,b,c) sendcmd(p,PARM,PCLR,BYTE2(b)|BYTE3(c),RET(0)) /* deactivate lbus path */#define SEND_PLST(p,b) sendcmd(p,PARM,PLST,BYTE3(b),RET(0))#define SEND_RSSV(p,b,c,d) sendcmd(p,PARM|RESP,RSSV,BYTE2(b)|BYTE3(c),RET(d))#define SEND_LSEL(p,b,c,d,e,f,g,h) sendcmd(p,PARM,LSEL|BYTE1(b)|BYTE2(c)|BYTE3(d),BYTE0(e)|BYTE1(f)|BYTE2(g)|BYTE3(h),RET(0)) /* select paths for internal connections */#define SEND_SSRC(p,b,c,d,e) sendcmd(p,PARM,SSRC|BYTE1(b)|WORD2(c),WORD0(d)|WORD2(e),RET(0)) /* configure source */#define SEND_SLST(p,b) sendcmd(p,PARM,SLST,BYTE3(b),RET(0))#define SEND_RSRC(p,b,c) sendcmd(p,RESP,RSRC|BYTE1(b),0,RET(c)) /* read source config */#define SEND_SSRB(p,b,c) sendcmd(p,PARM,SSRB|BYTE1(b),WORD2(c),RET(0))#define SEND_SDGV(p,b,c,d,e) sendcmd(p,PARM,SDGV|BYTE2(b)|BYTE3(c),WORD0(d)|WORD2(e),RET(0)) /* set digital mixer */#define SEND_RDGV(p,b,c,d) sendcmd(p,PARM|RESP,RDGV|BYTE2(b)|BYTE3(c),0,RET(d)) /* read digital mixer */#define SEND_DLST(p,b) sendcmd(p,PARM,DLST,BYTE3(b),RET(0))#define SEND_SACR(p,b,c) sendcmd(p,PARM,SACR,WORD0(b)|WORD2(c),RET(0)) /* set AC97 register */#define SEND_RACR(p,b,c) sendcmd(p,PARM|RESP,RACR,WORD2(b),RET(c)) /* get AC97 register */#define SEND_ALST(p,b) sendcmd(p,PARM,ALST,BYTE3(b),RET(0))#define SEND_TXAC(p,b,c,d,e,f) sendcmd(p,PARM,TXAC|BYTE1(b)|WORD2(c),WORD0(d)|BYTE2(e)|BYTE3(f),RET(0))#define SEND_RXAC(p,b,c,d) sendcmd(p,PARM|RESP,RXAC,BYTE2(b)|BYTE3(c),RET(d))#define SEND_SI2S(p,b) sendcmd(p,PARM,SI2S,WORD2(b),RET(0))#define EOB_STATUS 0x80000000 /* status flags : block boundary */#define EOS_STATUS 0x40000000 /* : stoppped */#define EOC_STATUS 0x20000000 /* : stream end */#define ERR_STATUS 0x10000000#define EMPTY_STATUS 0x08000000#define IEOB_ENABLE 0x1 /* enable interrupts for status notification above */#define IEOS_ENABLE 0x2#define IEOC_ENABLE 0x4#define RDONCE 0x8#define DESC_MAX_MASK 0xff#define ST_PLAY 0x1 /* stream states */#define ST_STOP 0x2#define ST_PAUSE 0x4#define I2S_INTDEC 3 /* config for I2S link */#define I2S_MERGER 0#define I2S_SPLITTER 0#define I2S_MIXER 7#define I2S_RATE 44100#define MODEM_INTDEC 4 /* config for modem link */#define MODEM_MERGER 3#define MODEM_SPLITTER 0#define MODEM_MIXER 11#define FM_INTDEC 3 /* config for FM/OPL3 link */#define FM_MERGER 0#define FM_SPLITTER 0#define FM_MIXER 9#define SPLIT_PATH 0x80 /* path splitting flag */enum FIRMWARE { DATA_REC = 0, EXT_END_OF_FILE, EXT_SEG_ADDR_REC, EXT_GOTO_CMD_REC, EXT_LIN_ADDR_REC,};enum CMDS { GETV = 0x00, GETC, GUNS, SCID, RMEM = 0x10, SMEM, WMEM, SDTM, GOTO, SSTR = 0x20, PSTR, KSTR, KDMA, GPOS, SETF, GSTS, NGPOS, PSEL = 0x30, PCLR, PLST, RSSV, LSEL, SSRC = 0x40, SLST, RSRC, SSRB, SDGV = 0x50, RDGV, DLST, SACR = 0x60, RACR, ALST, TXAC, RXAC, SI2S = 0x70, ARM_SETDPLL = 0x72,};enum E1SOURCE { ARM2LBUS_FIFO0 = 0, ARM2LBUS_FIFO1, ARM2LBUS_FIFO2, ARM2LBUS_FIFO3, ARM2LBUS_FIFO4, ARM2LBUS_FIFO5, ARM2LBUS_FIFO6, ARM2LBUS_FIFO7, ARM2LBUS_FIFO8, ARM2LBUS_FIFO9, ARM2LBUS_FIFO10, ARM2LBUS_FIFO11, ARM2LBUS_FIFO12, ARM2LBUS_FIFO13, ARM2LBUS_FIFO14, ARM2LBUS_FIFO15, INTER0_OUT, INTER1_OUT, INTER2_OUT, INTER3_OUT, INTER4_OUT, INTERM0_OUT, INTERM1_OUT, INTERM2_OUT, INTERM3_OUT, INTERM4_OUT, INTERM5_OUT, INTERM6_OUT, DECIMM0_OUT, DECIMM1_OUT, DECIMM2_OUT, DECIMM3_OUT, DECIM0_OUT, SR3_4_OUT, OPL3_SAMPLE, ASRC0, ASRC1, ACLNK2PADC, ACLNK2MODEM0RX, ACLNK2MIC, ACLNK2MODEM1RX, ACLNK2HNDMIC, DIGITAL_MIXER_OUT0, GAINFUNC0_OUT, GAINFUNC1_OUT, GAINFUNC2_OUT, GAINFUNC3_OUT, GAINFUNC4_OUT, SOFTMODEMTX, SPLITTER0_OUTL, SPLITTER0_OUTR, SPLITTER1_OUTL, SPLITTER1_OUTR, SPLITTER2_OUTL, SPLITTER2_OUTR, SPLITTER3_OUTL, SPLITTER3_OUTR, MERGER0_OUT, MERGER1_OUT, MERGER2_OUT, MERGER3_OUT, ARM2LBUS_FIFO_DIRECT, NO_OUT};enum E2SINK { LBUS2ARM_FIFO0 = 0, LBUS2ARM_FIFO1, LBUS2ARM_FIFO2, LBUS2ARM_FIFO3, LBUS2ARM_FIFO4, LBUS2ARM_FIFO5, LBUS2ARM_FIFO6, LBUS2ARM_FIFO7, INTER0_IN, INTER1_IN, INTER2_IN, INTER3_IN, INTER4_IN, INTERM0_IN, INTERM1_IN, INTERM2_IN, INTERM3_IN, INTERM4_IN, INTERM5_IN, INTERM6_IN, DECIMM0_IN, DECIMM1_IN, DECIMM2_IN, DECIMM3_IN, DECIM0_IN, SR3_4_IN, PDAC2ACLNK, MODEM0TX2ACLNK, MODEM1TX2ACLNK, HNDSPK2ACLNK, DIGITAL_MIXER_IN0, DIGITAL_MIXER_IN1, DIGITAL_MIXER_IN2, DIGITAL_MIXER_IN3, DIGITAL_MIXER_IN4, DIGITAL_MIXER_IN5, DIGITAL_MIXER_IN6, DIGITAL_MIXER_IN7, DIGITAL_MIXER_IN8, DIGITAL_MIXER_IN9, DIGITAL_MIXER_IN10, DIGITAL_MIXER_IN11, GAINFUNC0_IN, GAINFUNC1_IN, GAINFUNC2_IN, GAINFUNC3_IN, GAINFUNC4_IN, SOFTMODEMRX, SPLITTER0_IN, SPLITTER1_IN, SPLITTER2_IN, SPLITTER3_IN, MERGER0_INL, MERGER0_INR, MERGER1_INL, MERGER1_INR, MERGER2_INL, MERGER2_INR, MERGER3_INL, MERGER3_INR, E2SINK_MAX};enum LBUS_SINK { LS_SRC_INTERPOLATOR = 0, LS_SRC_INTERPOLATORM, LS_SRC_DECIMATOR, LS_SRC_DECIMATORM, LS_MIXER_IN, LS_MIXER_GAIN_FUNCTION, LS_SRC_SPLITTER, LS_SRC_MERGER, LS_NONE1, LS_NONE2,};enum RT_CHANNEL_IDS { M0TX = 0, M1TX, TAMTX, HSSPKR, PDAC, DSNDTX0, DSNDTX1, DSNDTX2, DSNDTX3, DSNDTX4, DSNDTX5, DSNDTX6, DSNDTX7, WVSTRTX, COP3DTX, SPARE, M0RX, HSMIC, M1RX, CLEANRX, MICADC, PADC, COPRX1, COPRX2, CHANNEL_ID_COUNTER};enum { SB_CMD = 0, MODEM_CMD, I2S_CMD0, I2S_CMD1, FM_CMD, MAX_CMD };struct lbuspath { unsigned char *noconv; unsigned char *stereo; unsigned char *mono;};struct cmdport { u32 data1; /* cmd,param */ u32 data2; /* param */ u32 stat; /* status */ u32 pad[5];};struct riptideport { u32 audio_control; /* status registers */ u32 audio_status; u32 pad[2]; struct cmdport port[2]; /* command ports */};struct cmdif { struct riptideport *hwport; spinlock_t lock; unsigned int cmdcnt; /* cmd statistics */ unsigned int cmdtime; unsigned int cmdtimemax; unsigned int cmdtimemin; unsigned int errcnt; int is_reset;};struct riptide_firmware { u16 ASIC; u16 CODEC; u16 AUXDSP; u16 PROG;};union cmdret { u8 retbytes[8]; u16 retwords[4]; u32 retlongs[2];};union firmware_version { union cmdret ret; struct riptide_firmware firmware;};#define get_pcmhwdev(substream) (struct pcmhw *)(substream->runtime->private_data)#define PLAYBACK_SUBSTREAMS 3struct snd_riptide { struct snd_card *card; struct pci_dev *pci; const struct firmware *fw_entry; struct cmdif *cif; struct snd_pcm *pcm; struct snd_pcm *pcm_i2s; struct snd_rawmidi *rmidi; struct snd_opl3 *opl3; struct snd_ac97 *ac97; struct snd_ac97_bus *ac97_bus; struct snd_pcm_substream *playback_substream[PLAYBACK_SUBSTREAMS]; struct snd_pcm_substream *capture_substream; int openstreams;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -