1
0
Files
kernel-49/sound/pci/rme9652/rme9652.c
Greg Kroah-Hartman b2edd4e6c6 Merge 4.9.269 into android-4.9-q
Changes in 4.9.269
	net: usb: ax88179_178a: initialize local variables before use
	iwlwifi: Fix softirq/hardirq disabling in iwl_pcie_enqueue_hcmd()
	ALSA: usb-audio: Add MIDI quirk for Vox ToneLab EX
	USB: Add LPM quirk for Lenovo ThinkPad USB-C Dock Gen2 Ethernet
	USB: Add reset-resume quirk for WD19's Realtek Hub
	platform/x86: thinkpad_acpi: Correct thermal sensor allocation
	s390/disassembler: increase ebpf disasm buffer size
	ACPI: custom_method: fix potential use-after-free issue
	ACPI: custom_method: fix a possible memory leak
	arm64: dts: mt8173: fix property typo of 'phys' in dsi node
	ecryptfs: fix kernel panic with null dev_name
	mmc: core: Do a power cycle when the CMD11 fails
	mmc: core: Set read only for SD cards with permanent write protect bit
	btrfs: fix metadata extent leak after failure to create subvolume
	fbdev: zero-fill colormap in fbcmap.c
	staging: wimax/i2400m: fix byte-order issue
	usb: gadget: uvc: add bInterval checking for HS mode
	usb: dwc3: gadget: Ignore EP queue requests during bus reset
	usb: xhci: Fix port minor revision
	PCI: PM: Do not read power state in pci_enable_device_flags()
	x86/build: Propagate $(CLANG_FLAGS) to $(REALMODE_FLAGS)
	spi: dln2: Fix reference leak to master
	spi: omap-100k: Fix reference leak to master
	intel_th: Consistency and off-by-one fix
	phy: phy-twl4030-usb: Fix possible use-after-free in twl4030_usb_remove()
	btrfs: convert logic BUG_ON()'s in replace_path to ASSERT()'s
	scsi: target: pscsi: Fix warning in pscsi_complete_cmd()
	media: ite-cir: check for receive overflow
	extcon: arizona: Fix some issues when HPDET IRQ fires after the jack has been unplugged
	media: media/saa7164: fix saa7164_encoder_register() memory leak bugs
	media: gspca/sq905.c: fix uninitialized variable
	power: supply: Use IRQF_ONESHOT
	scsi: qla2xxx: Always check the return value of qla24xx_get_isp_stats()
	scsi: scsi_dh_alua: Remove check for ASC 24h in alua_rtpg()
	media: em28xx: fix memory leak
	clk: socfpga: arria10: Fix memory leak of socfpga_clk on error return
	power: supply: generic-adc-battery: fix possible use-after-free in gab_remove()
	power: supply: s3c_adc_battery: fix possible use-after-free in s3c_adc_bat_remove()
	media: adv7604: fix possible use-after-free in adv76xx_remove()
	media: i2c: adv7511-v4l2: fix possible use-after-free in adv7511_remove()
	media: i2c: adv7842: fix possible use-after-free in adv7842_remove()
	media: dvb-usb: fix memory leak in dvb_usb_adapter_init
	media: gscpa/stv06xx: fix memory leak
	drm/msm/mdp5: Configure PP_SYNC_HEIGHT to double the vtotal
	drm/amdgpu: fix NULL pointer dereference
	scsi: lpfc: Fix crash when a REG_RPI mailbox fails triggering a LOGO response
	scsi: libfc: Fix a format specifier
	ALSA: emu8000: Fix a use after free in snd_emu8000_create_mixer
	ALSA: sb: Fix two use after free in snd_sb_qsound_build
	arm64/vdso: Discard .note.gnu.property sections in vDSO
	openvswitch: fix stack OOB read while fragmenting IPv4 packets
	NFSv4: Don't discard segments marked for return in _pnfs_return_layout()
	jffs2: Fix kasan slab-out-of-bounds problem
	powerpc/eeh: Fix EEH handling for hugepages in ioremap space.
	powerpc: fix EDEADLOCK redefinition error in uapi/asm/errno.h
	jffs2: check the validity of dstlen in jffs2_zlib_compress()
	Revert 337f13046ff0 ("futex: Allow FUTEX_CLOCK_REALTIME with FUTEX_WAIT op")
	ftrace: Handle commands when closing set_ftrace_filter file
	ext4: fix check to prevent false positive report of incorrect used inodes
	ext4: fix error code in ext4_commit_super
	media: dvbdev: Fix memory leak in dvb_media_device_free()
	usb: gadget: dummy_hcd: fix gpf in gadget_setup
	usb: gadget: Fix double free of device descriptor pointers
	usb: gadget/function/f_fs string table fix for multiple languages
	dm persistent data: packed struct should have an aligned() attribute too
	dm space map common: fix division bug in sm_ll_find_free_block()
	dm rq: fix double free of blk_mq_tag_set in dev remove after table load fails
	Bluetooth: verify AMP hci_chan before amp_destroy
	hsr: use netdev_err() instead of WARN_ONCE()
	bluetooth: eliminate the potential race condition when removing the HCI controller
	net/nfc: fix use-after-free llcp_sock_bind/connect
	FDDI: defxx: Bail out gracefully with unassigned PCI resource for CSR
	misc: lis3lv02d: Fix false-positive WARN on various HP models
	misc: vmw_vmci: explicitly initialize vmci_notify_bm_set_msg struct
	misc: vmw_vmci: explicitly initialize vmci_datagram payload
	tracing: Treat recording comm for idle task as a success
	tracing: Use strlcpy() instead of strcpy() in __trace_find_cmdline()
	tracing: Map all PIDs to command lines
	tracing: Restructure trace_clock_global() to never block
	md-cluster: fix use-after-free issue when removing rdev
	md: factor out a mddev_find_locked helper from mddev_find
	md: md_open returns -EBUSY when entering racing area
	ipw2x00: potential buffer overflow in libipw_wx_set_encodeext()
	cfg80211: scan: drop entry from hidden_list on overflow
	drm/radeon: fix copy of uninitialized variable back to userspace
	ALSA: hda/realtek: Re-order ALC882 Acer quirk table entries
	ALSA: hda/realtek: Re-order ALC882 Sony quirk table entries
	ALSA: hda/realtek: Re-order ALC269 Sony quirk table entries
	ALSA: hda/realtek: Re-order ALC269 Lenovo quirk table entries
	ALSA: hda/realtek: Remove redundant entry for ALC861 Haier/Uniwill devices
	usb: gadget: pch_udc: Revert d3cb25a12138 completely
	memory: gpmc: fix out of bounds read and dereference on gpmc_cs[]
	ARM: dts: exynos: correct PMIC interrupt trigger level on SMDK5250
	ARM: dts: exynos: correct PMIC interrupt trigger level on Snow
	serial: stm32: fix incorrect characters on console
	usb: gadget: pch_udc: Replace cpu_to_le32() by lower_32_bits()
	usb: gadget: pch_udc: Check if driver is present before calling ->setup()
	usb: gadget: pch_udc: Check for DMA mapping error
	crypto: qat - don't release uninitialized resources
	crypto: qat - ADF_STATUS_PF_RUNNING should be set after adf_dev_init
	fotg210-udc: Fix DMA on EP0 for length > max packet size
	fotg210-udc: Fix EP0 IN requests bigger than two packets
	fotg210-udc: Remove a dubious condition leading to fotg210_done
	fotg210-udc: Mask GRP2 interrupts we don't handle
	fotg210-udc: Don't DMA more than the buffer can take
	fotg210-udc: Complete OUT requests on short packets
	mtd: require write permissions for locking and badblock ioctls
	bus: qcom: Put child node before return
	crypto: qat - fix error path in adf_isr_resource_alloc()
	mtd: rawnand: gpmi: Fix a double free in gpmi_nand_init
	staging: rtl8192u: Fix potential infinite loop
	staging: greybus: uart: fix unprivileged TIOCCSERIAL
	crypto: qat - Fix a double free in adf_create_ring
	usb: gadget: r8a66597: Add missing null check on return from platform_get_resource
	USB: cdc-acm: fix unprivileged TIOCCSERIAL
	tty: actually undefine superseded ASYNC flags
	tty: fix return value for unsupported ioctls
	firmware: qcom-scm: Fix QCOM_SCM configuration
	x86/platform/uv: Fix !KEXEC build failure
	Drivers: hv: vmbus: Increase wait time for VMbus unload
	ttyprintk: Add TTY hangup callback.
	media: vivid: fix assignment of dev->fbuf_out_flags
	media: omap4iss: return error code when omap4iss_get() failed
	media: m88rs6000t: avoid potential out-of-bounds reads on arrays
	pata_arasan_cf: fix IRQ check
	pata_ipx4xx_cf: fix IRQ check
	sata_mv: add IRQ checks
	ata: libahci_platform: fix IRQ check
	scsi: fcoe: Fix mismatched fcoe_wwn_from_mac declaration
	media: dvb-usb-remote: fix dvb_usb_nec_rc_key_to_event type mismatch
	clk: uniphier: Fix potential infinite loop
	scsi: jazz_esp: Add IRQ check
	scsi: sun3x_esp: Add IRQ check
	scsi: sni_53c710: Add IRQ check
	HSI: core: fix resource leaks in hsi_add_client_from_dt()
	x86/events/amd/iommu: Fix sysfs type mismatch
	HID: plantronics: Workaround for double volume key presses
	perf symbols: Fix dso__fprintf_symbols_by_name() to return the number of printed chars
	net: lapbether: Prevent racing when checking whether the netif is running
	powerpc/prom: Mark identical_pvr_fixup as __init
	ALSA: core: remove redundant spin_lock pair in snd_card_disconnect
	nfc: pn533: prevent potential memory corruption
	ALSA: usb-audio: Add error checks for usb_driver_claim_interface() calls
	liquidio: Fix unintented sign extension of a left shift of a u16
	powerpc/perf: Fix PMU constraint check for EBB events
	powerpc: iommu: fix build when neither PCI or IBMVIO is set
	mac80211: bail out if cipher schemes are invalid
	mt7601u: fix always true expression
	net: thunderx: Fix unintentional sign extension issue
	i2c: cadence: add IRQ check
	i2c: emev2: add IRQ check
	i2c: jz4780: add IRQ check
	i2c: sh7760: add IRQ check
	MIPS: pci-legacy: stop using of_pci_range_to_resource
	powerpc/pseries: extract host bridge from pci_bus prior to bus removal
	i2c: sh7760: fix IRQ error path
	mwl8k: Fix a double Free in mwl8k_probe_hw
	vsock/vmci: log once the failed queue pair allocation
	RDMA/i40iw: Fix error unwinding when i40iw_hmc_sd_one fails
	net: davinci_emac: Fix incorrect masking of tx and rx error channel
	ath9k: Fix error check in ath9k_hw_read_revisions() for PCI devices
	powerpc/52xx: Fix an invalid ASM expression ('addi' used instead of 'add')
	net:emac/emac-mac: Fix a use after free in emac_mac_tx_buf_send
	net:nfc:digital: Fix a double free in digital_tg_recv_dep_req
	kfifo: fix ternary sign extension bugs
	Revert "net/sctp: fix race condition in sctp_destroy_sock"
	sctp: delay auto_asconf init until binding the first addr
	Revert "of/fdt: Make sure no-map does not remove already reserved regions"
	Revert "fdt: Properly handle "no-map" field in the memory region"
	fs: dlm: fix debugfs dump
	tipc: convert dest node's address to network order
	net: stmmac: Set FIFO sizes for ipq806x
	ALSA: hdsp: don't disable if not enabled
	ALSA: hdspm: don't disable if not enabled
	ALSA: rme9652: don't disable if not enabled
	Bluetooth: Set CONF_NOT_COMPLETE as l2cap_chan default
	Bluetooth: initialize skb_queue_head at l2cap_chan_create()
	ip6_vti: proper dev_{hold|put} in ndo_[un]init methods
	mac80211: clear the beacon's CRC after channel switch
	cuse: prevent clone
	selftests: Set CC to clang in lib.mk if LLVM is set
	kconfig: nconf: stop endless search loops
	sctp: Fix out-of-bounds warning in sctp_process_asconf_param()
	ASoC: rt286: Generalize support for ALC3263 codec
	samples/bpf: Fix broken tracex1 due to kprobe argument change
	powerpc/pseries: Stop calling printk in rtas_stop_self()
	wl3501_cs: Fix out-of-bounds warnings in wl3501_send_pkt
	wl3501_cs: Fix out-of-bounds warnings in wl3501_mgmt_join
	powerpc/iommu: Annotate nested lock for lockdep
	net: ethernet: mtk_eth_soc: fix RX VLAN offload
	ASoC: rt286: Make RT286_SET_GPIO_* readable and writable
	f2fs: fix a redundant call to f2fs_balance_fs if an error occurs
	PCI: Release OF node in pci_scan_device()'s error path
	ARM: 9064/1: hw_breakpoint: Do not directly check the event's overflow_handler hook
	NFSv4.2: Always flush out writes in nfs42_proc_fallocate()
	NFS: Deal correctly with attribute generation counter overflow
	pNFS/flexfiles: fix incorrect size check in decode_nfs_fh()
	NFSv4.2 fix handling of sr_eof in SEEK's reply
	sctp: fix a SCTP_MIB_CURRESTAB leak in sctp_sf_do_dupcook_b
	drm/radeon: Fix off-by-one power_state index heap overwrite
	khugepaged: fix wrong result value for trace_mm_collapse_huge_page_isolate()
	mm/hugeltb: handle the error case in hugetlb_fix_reserve_counts()
	ksm: fix potential missing rmap_item for stable_node
	kernel: kexec_file: fix error return code of kexec_calculate_store_digests()
	ARC: entry: fix off-by-one error in syscall number validation
	powerpc/64s: Fix crashes when toggling entry flush barrier
	squashfs: fix divide error in calculate_skip()
	iio: proximity: pulsedlight: Fix rumtime PM imbalance on error
	usb: fotg210-hcd: Fix an error message
	ACPI: scan: Fix a memory leak in an error handling path
	usb: xhci: Increase timeout for HC halt
	usb: dwc2: Fix gadget DMA unmap direction
	usb: core: hub: fix race condition about TRSMRCY of resume
	KVM: x86: Cancel pvclock_gtod_work on module removal
	FDDI: defxx: Make MMIO the configuration default except for EISA
	MIPS: Reinstate platform `__div64_32' handler
	MIPS: Avoid DIVU in `__div64_32' is result would be zero
	MIPS: Avoid handcoded DIVU in `__div64_32' altogether
	thermal/core/fair share: Lock the thermal zone while looping over instances
	dm ioctl: fix out of bounds array access when no devices
	kobject_uevent: remove warning in init_uevent_argv()
	netfilter: conntrack: Make global sysctls readonly in non-init netns
	clk: exynos7: Mark aclk_fsys1_200 as critical
	x86/msr: Fix wr/rdmsr_safe_regs_on_cpu() prototypes
	extcon: adc-jack: Fix incompatible pointer type warning
	kgdb: fix gcc-11 warning on indentation
	usb: sl811-hcd: improve misleading indentation
	cxgb4: Fix the -Wmisleading-indentation warning
	isdn: capi: fix mismatched prototypes
	ACPI / hotplug / PCI: Fix reference count leak in enable_slot()
	Input: silead - add workaround for x86 BIOS-es which bring the chip up in a stuck state
	um: Mark all kernel symbols as local
	ceph: fix fscache invalidation
	ALSA: hda: generic: change the DAC ctl name for LO+SPK or LO+HP
	lib: stackdepot: turn depot_lock spinlock to raw_spinlock
	sit: proper dev_{hold|put} in ndo_[un]init methods
	ip6_tunnel: sit: proper dev_{hold|put} in ndo_[un]init methods
	xhci: Do not use GFP_KERNEL in (potentially) atomic context
	ipv6: remove extra dev_hold() for fallback tunnels
	Linux 4.9.269

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: Ib994aef2c6746afa8dcbb237d8c0645ba2c6f7e1
2021-05-26 21:04:22 +03:00

2621 lines
73 KiB
C

/*
* ALSA driver for RME Digi9652 audio interfaces
*
* Copyright (c) 1999 IEM - Winfried Ritsch
* Copyright (c) 1999-2001 Paul Davis
*
* 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
*
*/
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/nospec.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
#include <sound/info.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
#include <asm/current.h>
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
static bool precise_ptr[SNDRV_CARDS]; /* Enable precise pointer */
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for RME Digi9652 (Hammerfall) soundcard.");
module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for RME Digi9652 (Hammerfall) soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable/disable specific RME96{52,36} soundcards.");
module_param_array(precise_ptr, bool, NULL, 0444);
MODULE_PARM_DESC(precise_ptr, "Enable precise pointer (doesn't work reliably).");
MODULE_AUTHOR("Paul Davis <pbd@op.net>, Winfried Ritsch");
MODULE_DESCRIPTION("RME Digi9652/Digi9636");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{RME,Hammerfall},"
"{RME,Hammerfall-Light}}");
/* The Hammerfall has two sets of 24 ADAT + 2 S/PDIF channels, one for
capture, one for playback. Both the ADAT and S/PDIF channels appear
to the host CPU in the same block of memory. There is no functional
difference between them in terms of access.
The Hammerfall Light is identical to the Hammerfall, except that it
has 2 sets 18 channels (16 ADAT + 2 S/PDIF) for capture and playback.
*/
#define RME9652_NCHANNELS 26
#define RME9636_NCHANNELS 18
/* Preferred sync source choices - used by "sync_pref" control switch */
#define RME9652_SYNC_FROM_SPDIF 0
#define RME9652_SYNC_FROM_ADAT1 1
#define RME9652_SYNC_FROM_ADAT2 2
#define RME9652_SYNC_FROM_ADAT3 3
/* Possible sources of S/PDIF input */
#define RME9652_SPDIFIN_OPTICAL 0 /* optical (ADAT1) */
#define RME9652_SPDIFIN_COAXIAL 1 /* coaxial (RCA) */
#define RME9652_SPDIFIN_INTERN 2 /* internal (CDROM) */
/* ------------- Status-Register bits --------------------- */
#define RME9652_IRQ (1<<0) /* IRQ is High if not reset by irq_clear */
#define RME9652_lock_2 (1<<1) /* ADAT 3-PLL: 1=locked, 0=unlocked */
#define RME9652_lock_1 (1<<2) /* ADAT 2-PLL: 1=locked, 0=unlocked */
#define RME9652_lock_0 (1<<3) /* ADAT 1-PLL: 1=locked, 0=unlocked */
#define RME9652_fs48 (1<<4) /* sample rate is 0=44.1/88.2,1=48/96 Khz */
#define RME9652_wsel_rd (1<<5) /* if Word-Clock is used and valid then 1 */
/* bits 6-15 encode h/w buffer pointer position */
#define RME9652_sync_2 (1<<16) /* if ADAT-IN 3 in sync to system clock */
#define RME9652_sync_1 (1<<17) /* if ADAT-IN 2 in sync to system clock */
#define RME9652_sync_0 (1<<18) /* if ADAT-IN 1 in sync to system clock */
#define RME9652_DS_rd (1<<19) /* 1=Double Speed Mode, 0=Normal Speed */
#define RME9652_tc_busy (1<<20) /* 1=time-code copy in progress (960ms) */
#define RME9652_tc_out (1<<21) /* time-code out bit */
#define RME9652_F_0 (1<<22) /* 000=64kHz, 100=88.2kHz, 011=96kHz */
#define RME9652_F_1 (1<<23) /* 111=32kHz, 110=44.1kHz, 101=48kHz, */
#define RME9652_F_2 (1<<24) /* external Crystal Chip if ERF=1 */
#define RME9652_ERF (1<<25) /* Error-Flag of SDPIF Receiver (1=No Lock) */
#define RME9652_buffer_id (1<<26) /* toggles by each interrupt on rec/play */
#define RME9652_tc_valid (1<<27) /* 1 = a signal is detected on time-code input */
#define RME9652_SPDIF_READ (1<<28) /* byte available from Rev 1.5+ S/PDIF interface */
#define RME9652_sync (RME9652_sync_0|RME9652_sync_1|RME9652_sync_2)
#define RME9652_lock (RME9652_lock_0|RME9652_lock_1|RME9652_lock_2)
#define RME9652_F (RME9652_F_0|RME9652_F_1|RME9652_F_2)
#define rme9652_decode_spdif_rate(x) ((x)>>22)
/* Bit 6..15 : h/w buffer pointer */
#define RME9652_buf_pos 0x000FFC0
/* Bits 31,30,29 are bits 5,4,3 of h/w pointer position on later
Rev G EEPROMS and Rev 1.5 cards or later.
*/
#define RME9652_REV15_buf_pos(x) ((((x)&0xE0000000)>>26)|((x)&RME9652_buf_pos))
/* amount of io space we remap for register access. i'm not sure we
even need this much, but 1K is nice round number :)
*/
#define RME9652_IO_EXTENT 1024
#define RME9652_init_buffer 0
#define RME9652_play_buffer 32 /* holds ptr to 26x64kBit host RAM */
#define RME9652_rec_buffer 36 /* holds ptr to 26x64kBit host RAM */
#define RME9652_control_register 64
#define RME9652_irq_clear 96
#define RME9652_time_code 100 /* useful if used with alesis adat */
#define RME9652_thru_base 128 /* 132...228 Thru for 26 channels */
/* Read-only registers */
/* Writing to any of the register locations writes to the status
register. We'll use the first location as our point of access.
*/
#define RME9652_status_register 0
/* --------- Control-Register Bits ---------------- */
#define RME9652_start_bit (1<<0) /* start record/play */
/* bits 1-3 encode buffersize/latency */
#define RME9652_Master (1<<4) /* Clock Mode Master=1,Slave/Auto=0 */
#define RME9652_IE (1<<5) /* Interrupt Enable */
#define RME9652_freq (1<<6) /* samplerate 0=44.1/88.2, 1=48/96 kHz */
#define RME9652_freq1 (1<<7) /* if 0, 32kHz, else always 1 */
#define RME9652_DS (1<<8) /* Doule Speed 0=44.1/48, 1=88.2/96 Khz */
#define RME9652_PRO (1<<9) /* S/PDIF out: 0=consumer, 1=professional */
#define RME9652_EMP (1<<10) /* Emphasis 0=None, 1=ON */
#define RME9652_Dolby (1<<11) /* Non-audio bit 1=set, 0=unset */
#define RME9652_opt_out (1<<12) /* Use 1st optical OUT as SPDIF: 1=yes,0=no */
#define RME9652_wsel (1<<13) /* use Wordclock as sync (overwrites master) */
#define RME9652_inp_0 (1<<14) /* SPDIF-IN: 00=optical (ADAT1), */
#define RME9652_inp_1 (1<<15) /* 01=koaxial (Cinch), 10=Internal CDROM */
#define RME9652_SyncPref_ADAT2 (1<<16)
#define RME9652_SyncPref_ADAT3 (1<<17)
#define RME9652_SPDIF_RESET (1<<18) /* Rev 1.5+: h/w S/PDIF receiver */
#define RME9652_SPDIF_SELECT (1<<19)
#define RME9652_SPDIF_CLOCK (1<<20)
#define RME9652_SPDIF_WRITE (1<<21)
#define RME9652_ADAT1_INTERNAL (1<<22) /* Rev 1.5+: if set, internal CD connector carries ADAT */
/* buffersize = 512Bytes * 2^n, where n is made from Bit2 ... Bit0 */
#define RME9652_latency 0x0e
#define rme9652_encode_latency(x) (((x)&0x7)<<1)
#define rme9652_decode_latency(x) (((x)>>1)&0x7)
#define rme9652_running_double_speed(s) ((s)->control_register & RME9652_DS)
#define RME9652_inp (RME9652_inp_0|RME9652_inp_1)
#define rme9652_encode_spdif_in(x) (((x)&0x3)<<14)
#define rme9652_decode_spdif_in(x) (((x)>>14)&0x3)
#define RME9652_SyncPref_Mask (RME9652_SyncPref_ADAT2|RME9652_SyncPref_ADAT3)
#define RME9652_SyncPref_ADAT1 0
#define RME9652_SyncPref_SPDIF (RME9652_SyncPref_ADAT2|RME9652_SyncPref_ADAT3)
/* the size of a substream (1 mono data stream) */
#define RME9652_CHANNEL_BUFFER_SAMPLES (16*1024)
#define RME9652_CHANNEL_BUFFER_BYTES (4*RME9652_CHANNEL_BUFFER_SAMPLES)
/* the size of the area we need to allocate for DMA transfers. the
size is the same regardless of the number of channels - the
9636 still uses the same memory area.
Note that we allocate 1 more channel than is apparently needed
because the h/w seems to write 1 byte beyond the end of the last
page. Sigh.
*/
#define RME9652_DMA_AREA_BYTES ((RME9652_NCHANNELS+1) * RME9652_CHANNEL_BUFFER_BYTES)
#define RME9652_DMA_AREA_KILOBYTES (RME9652_DMA_AREA_BYTES/1024)
struct snd_rme9652 {
int dev;
spinlock_t lock;
int irq;
unsigned long port;
void __iomem *iobase;
int precise_ptr;
u32 control_register; /* cached value */
u32 thru_bits; /* thru 1=on, 0=off channel 1=Bit1... channel 26= Bit26 */
u32 creg_spdif;
u32 creg_spdif_stream;
char *card_name; /* hammerfall or hammerfall light names */
size_t hw_offsetmask; /* &-with status register to get real hw_offset */
size_t prev_hw_offset; /* previous hw offset */
size_t max_jitter; /* maximum jitter in frames for
hw pointer */
size_t period_bytes; /* guess what this is */
unsigned char ds_channels;
unsigned char ss_channels; /* different for hammerfall/hammerfall-light */
struct snd_dma_buffer playback_dma_buf;
struct snd_dma_buffer capture_dma_buf;
unsigned char *capture_buffer; /* suitably aligned address */
unsigned char *playback_buffer; /* suitably aligned address */
pid_t capture_pid;
pid_t playback_pid;
struct snd_pcm_substream *capture_substream;
struct snd_pcm_substream *playback_substream;
int running;
int passthru; /* non-zero if doing pass-thru */
int hw_rev; /* h/w rev * 10 (i.e. 1.5 has hw_rev = 15) */
int last_spdif_sample_rate; /* so that we can catch externally ... */
int last_adat_sample_rate; /* ... induced rate changes */
char *channel_map;
struct snd_card *card;
struct snd_pcm *pcm;
struct pci_dev *pci;
struct snd_kcontrol *spdif_ctl;
};
/* These tables map the ALSA channels 1..N to the channels that we
need to use in order to find the relevant channel buffer. RME
refer to this kind of mapping as between "the ADAT channel and
the DMA channel." We index it using the logical audio channel,
and the value is the DMA channel (i.e. channel buffer number)
where the data for that channel can be read/written from/to.
*/
static char channel_map_9652_ss[26] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25
};
static char channel_map_9636_ss[26] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
/* channels 16 and 17 are S/PDIF */
24, 25,
/* channels 18-25 don't exist */
-1, -1, -1, -1, -1, -1, -1, -1
};
static char channel_map_9652_ds[26] = {
/* ADAT channels are remapped */
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23,
/* channels 12 and 13 are S/PDIF */
24, 25,
/* others don't exist */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
static char channel_map_9636_ds[26] = {
/* ADAT channels are remapped */
1, 3, 5, 7, 9, 11, 13, 15,
/* channels 8 and 9 are S/PDIF */
24, 25,
/* others don't exist */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer *dmab, size_t size)
{
dmab->dev.type = SNDRV_DMA_TYPE_DEV;
dmab->dev.dev = snd_dma_pci_data(pci);
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
size, dmab) < 0)
return -ENOMEM;
return 0;
}
static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci)
{
if (dmab->area)
snd_dma_free_pages(dmab);
}
static const struct pci_device_id snd_rme9652_ids[] = {
{
.vendor = 0x10ee,
.device = 0x3fc4,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
}, /* RME Digi9652 */
{ 0, },
};
MODULE_DEVICE_TABLE(pci, snd_rme9652_ids);
static inline void rme9652_write(struct snd_rme9652 *rme9652, int reg, int val)
{
writel(val, rme9652->iobase + reg);
}
static inline unsigned int rme9652_read(struct snd_rme9652 *rme9652, int reg)
{
return readl(rme9652->iobase + reg);
}
static inline int snd_rme9652_use_is_exclusive(struct snd_rme9652 *rme9652)
{
unsigned long flags;
int ret = 1;
spin_lock_irqsave(&rme9652->lock, flags);
if ((rme9652->playback_pid != rme9652->capture_pid) &&
(rme9652->playback_pid >= 0) && (rme9652->capture_pid >= 0)) {
ret = 0;
}
spin_unlock_irqrestore(&rme9652->lock, flags);
return ret;
}
static inline int rme9652_adat_sample_rate(struct snd_rme9652 *rme9652)
{
if (rme9652_running_double_speed(rme9652)) {
return (rme9652_read(rme9652, RME9652_status_register) &
RME9652_fs48) ? 96000 : 88200;
} else {
return (rme9652_read(rme9652, RME9652_status_register) &
RME9652_fs48) ? 48000 : 44100;
}
}
static inline void rme9652_compute_period_size(struct snd_rme9652 *rme9652)
{
unsigned int i;
i = rme9652->control_register & RME9652_latency;
rme9652->period_bytes = 1 << ((rme9652_decode_latency(i) + 8));
rme9652->hw_offsetmask =
(rme9652->period_bytes * 2 - 1) & RME9652_buf_pos;
rme9652->max_jitter = 80;
}
static snd_pcm_uframes_t rme9652_hw_pointer(struct snd_rme9652 *rme9652)
{
int status;
unsigned int offset, frag;
snd_pcm_uframes_t period_size = rme9652->period_bytes / 4;
snd_pcm_sframes_t delta;
status = rme9652_read(rme9652, RME9652_status_register);
if (!rme9652->precise_ptr)
return (status & RME9652_buffer_id) ? period_size : 0;
offset = status & RME9652_buf_pos;
/* The hardware may give a backward movement for up to 80 frames
Martin Kirst <martin.kirst@freenet.de> knows the details.
*/
delta = rme9652->prev_hw_offset - offset;
delta &= 0xffff;
if (delta <= (snd_pcm_sframes_t)rme9652->max_jitter * 4)
offset = rme9652->prev_hw_offset;
else
rme9652->prev_hw_offset = offset;
offset &= rme9652->hw_offsetmask;
offset /= 4;
frag = status & RME9652_buffer_id;
if (offset < period_size) {
if (offset > rme9652->max_jitter) {
if (frag)
dev_err(rme9652->card->dev,
"Unexpected hw_pointer position (bufid == 0): status: %x offset: %d\n",
status, offset);
} else if (!frag)
return 0;
offset -= rme9652->max_jitter;
if ((int)offset < 0)
offset += period_size * 2;
} else {
if (offset > period_size + rme9652->max_jitter) {
if (!frag)
dev_err(rme9652->card->dev,
"Unexpected hw_pointer position (bufid == 1): status: %x offset: %d\n",
status, offset);
} else if (frag)
return period_size;
offset -= rme9652->max_jitter;
}
return offset;
}
static inline void rme9652_reset_hw_pointer(struct snd_rme9652 *rme9652)
{
int i;
/* reset the FIFO pointer to zero. We do this by writing to 8
registers, each of which is a 32bit wide register, and set
them all to zero. Note that s->iobase is a pointer to
int32, not pointer to char.
*/
for (i = 0; i < 8; i++) {
rme9652_write(rme9652, i * 4, 0);
udelay(10);
}
rme9652->prev_hw_offset = 0;
}
static inline void rme9652_start(struct snd_rme9652 *s)
{
s->control_register |= (RME9652_IE | RME9652_start_bit);
rme9652_write(s, RME9652_control_register, s->control_register);
}
static inline void rme9652_stop(struct snd_rme9652 *s)
{
s->control_register &= ~(RME9652_start_bit | RME9652_IE);
rme9652_write(s, RME9652_control_register, s->control_register);
}
static int rme9652_set_interrupt_interval(struct snd_rme9652 *s,
unsigned int frames)
{
int restart = 0;
int n;
spin_lock_irq(&s->lock);
if ((restart = s->running)) {
rme9652_stop(s);
}
frames >>= 7;
n = 0;
while (frames) {
n++;
frames >>= 1;
}
s->control_register &= ~RME9652_latency;
s->control_register |= rme9652_encode_latency(n);
rme9652_write(s, RME9652_control_register, s->control_register);
rme9652_compute_period_size(s);
if (restart)
rme9652_start(s);
spin_unlock_irq(&s->lock);
return 0;
}
static int rme9652_set_rate(struct snd_rme9652 *rme9652, int rate)
{
int restart;
int reject_if_open = 0;
int xrate;
if (!snd_rme9652_use_is_exclusive (rme9652)) {
return -EBUSY;
}
/* Changing from a "single speed" to a "double speed" rate is
not allowed if any substreams are open. This is because
such a change causes a shift in the location of
the DMA buffers and a reduction in the number of available
buffers.
Note that a similar but essentially insoluble problem
exists for externally-driven rate changes. All we can do
is to flag rate changes in the read/write routines.
*/
spin_lock_irq(&rme9652->lock);
xrate = rme9652_adat_sample_rate(rme9652);
switch (rate) {
case 44100:
if (xrate > 48000) {
reject_if_open = 1;
}
rate = 0;
break;
case 48000:
if (xrate > 48000) {
reject_if_open = 1;
}
rate = RME9652_freq;
break;
case 88200:
if (xrate < 48000) {
reject_if_open = 1;
}
rate = RME9652_DS;
break;
case 96000:
if (xrate < 48000) {
reject_if_open = 1;
}
rate = RME9652_DS | RME9652_freq;
break;
default:
spin_unlock_irq(&rme9652->lock);
return -EINVAL;
}
if (reject_if_open && (rme9652->capture_pid >= 0 || rme9652->playback_pid >= 0)) {
spin_unlock_irq(&rme9652->lock);
return -EBUSY;
}
if ((restart = rme9652->running)) {
rme9652_stop(rme9652);
}
rme9652->control_register &= ~(RME9652_freq | RME9652_DS);
rme9652->control_register |= rate;
rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);
if (restart) {
rme9652_start(rme9652);
}
if (rate & RME9652_DS) {
if (rme9652->ss_channels == RME9652_NCHANNELS) {
rme9652->channel_map = channel_map_9652_ds;
} else {
rme9652->channel_map = channel_map_9636_ds;
}
} else {
if (rme9652->ss_channels == RME9652_NCHANNELS) {
rme9652->channel_map = channel_map_9652_ss;
} else {
rme9652->channel_map = channel_map_9636_ss;
}
}
spin_unlock_irq(&rme9652->lock);
return 0;
}
static void rme9652_set_thru(struct snd_rme9652 *rme9652, int channel, int enable)
{
int i;
rme9652->passthru = 0;
if (channel < 0) {
/* set thru for all channels */
if (enable) {
for (i = 0; i < RME9652_NCHANNELS; i++) {
rme9652->thru_bits |= (1 << i);
rme9652_write(rme9652, RME9652_thru_base + i * 4, 1);
}
} else {
for (i = 0; i < RME9652_NCHANNELS; i++) {
rme9652->thru_bits &= ~(1 << i);
rme9652_write(rme9652, RME9652_thru_base + i * 4, 0);
}
}
} else {
int mapped_channel;
mapped_channel = rme9652->channel_map[channel];
if (enable) {
rme9652->thru_bits |= (1 << mapped_channel);
} else {
rme9652->thru_bits &= ~(1 << mapped_channel);
}
rme9652_write(rme9652,
RME9652_thru_base + mapped_channel * 4,
enable ? 1 : 0);
}
}
static int rme9652_set_passthru(struct snd_rme9652 *rme9652, int onoff)
{
if (onoff) {
rme9652_set_thru(rme9652, -1, 1);
/* we don't want interrupts, so do a
custom version of rme9652_start().
*/
rme9652->control_register =
RME9652_inp_0 |
rme9652_encode_latency(7) |
RME9652_start_bit;
rme9652_reset_hw_pointer(rme9652);
rme9652_write(rme9652, RME9652_control_register,
rme9652->control_register);
rme9652->passthru = 1;
} else {
rme9652_set_thru(rme9652, -1, 0);
rme9652_stop(rme9652);
rme9652->passthru = 0;
}
return 0;
}
static void rme9652_spdif_set_bit (struct snd_rme9652 *rme9652, int mask, int onoff)
{
if (onoff)
rme9652->control_register |= mask;
else
rme9652->control_register &= ~mask;
rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);
}
static void rme9652_spdif_write_byte (struct snd_rme9652 *rme9652, const int val)
{
long mask;
long i;
for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) {
if (val & mask)
rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_WRITE, 1);
else
rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_WRITE, 0);
rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_CLOCK, 1);
rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_CLOCK, 0);
}
}
static int rme9652_spdif_read_byte (struct snd_rme9652 *rme9652)
{
long mask;
long val;
long i;
val = 0;
for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) {
rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_CLOCK, 1);
if (rme9652_read (rme9652, RME9652_status_register) & RME9652_SPDIF_READ)
val |= mask;
rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_CLOCK, 0);
}
return val;
}
static void rme9652_write_spdif_codec (struct snd_rme9652 *rme9652, const int address, const int data)
{
rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 1);
rme9652_spdif_write_byte (rme9652, 0x20);
rme9652_spdif_write_byte (rme9652, address);
rme9652_spdif_write_byte (rme9652, data);
rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 0);
}
static int rme9652_spdif_read_codec (struct snd_rme9652 *rme9652, const int address)
{
int ret;
rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 1);
rme9652_spdif_write_byte (rme9652, 0x20);
rme9652_spdif_write_byte (rme9652, address);
rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 0);
rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 1);
rme9652_spdif_write_byte (rme9652, 0x21);
ret = rme9652_spdif_read_byte (rme9652);
rme9652_spdif_set_bit (rme9652, RME9652_SPDIF_SELECT, 0);
return ret;
}
static void rme9652_initialize_spdif_receiver (struct snd_rme9652 *rme9652)
{
/* XXX what unsets this ? */
rme9652->control_register |= RME9652_SPDIF_RESET;
rme9652_write_spdif_codec (rme9652, 4, 0x40);
rme9652_write_spdif_codec (rme9652, 17, 0x13);
rme9652_write_spdif_codec (rme9652, 6, 0x02);
}
static inline int rme9652_spdif_sample_rate(struct snd_rme9652 *s)
{
unsigned int rate_bits;
if (rme9652_read(s, RME9652_status_register) & RME9652_ERF) {
return -1; /* error condition */
}
if (s->hw_rev == 15) {
int x, y, ret;
x = rme9652_spdif_read_codec (s, 30);
if (x != 0)
y = 48000 * 64 / x;
else
y = 0;
if (y > 30400 && y < 33600) ret = 32000;
else if (y > 41900 && y < 46000) ret = 44100;
else if (y > 46000 && y < 50400) ret = 48000;
else if (y > 60800 && y < 67200) ret = 64000;
else if (y > 83700 && y < 92000) ret = 88200;
else if (y > 92000 && y < 100000) ret = 96000;
else ret = 0;
return ret;
}
rate_bits = rme9652_read(s, RME9652_status_register) & RME9652_F;
switch (rme9652_decode_spdif_rate(rate_bits)) {
case 0x7:
return 32000;
break;
case 0x6:
return 44100;
break;
case 0x5:
return 48000;
break;
case 0x4:
return 88200;
break;
case 0x3:
return 96000;
break;
case 0x0:
return 64000;
break;
default:
dev_err(s->card->dev,
"%s: unknown S/PDIF input rate (bits = 0x%x)\n",
s->card_name, rate_bits);
return 0;
break;
}
}
/*-----------------------------------------------------------------------------
Control Interface
----------------------------------------------------------------------------*/
static u32 snd_rme9652_convert_from_aes(struct snd_aes_iec958 *aes)
{
u32 val = 0;
val |= (aes->status[0] & IEC958_AES0_PROFESSIONAL) ? RME9652_PRO : 0;
val |= (aes->status[0] & IEC958_AES0_NONAUDIO) ? RME9652_Dolby : 0;
if (val & RME9652_PRO)
val |= (aes->status[0] & IEC958_AES0_PRO_EMPHASIS_5015) ? RME9652_EMP : 0;
else
val |= (aes->status[0] & IEC958_AES0_CON_EMPHASIS_5015) ? RME9652_EMP : 0;
return val;
}
static void snd_rme9652_convert_to_aes(struct snd_aes_iec958 *aes, u32 val)
{
aes->status[0] = ((val & RME9652_PRO) ? IEC958_AES0_PROFESSIONAL : 0) |
((val & RME9652_Dolby) ? IEC958_AES0_NONAUDIO : 0);
if (val & RME9652_PRO)
aes->status[0] |= (val & RME9652_EMP) ? IEC958_AES0_PRO_EMPHASIS_5015 : 0;
else
aes->status[0] |= (val & RME9652_EMP) ? IEC958_AES0_CON_EMPHASIS_5015 : 0;
}
static int snd_rme9652_control_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
uinfo->count = 1;
return 0;
}
static int snd_rme9652_control_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
snd_rme9652_convert_to_aes(&ucontrol->value.iec958, rme9652->creg_spdif);
return 0;
}
static int snd_rme9652_control_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
int change;
u32 val;
val = snd_rme9652_convert_from_aes(&ucontrol->value.iec958);
spin_lock_irq(&rme9652->lock);
change = val != rme9652->creg_spdif;
rme9652->creg_spdif = val;
spin_unlock_irq(&rme9652->lock);
return change;
}
static int snd_rme9652_control_spdif_stream_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
uinfo->count = 1;
return 0;
}
static int snd_rme9652_control_spdif_stream_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
snd_rme9652_convert_to_aes(&ucontrol->value.iec958, rme9652->creg_spdif_stream);
return 0;
}
static int snd_rme9652_control_spdif_stream_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
int change;
u32 val;
val = snd_rme9652_convert_from_aes(&ucontrol->value.iec958);
spin_lock_irq(&rme9652->lock);
change = val != rme9652->creg_spdif_stream;
rme9652->creg_spdif_stream = val;
rme9652->control_register &= ~(RME9652_PRO | RME9652_Dolby | RME9652_EMP);
rme9652_write(rme9652, RME9652_control_register, rme9652->control_register |= val);
spin_unlock_irq(&rme9652->lock);
return change;
}
static int snd_rme9652_control_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
uinfo->count = 1;
return 0;
}
static int snd_rme9652_control_spdif_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.iec958.status[0] = kcontrol->private_value;
return 0;
}
#define RME9652_ADAT1_IN(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_adat1_in, \
.get = snd_rme9652_get_adat1_in, \
.put = snd_rme9652_put_adat1_in }
static unsigned int rme9652_adat1_in(struct snd_rme9652 *rme9652)
{
if (rme9652->control_register & RME9652_ADAT1_INTERNAL)
return 1;
return 0;
}
static int rme9652_set_adat1_input(struct snd_rme9652 *rme9652, int internal)
{
int restart = 0;
if (internal) {
rme9652->control_register |= RME9652_ADAT1_INTERNAL;
} else {
rme9652->control_register &= ~RME9652_ADAT1_INTERNAL;
}
/* XXX do we actually need to stop the card when we do this ? */
if ((restart = rme9652->running)) {
rme9652_stop(rme9652);
}
rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);
if (restart) {
rme9652_start(rme9652);
}
return 0;
}
static int snd_rme9652_info_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
static const char * const texts[2] = {"ADAT1", "Internal"};
return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_rme9652_get_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
spin_lock_irq(&rme9652->lock);
ucontrol->value.enumerated.item[0] = rme9652_adat1_in(rme9652);
spin_unlock_irq(&rme9652->lock);
return 0;
}
static int snd_rme9652_put_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
int change;
unsigned int val;
if (!snd_rme9652_use_is_exclusive(rme9652))
return -EBUSY;
val = ucontrol->value.enumerated.item[0] % 2;
spin_lock_irq(&rme9652->lock);
change = val != rme9652_adat1_in(rme9652);
if (change)
rme9652_set_adat1_input(rme9652, val);
spin_unlock_irq(&rme9652->lock);
return change;
}
#define RME9652_SPDIF_IN(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_spdif_in, \
.get = snd_rme9652_get_spdif_in, .put = snd_rme9652_put_spdif_in }
static unsigned int rme9652_spdif_in(struct snd_rme9652 *rme9652)
{
return rme9652_decode_spdif_in(rme9652->control_register &
RME9652_inp);
}
static int rme9652_set_spdif_input(struct snd_rme9652 *rme9652, int in)
{
int restart = 0;
rme9652->control_register &= ~RME9652_inp;
rme9652->control_register |= rme9652_encode_spdif_in(in);
if ((restart = rme9652->running)) {
rme9652_stop(rme9652);
}
rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);
if (restart) {
rme9652_start(rme9652);
}
return 0;
}
static int snd_rme9652_info_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
static const char * const texts[3] = {"ADAT1", "Coaxial", "Internal"};
return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_rme9652_get_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
spin_lock_irq(&rme9652->lock);
ucontrol->value.enumerated.item[0] = rme9652_spdif_in(rme9652);
spin_unlock_irq(&rme9652->lock);
return 0;
}
static int snd_rme9652_put_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
int change;
unsigned int val;
if (!snd_rme9652_use_is_exclusive(rme9652))
return -EBUSY;
val = ucontrol->value.enumerated.item[0] % 3;
spin_lock_irq(&rme9652->lock);
change = val != rme9652_spdif_in(rme9652);
if (change)
rme9652_set_spdif_input(rme9652, val);
spin_unlock_irq(&rme9652->lock);
return change;
}
#define RME9652_SPDIF_OUT(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_spdif_out, \
.get = snd_rme9652_get_spdif_out, .put = snd_rme9652_put_spdif_out }
static int rme9652_spdif_out(struct snd_rme9652 *rme9652)
{
return (rme9652->control_register & RME9652_opt_out) ? 1 : 0;
}
static int rme9652_set_spdif_output(struct snd_rme9652 *rme9652, int out)
{
int restart = 0;
if (out) {
rme9652->control_register |= RME9652_opt_out;
} else {
rme9652->control_register &= ~RME9652_opt_out;
}
if ((restart = rme9652->running)) {
rme9652_stop(rme9652);
}
rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);
if (restart) {
rme9652_start(rme9652);
}
return 0;
}
#define snd_rme9652_info_spdif_out snd_ctl_boolean_mono_info
static int snd_rme9652_get_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
spin_lock_irq(&rme9652->lock);
ucontrol->value.integer.value[0] = rme9652_spdif_out(rme9652);
spin_unlock_irq(&rme9652->lock);
return 0;
}
static int snd_rme9652_put_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
int change;
unsigned int val;
if (!snd_rme9652_use_is_exclusive(rme9652))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
spin_lock_irq(&rme9652->lock);
change = (int)val != rme9652_spdif_out(rme9652);
rme9652_set_spdif_output(rme9652, val);
spin_unlock_irq(&rme9652->lock);
return change;
}
#define RME9652_SYNC_MODE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_sync_mode, \
.get = snd_rme9652_get_sync_mode, .put = snd_rme9652_put_sync_mode }
static int rme9652_sync_mode(struct snd_rme9652 *rme9652)
{
if (rme9652->control_register & RME9652_wsel) {
return 2;
} else if (rme9652->control_register & RME9652_Master) {
return 1;
} else {
return 0;
}
}
static int rme9652_set_sync_mode(struct snd_rme9652 *rme9652, int mode)
{
int restart = 0;
switch (mode) {
case 0:
rme9652->control_register &=
~(RME9652_Master | RME9652_wsel);
break;
case 1:
rme9652->control_register =
(rme9652->control_register & ~RME9652_wsel) | RME9652_Master;
break;
case 2:
rme9652->control_register |=
(RME9652_Master | RME9652_wsel);
break;
}
if ((restart = rme9652->running)) {
rme9652_stop(rme9652);
}
rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);
if (restart) {
rme9652_start(rme9652);
}
return 0;
}
static int snd_rme9652_info_sync_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
static const char * const texts[3] = {
"AutoSync", "Master", "Word Clock"
};
return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_rme9652_get_sync_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
spin_lock_irq(&rme9652->lock);
ucontrol->value.enumerated.item[0] = rme9652_sync_mode(rme9652);
spin_unlock_irq(&rme9652->lock);
return 0;
}
static int snd_rme9652_put_sync_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
int change;
unsigned int val;
val = ucontrol->value.enumerated.item[0] % 3;
spin_lock_irq(&rme9652->lock);
change = (int)val != rme9652_sync_mode(rme9652);
rme9652_set_sync_mode(rme9652, val);
spin_unlock_irq(&rme9652->lock);
return change;
}
#define RME9652_SYNC_PREF(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_sync_pref, \
.get = snd_rme9652_get_sync_pref, .put = snd_rme9652_put_sync_pref }
static int rme9652_sync_pref(struct snd_rme9652 *rme9652)
{
switch (rme9652->control_register & RME9652_SyncPref_Mask) {
case RME9652_SyncPref_ADAT1:
return RME9652_SYNC_FROM_ADAT1;
case RME9652_SyncPref_ADAT2:
return RME9652_SYNC_FROM_ADAT2;
case RME9652_SyncPref_ADAT3:
return RME9652_SYNC_FROM_ADAT3;
case RME9652_SyncPref_SPDIF:
return RME9652_SYNC_FROM_SPDIF;
}
/* Not reachable */
return 0;
}
static int rme9652_set_sync_pref(struct snd_rme9652 *rme9652, int pref)
{
int restart;
rme9652->control_register &= ~RME9652_SyncPref_Mask;
switch (pref) {
case RME9652_SYNC_FROM_ADAT1:
rme9652->control_register |= RME9652_SyncPref_ADAT1;
break;
case RME9652_SYNC_FROM_ADAT2:
rme9652->control_register |= RME9652_SyncPref_ADAT2;
break;
case RME9652_SYNC_FROM_ADAT3:
rme9652->control_register |= RME9652_SyncPref_ADAT3;
break;
case RME9652_SYNC_FROM_SPDIF:
rme9652->control_register |= RME9652_SyncPref_SPDIF;
break;
}
if ((restart = rme9652->running)) {
rme9652_stop(rme9652);
}
rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);
if (restart) {
rme9652_start(rme9652);
}
return 0;
}
static int snd_rme9652_info_sync_pref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
static const char * const texts[4] = {
"IEC958 In", "ADAT1 In", "ADAT2 In", "ADAT3 In"
};
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
return snd_ctl_enum_info(uinfo, 1,
rme9652->ss_channels == RME9652_NCHANNELS ? 4 : 3,
texts);
}
static int snd_rme9652_get_sync_pref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
spin_lock_irq(&rme9652->lock);
ucontrol->value.enumerated.item[0] = rme9652_sync_pref(rme9652);
spin_unlock_irq(&rme9652->lock);
return 0;
}
static int snd_rme9652_put_sync_pref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
int change, max;
unsigned int val;
if (!snd_rme9652_use_is_exclusive(rme9652))
return -EBUSY;
max = rme9652->ss_channels == RME9652_NCHANNELS ? 4 : 3;
val = ucontrol->value.enumerated.item[0] % max;
spin_lock_irq(&rme9652->lock);
change = (int)val != rme9652_sync_pref(rme9652);
rme9652_set_sync_pref(rme9652, val);
spin_unlock_irq(&rme9652->lock);
return change;
}
static int snd_rme9652_info_thru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = rme9652->ss_channels;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
return 0;
}
static int snd_rme9652_get_thru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
unsigned int k;
u32 thru_bits = rme9652->thru_bits;
for (k = 0; k < rme9652->ss_channels; ++k) {
ucontrol->value.integer.value[k] = !!(thru_bits & (1 << k));
}
return 0;
}
static int snd_rme9652_put_thru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
int change;
unsigned int chn;
u32 thru_bits = 0;
if (!snd_rme9652_use_is_exclusive(rme9652))
return -EBUSY;
for (chn = 0; chn < rme9652->ss_channels; ++chn) {
if (ucontrol->value.integer.value[chn])
thru_bits |= 1 << chn;
}
spin_lock_irq(&rme9652->lock);
change = thru_bits ^ rme9652->thru_bits;
if (change) {
for (chn = 0; chn < rme9652->ss_channels; ++chn) {
if (!(change & (1 << chn)))
continue;
rme9652_set_thru(rme9652,chn,thru_bits&(1<<chn));
}
}
spin_unlock_irq(&rme9652->lock);
return !!change;
}
#define RME9652_PASSTHRU(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_passthru, \
.put = snd_rme9652_put_passthru, \
.get = snd_rme9652_get_passthru }
#define snd_rme9652_info_passthru snd_ctl_boolean_mono_info
static int snd_rme9652_get_passthru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
spin_lock_irq(&rme9652->lock);
ucontrol->value.integer.value[0] = rme9652->passthru;
spin_unlock_irq(&rme9652->lock);
return 0;
}
static int snd_rme9652_put_passthru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
int change;
unsigned int val;
int err = 0;
if (!snd_rme9652_use_is_exclusive(rme9652))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
spin_lock_irq(&rme9652->lock);
change = (ucontrol->value.integer.value[0] != rme9652->passthru);
if (change)
err = rme9652_set_passthru(rme9652, val);
spin_unlock_irq(&rme9652->lock);
return err ? err : change;
}
/* Read-only switches */
#define RME9652_SPDIF_RATE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.info = snd_rme9652_info_spdif_rate, \
.get = snd_rme9652_get_spdif_rate }
static int snd_rme9652_info_spdif_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 96000;
return 0;
}
static int snd_rme9652_get_spdif_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
spin_lock_irq(&rme9652->lock);
ucontrol->value.integer.value[0] = rme9652_spdif_sample_rate(rme9652);
spin_unlock_irq(&rme9652->lock);
return 0;
}
#define RME9652_ADAT_SYNC(xname, xindex, xidx) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.info = snd_rme9652_info_adat_sync, \
.get = snd_rme9652_get_adat_sync, .private_value = xidx }
static int snd_rme9652_info_adat_sync(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
static const char * const texts[4] = {
"No Lock", "Lock", "No Lock Sync", "Lock Sync"
};
return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int snd_rme9652_get_adat_sync(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
unsigned int mask1, mask2, val;
switch (kcontrol->private_value) {
case 0: mask1 = RME9652_lock_0; mask2 = RME9652_sync_0; break;
case 1: mask1 = RME9652_lock_1; mask2 = RME9652_sync_1; break;
case 2: mask1 = RME9652_lock_2; mask2 = RME9652_sync_2; break;
default: return -EINVAL;
}
val = rme9652_read(rme9652, RME9652_status_register);
ucontrol->value.enumerated.item[0] = (val & mask1) ? 1 : 0;
ucontrol->value.enumerated.item[0] |= (val & mask2) ? 2 : 0;
return 0;
}
#define RME9652_TC_VALID(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.info = snd_rme9652_info_tc_valid, \
.get = snd_rme9652_get_tc_valid }
#define snd_rme9652_info_tc_valid snd_ctl_boolean_mono_info
static int snd_rme9652_get_tc_valid(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] =
(rme9652_read(rme9652, RME9652_status_register) & RME9652_tc_valid) ? 1 : 0;
return 0;
}
#ifdef ALSA_HAS_STANDARD_WAY_OF_RETURNING_TIMECODE
/* FIXME: this routine needs a port to the new control API --jk */
static int snd_rme9652_get_tc_value(void *private_data,
snd_kswitch_t *kswitch,
snd_switch_t *uswitch)
{
struct snd_rme9652 *s = (struct snd_rme9652 *) private_data;
u32 value;
int i;
uswitch->type = SNDRV_SW_TYPE_DWORD;
if ((rme9652_read(s, RME9652_status_register) &
RME9652_tc_valid) == 0) {
uswitch->value.data32[0] = 0;
return 0;
}
/* timecode request */
rme9652_write(s, RME9652_time_code, 0);
/* XXX bug alert: loop-based timing !!!! */
for (i = 0; i < 50; i++) {
if (!(rme9652_read(s, i * 4) & RME9652_tc_busy))
break;
}
if (!(rme9652_read(s, i * 4) & RME9652_tc_busy)) {
return -EIO;
}
value = 0;
for (i = 0; i < 32; i++) {
value >>= 1;
if (rme9652_read(s, i * 4) & RME9652_tc_out)
value |= 0x80000000;
}
if (value > 2 * 60 * 48000) {
value -= 2 * 60 * 48000;
} else {
value = 0;
}
uswitch->value.data32[0] = value;
return 0;
}
#endif /* ALSA_HAS_STANDARD_WAY_OF_RETURNING_TIMECODE */
static struct snd_kcontrol_new snd_rme9652_controls[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.info = snd_rme9652_control_spdif_info,
.get = snd_rme9652_control_spdif_get,
.put = snd_rme9652_control_spdif_put,
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
.info = snd_rme9652_control_spdif_stream_info,
.get = snd_rme9652_control_spdif_stream_get,
.put = snd_rme9652_control_spdif_stream_put,
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
.info = snd_rme9652_control_spdif_mask_info,
.get = snd_rme9652_control_spdif_mask_get,
.private_value = IEC958_AES0_NONAUDIO |
IEC958_AES0_PROFESSIONAL |
IEC958_AES0_CON_EMPHASIS,
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
.info = snd_rme9652_control_spdif_mask_info,
.get = snd_rme9652_control_spdif_mask_get,
.private_value = IEC958_AES0_NONAUDIO |
IEC958_AES0_PROFESSIONAL |
IEC958_AES0_PRO_EMPHASIS,
},
RME9652_SPDIF_IN("IEC958 Input Connector", 0),
RME9652_SPDIF_OUT("IEC958 Output also on ADAT1", 0),
RME9652_SYNC_MODE("Sync Mode", 0),
RME9652_SYNC_PREF("Preferred Sync Source", 0),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Channels Thru",
.index = 0,
.info = snd_rme9652_info_thru,
.get = snd_rme9652_get_thru,
.put = snd_rme9652_put_thru,
},
RME9652_SPDIF_RATE("IEC958 Sample Rate", 0),
RME9652_ADAT_SYNC("ADAT1 Sync Check", 0, 0),
RME9652_ADAT_SYNC("ADAT2 Sync Check", 0, 1),
RME9652_TC_VALID("Timecode Valid", 0),
RME9652_PASSTHRU("Passthru", 0)
};
static struct snd_kcontrol_new snd_rme9652_adat3_check =
RME9652_ADAT_SYNC("ADAT3 Sync Check", 0, 2);
static struct snd_kcontrol_new snd_rme9652_adat1_input =
RME9652_ADAT1_IN("ADAT1 Input Source", 0);
static int snd_rme9652_create_controls(struct snd_card *card, struct snd_rme9652 *rme9652)
{
unsigned int idx;
int err;
struct snd_kcontrol *kctl;
for (idx = 0; idx < ARRAY_SIZE(snd_rme9652_controls); idx++) {
if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme9652_controls[idx], rme9652))) < 0)
return err;
if (idx == 1) /* IEC958 (S/PDIF) Stream */
rme9652->spdif_ctl = kctl;
}
if (rme9652->ss_channels == RME9652_NCHANNELS)
if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme9652_adat3_check, rme9652))) < 0)
return err;
if (rme9652->hw_rev >= 15)
if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme9652_adat1_input, rme9652))) < 0)
return err;
return 0;
}
/*------------------------------------------------------------
/proc interface
------------------------------------------------------------*/
static void
snd_rme9652_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
struct snd_rme9652 *rme9652 = (struct snd_rme9652 *) entry->private_data;
u32 thru_bits = rme9652->thru_bits;
int show_auto_sync_source = 0;
int i;
unsigned int status;
int x;
status = rme9652_read(rme9652, RME9652_status_register);
snd_iprintf(buffer, "%s (Card #%d)\n", rme9652->card_name, rme9652->card->number + 1);
snd_iprintf(buffer, "Buffers: capture %p playback %p\n",
rme9652->capture_buffer, rme9652->playback_buffer);
snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
rme9652->irq, rme9652->port, (unsigned long)rme9652->iobase);
snd_iprintf(buffer, "Control register: %x\n", rme9652->control_register);
snd_iprintf(buffer, "\n");
x = 1 << (6 + rme9652_decode_latency(rme9652->control_register &
RME9652_latency));
snd_iprintf(buffer, "Latency: %d samples (2 periods of %lu bytes)\n",
x, (unsigned long) rme9652->period_bytes);
snd_iprintf(buffer, "Hardware pointer (frames): %ld\n",
rme9652_hw_pointer(rme9652));
snd_iprintf(buffer, "Passthru: %s\n",
rme9652->passthru ? "yes" : "no");
if ((rme9652->control_register & (RME9652_Master | RME9652_wsel)) == 0) {
snd_iprintf(buffer, "Clock mode: autosync\n");
show_auto_sync_source = 1;
} else if (rme9652->control_register & RME9652_wsel) {
if (status & RME9652_wsel_rd) {
snd_iprintf(buffer, "Clock mode: word clock\n");
} else {
snd_iprintf(buffer, "Clock mode: word clock (no signal)\n");
}
} else {
snd_iprintf(buffer, "Clock mode: master\n");
}
if (show_auto_sync_source) {
switch (rme9652->control_register & RME9652_SyncPref_Mask) {
case RME9652_SyncPref_ADAT1:
snd_iprintf(buffer, "Pref. sync source: ADAT1\n");
break;
case RME9652_SyncPref_ADAT2:
snd_iprintf(buffer, "Pref. sync source: ADAT2\n");
break;
case RME9652_SyncPref_ADAT3:
snd_iprintf(buffer, "Pref. sync source: ADAT3\n");
break;
case RME9652_SyncPref_SPDIF:
snd_iprintf(buffer, "Pref. sync source: IEC958\n");
break;
default:
snd_iprintf(buffer, "Pref. sync source: ???\n");
}
}
if (rme9652->hw_rev >= 15)
snd_iprintf(buffer, "\nADAT1 Input source: %s\n",
(rme9652->control_register & RME9652_ADAT1_INTERNAL) ?
"Internal" : "ADAT1 optical");
snd_iprintf(buffer, "\n");
switch (rme9652_decode_spdif_in(rme9652->control_register &
RME9652_inp)) {
case RME9652_SPDIFIN_OPTICAL:
snd_iprintf(buffer, "IEC958 input: ADAT1\n");
break;
case RME9652_SPDIFIN_COAXIAL:
snd_iprintf(buffer, "IEC958 input: Coaxial\n");
break;
case RME9652_SPDIFIN_INTERN:
snd_iprintf(buffer, "IEC958 input: Internal\n");
break;
default:
snd_iprintf(buffer, "IEC958 input: ???\n");
break;
}
if (rme9652->control_register & RME9652_opt_out) {
snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n");
} else {
snd_iprintf(buffer, "IEC958 output: Coaxial only\n");
}
if (rme9652->control_register & RME9652_PRO) {
snd_iprintf(buffer, "IEC958 quality: Professional\n");
} else {
snd_iprintf(buffer, "IEC958 quality: Consumer\n");
}
if (rme9652->control_register & RME9652_EMP) {
snd_iprintf(buffer, "IEC958 emphasis: on\n");
} else {
snd_iprintf(buffer, "IEC958 emphasis: off\n");
}
if (rme9652->control_register & RME9652_Dolby) {
snd_iprintf(buffer, "IEC958 Dolby: on\n");
} else {
snd_iprintf(buffer, "IEC958 Dolby: off\n");
}
i = rme9652_spdif_sample_rate(rme9652);
if (i < 0) {
snd_iprintf(buffer,
"IEC958 sample rate: error flag set\n");
} else if (i == 0) {
snd_iprintf(buffer, "IEC958 sample rate: undetermined\n");
} else {
snd_iprintf(buffer, "IEC958 sample rate: %d\n", i);
}
snd_iprintf(buffer, "\n");
snd_iprintf(buffer, "ADAT Sample rate: %dHz\n",
rme9652_adat_sample_rate(rme9652));
/* Sync Check */
x = status & RME9652_sync_0;
if (status & RME9652_lock_0) {
snd_iprintf(buffer, "ADAT1: %s\n", x ? "Sync" : "Lock");
} else {
snd_iprintf(buffer, "ADAT1: No Lock\n");
}
x = status & RME9652_sync_1;
if (status & RME9652_lock_1) {
snd_iprintf(buffer, "ADAT2: %s\n", x ? "Sync" : "Lock");
} else {
snd_iprintf(buffer, "ADAT2: No Lock\n");
}
x = status & RME9652_sync_2;
if (status & RME9652_lock_2) {
snd_iprintf(buffer, "ADAT3: %s\n", x ? "Sync" : "Lock");
} else {
snd_iprintf(buffer, "ADAT3: No Lock\n");
}
snd_iprintf(buffer, "\n");
snd_iprintf(buffer, "Timecode signal: %s\n",
(status & RME9652_tc_valid) ? "yes" : "no");
/* thru modes */
snd_iprintf(buffer, "Punch Status:\n\n");
for (i = 0; i < rme9652->ss_channels; i++) {
if (thru_bits & (1 << i)) {
snd_iprintf(buffer, "%2d: on ", i + 1);
} else {
snd_iprintf(buffer, "%2d: off ", i + 1);
}
if (((i + 1) % 8) == 0) {
snd_iprintf(buffer, "\n");
}
}
snd_iprintf(buffer, "\n");
}
static void snd_rme9652_proc_init(struct snd_rme9652 *rme9652)
{
struct snd_info_entry *entry;
if (! snd_card_proc_new(rme9652->card, "rme9652", &entry))
snd_info_set_text_ops(entry, rme9652, snd_rme9652_proc_read);
}
static void snd_rme9652_free_buffers(struct snd_rme9652 *rme9652)
{
snd_hammerfall_free_buffer(&rme9652->capture_dma_buf, rme9652->pci);
snd_hammerfall_free_buffer(&rme9652->playback_dma_buf, rme9652->pci);
}
static int snd_rme9652_free(struct snd_rme9652 *rme9652)
{
if (rme9652->irq >= 0)
rme9652_stop(rme9652);
snd_rme9652_free_buffers(rme9652);
if (rme9652->irq >= 0)
free_irq(rme9652->irq, (void *)rme9652);
iounmap(rme9652->iobase);
if (rme9652->port)
pci_release_regions(rme9652->pci);
if (pci_is_enabled(rme9652->pci))
pci_disable_device(rme9652->pci);
return 0;
}
static int snd_rme9652_initialize_memory(struct snd_rme9652 *rme9652)
{
unsigned long pb_bus, cb_bus;
if (snd_hammerfall_get_buffer(rme9652->pci, &rme9652->capture_dma_buf, RME9652_DMA_AREA_BYTES) < 0 ||
snd_hammerfall_get_buffer(rme9652->pci, &rme9652->playback_dma_buf, RME9652_DMA_AREA_BYTES) < 0) {
if (rme9652->capture_dma_buf.area)
snd_dma_free_pages(&rme9652->capture_dma_buf);
dev_err(rme9652->card->dev,
"%s: no buffers available\n", rme9652->card_name);
return -ENOMEM;
}
/* Align to bus-space 64K boundary */
cb_bus = ALIGN(rme9652->capture_dma_buf.addr, 0x10000ul);
pb_bus = ALIGN(rme9652->playback_dma_buf.addr, 0x10000ul);
/* Tell the card where it is */
rme9652_write(rme9652, RME9652_rec_buffer, cb_bus);
rme9652_write(rme9652, RME9652_play_buffer, pb_bus);
rme9652->capture_buffer = rme9652->capture_dma_buf.area + (cb_bus - rme9652->capture_dma_buf.addr);
rme9652->playback_buffer = rme9652->playback_dma_buf.area + (pb_bus - rme9652->playback_dma_buf.addr);
return 0;
}
static void snd_rme9652_set_defaults(struct snd_rme9652 *rme9652)
{
unsigned int k;
/* ASSUMPTION: rme9652->lock is either held, or
there is no need to hold it (e.g. during module
initialization).
*/
/* set defaults:
SPDIF Input via Coax
autosync clock mode
maximum latency (7 = 8192 samples, 64Kbyte buffer,
which implies 2 4096 sample, 32Kbyte periods).
if rev 1.5, initialize the S/PDIF receiver.
*/
rme9652->control_register =
RME9652_inp_0 | rme9652_encode_latency(7);
rme9652_write(rme9652, RME9652_control_register, rme9652->control_register);
rme9652_reset_hw_pointer(rme9652);
rme9652_compute_period_size(rme9652);
/* default: thru off for all channels */
for (k = 0; k < RME9652_NCHANNELS; ++k)
rme9652_write(rme9652, RME9652_thru_base + k * 4, 0);
rme9652->thru_bits = 0;
rme9652->passthru = 0;
/* set a default rate so that the channel map is set up */
rme9652_set_rate(rme9652, 48000);
}
static irqreturn_t snd_rme9652_interrupt(int irq, void *dev_id)
{
struct snd_rme9652 *rme9652 = (struct snd_rme9652 *) dev_id;
if (!(rme9652_read(rme9652, RME9652_status_register) & RME9652_IRQ)) {
return IRQ_NONE;
}
rme9652_write(rme9652, RME9652_irq_clear, 0);
if (rme9652->capture_substream) {
snd_pcm_period_elapsed(rme9652->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
}
if (rme9652->playback_substream) {
snd_pcm_period_elapsed(rme9652->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream);
}
return IRQ_HANDLED;
}
static snd_pcm_uframes_t snd_rme9652_hw_pointer(struct snd_pcm_substream *substream)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
return rme9652_hw_pointer(rme9652);
}
static char *rme9652_channel_buffer_location(struct snd_rme9652 *rme9652,
int stream,
int channel)
{
int mapped_channel;
if (snd_BUG_ON(channel < 0 || channel >= RME9652_NCHANNELS))
return NULL;
if ((mapped_channel = rme9652->channel_map[channel]) < 0) {
return NULL;
}
if (stream == SNDRV_PCM_STREAM_CAPTURE) {
return rme9652->capture_buffer +
(mapped_channel * RME9652_CHANNEL_BUFFER_BYTES);
} else {
return rme9652->playback_buffer +
(mapped_channel * RME9652_CHANNEL_BUFFER_BYTES);
}
}
static int snd_rme9652_playback_copy(struct snd_pcm_substream *substream, int channel,
snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
char *channel_buf;
if (snd_BUG_ON(pos + count > RME9652_CHANNEL_BUFFER_BYTES / 4))
return -EINVAL;
channel_buf = rme9652_channel_buffer_location (rme9652,
substream->pstr->stream,
channel);
if (snd_BUG_ON(!channel_buf))
return -EIO;
if (copy_from_user(channel_buf + pos * 4, src, count * 4))
return -EFAULT;
return count;
}
static int snd_rme9652_capture_copy(struct snd_pcm_substream *substream, int channel,
snd_pcm_uframes_t pos, void __user *dst, snd_pcm_uframes_t count)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
char *channel_buf;
if (snd_BUG_ON(pos + count > RME9652_CHANNEL_BUFFER_BYTES / 4))
return -EINVAL;
channel_buf = rme9652_channel_buffer_location (rme9652,
substream->pstr->stream,
channel);
if (snd_BUG_ON(!channel_buf))
return -EIO;
if (copy_to_user(dst, channel_buf + pos * 4, count * 4))
return -EFAULT;
return count;
}
static int snd_rme9652_hw_silence(struct snd_pcm_substream *substream, int channel,
snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
char *channel_buf;
channel_buf = rme9652_channel_buffer_location (rme9652,
substream->pstr->stream,
channel);
if (snd_BUG_ON(!channel_buf))
return -EIO;
memset(channel_buf + pos * 4, 0, count * 4);
return count;
}
static int snd_rme9652_reset(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
struct snd_pcm_substream *other;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
other = rme9652->capture_substream;
else
other = rme9652->playback_substream;
if (rme9652->running)
runtime->status->hw_ptr = rme9652_hw_pointer(rme9652);
else
runtime->status->hw_ptr = 0;
if (other) {
struct snd_pcm_substream *s;
struct snd_pcm_runtime *oruntime = other->runtime;
snd_pcm_group_for_each_entry(s, substream) {
if (s == other) {
oruntime->status->hw_ptr = runtime->status->hw_ptr;
break;
}
}
}
return 0;
}
static int snd_rme9652_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
int err;
pid_t this_pid;
pid_t other_pid;
spin_lock_irq(&rme9652->lock);
if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) {
rme9652->control_register &= ~(RME9652_PRO | RME9652_Dolby | RME9652_EMP);
rme9652_write(rme9652, RME9652_control_register, rme9652->control_register |= rme9652->creg_spdif_stream);
this_pid = rme9652->playback_pid;
other_pid = rme9652->capture_pid;
} else {
this_pid = rme9652->capture_pid;
other_pid = rme9652->playback_pid;
}
if ((other_pid > 0) && (this_pid != other_pid)) {
/* The other stream is open, and not by the same
task as this one. Make sure that the parameters
that matter are the same.
*/
if ((int)params_rate(params) !=
rme9652_adat_sample_rate(rme9652)) {
spin_unlock_irq(&rme9652->lock);
_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
return -EBUSY;
}
if (params_period_size(params) != rme9652->period_bytes / 4) {
spin_unlock_irq(&rme9652->lock);
_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
return -EBUSY;
}
/* We're fine. */
spin_unlock_irq(&rme9652->lock);
return 0;
} else {
spin_unlock_irq(&rme9652->lock);
}
/* how to make sure that the rate matches an externally-set one ?
*/
if ((err = rme9652_set_rate(rme9652, params_rate(params))) < 0) {
_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
return err;
}
if ((err = rme9652_set_interrupt_interval(rme9652, params_period_size(params))) < 0) {
_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
return err;
}
return 0;
}
static int snd_rme9652_channel_info(struct snd_pcm_substream *substream,
struct snd_pcm_channel_info *info)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
int chn;
if (snd_BUG_ON(info->channel >= RME9652_NCHANNELS))
return -EINVAL;
chn = rme9652->channel_map[array_index_nospec(info->channel,
RME9652_NCHANNELS)];
if (chn < 0)
return -EINVAL;
info->offset = chn * RME9652_CHANNEL_BUFFER_BYTES;
info->first = 0;
info->step = 32;
return 0;
}
static int snd_rme9652_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
{
switch (cmd) {
case SNDRV_PCM_IOCTL1_RESET:
{
return snd_rme9652_reset(substream);
}
case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
{
struct snd_pcm_channel_info *info = arg;
return snd_rme9652_channel_info(substream, info);
}
default:
break;
}
return snd_pcm_lib_ioctl(substream, cmd, arg);
}
static void rme9652_silence_playback(struct snd_rme9652 *rme9652)
{
memset(rme9652->playback_buffer, 0, RME9652_DMA_AREA_BYTES);
}
static int snd_rme9652_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
struct snd_pcm_substream *other;
int running;
spin_lock(&rme9652->lock);
running = rme9652->running;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
running |= 1 << substream->stream;
break;
case SNDRV_PCM_TRIGGER_STOP:
running &= ~(1 << substream->stream);
break;
default:
snd_BUG();
spin_unlock(&rme9652->lock);
return -EINVAL;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
other = rme9652->capture_substream;
else
other = rme9652->playback_substream;
if (other) {
struct snd_pcm_substream *s;
snd_pcm_group_for_each_entry(s, substream) {
if (s == other) {
snd_pcm_trigger_done(s, substream);
if (cmd == SNDRV_PCM_TRIGGER_START)
running |= 1 << s->stream;
else
running &= ~(1 << s->stream);
goto _ok;
}
}
if (cmd == SNDRV_PCM_TRIGGER_START) {
if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) &&
substream->stream == SNDRV_PCM_STREAM_CAPTURE)
rme9652_silence_playback(rme9652);
} else {
if (running &&
substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
rme9652_silence_playback(rme9652);
}
} else {
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
rme9652_silence_playback(rme9652);
}
_ok:
snd_pcm_trigger_done(substream, substream);
if (!rme9652->running && running)
rme9652_start(rme9652);
else if (rme9652->running && !running)
rme9652_stop(rme9652);
rme9652->running = running;
spin_unlock(&rme9652->lock);
return 0;
}
static int snd_rme9652_prepare(struct snd_pcm_substream *substream)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
unsigned long flags;
int result = 0;
spin_lock_irqsave(&rme9652->lock, flags);
if (!rme9652->running)
rme9652_reset_hw_pointer(rme9652);
spin_unlock_irqrestore(&rme9652->lock, flags);
return result;
}
static struct snd_pcm_hardware snd_rme9652_playback_subinfo =
{
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_NONINTERLEAVED |
SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_DOUBLE),
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = (SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_88200 |
SNDRV_PCM_RATE_96000),
.rate_min = 44100,
.rate_max = 96000,
.channels_min = 10,
.channels_max = 26,
.buffer_bytes_max = RME9652_CHANNEL_BUFFER_BYTES * 26,
.period_bytes_min = (64 * 4) * 10,
.period_bytes_max = (8192 * 4) * 26,
.periods_min = 2,
.periods_max = 2,
.fifo_size = 0,
};
static struct snd_pcm_hardware snd_rme9652_capture_subinfo =
{
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_NONINTERLEAVED |
SNDRV_PCM_INFO_SYNC_START),
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = (SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_88200 |
SNDRV_PCM_RATE_96000),
.rate_min = 44100,
.rate_max = 96000,
.channels_min = 10,
.channels_max = 26,
.buffer_bytes_max = RME9652_CHANNEL_BUFFER_BYTES *26,
.period_bytes_min = (64 * 4) * 10,
.period_bytes_max = (8192 * 4) * 26,
.periods_min = 2,
.periods_max = 2,
.fifo_size = 0,
};
static unsigned int period_sizes[] = { 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
static struct snd_pcm_hw_constraint_list hw_constraints_period_sizes = {
.count = ARRAY_SIZE(period_sizes),
.list = period_sizes,
.mask = 0
};
static int snd_rme9652_hw_rule_channels(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_rme9652 *rme9652 = rule->private;
struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
unsigned int list[2] = { rme9652->ds_channels, rme9652->ss_channels };
return snd_interval_list(c, 2, list, 0);
}
static int snd_rme9652_hw_rule_channels_rate(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_rme9652 *rme9652 = rule->private;
struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
if (r->min > 48000) {
struct snd_interval t = {
.min = rme9652->ds_channels,
.max = rme9652->ds_channels,
.integer = 1,
};
return snd_interval_refine(c, &t);
} else if (r->max < 88200) {
struct snd_interval t = {
.min = rme9652->ss_channels,
.max = rme9652->ss_channels,
.integer = 1,
};
return snd_interval_refine(c, &t);
}
return 0;
}
static int snd_rme9652_hw_rule_rate_channels(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_rme9652 *rme9652 = rule->private;
struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
if (c->min >= rme9652->ss_channels) {
struct snd_interval t = {
.min = 44100,
.max = 48000,
.integer = 1,
};
return snd_interval_refine(r, &t);
} else if (c->max <= rme9652->ds_channels) {
struct snd_interval t = {
.min = 88200,
.max = 96000,
.integer = 1,
};
return snd_interval_refine(r, &t);
}
return 0;
}
static int snd_rme9652_playback_open(struct snd_pcm_substream *substream)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
spin_lock_irq(&rme9652->lock);
snd_pcm_set_sync(substream);
runtime->hw = snd_rme9652_playback_subinfo;
runtime->dma_area = rme9652->playback_buffer;
runtime->dma_bytes = RME9652_DMA_AREA_BYTES;
if (rme9652->capture_substream == NULL) {
rme9652_stop(rme9652);
rme9652_set_thru(rme9652, -1, 0);
}
rme9652->playback_pid = current->pid;
rme9652->playback_substream = substream;
spin_unlock_irq(&rme9652->lock);
snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_period_sizes);
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
snd_rme9652_hw_rule_channels, rme9652,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
snd_rme9652_hw_rule_channels_rate, rme9652,
SNDRV_PCM_HW_PARAM_RATE, -1);
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
snd_rme9652_hw_rule_rate_channels, rme9652,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
rme9652->creg_spdif_stream = rme9652->creg_spdif;
rme9652->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
snd_ctl_notify(rme9652->card, SNDRV_CTL_EVENT_MASK_VALUE |
SNDRV_CTL_EVENT_MASK_INFO, &rme9652->spdif_ctl->id);
return 0;
}
static int snd_rme9652_playback_release(struct snd_pcm_substream *substream)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
spin_lock_irq(&rme9652->lock);
rme9652->playback_pid = -1;
rme9652->playback_substream = NULL;
spin_unlock_irq(&rme9652->lock);
rme9652->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
snd_ctl_notify(rme9652->card, SNDRV_CTL_EVENT_MASK_VALUE |
SNDRV_CTL_EVENT_MASK_INFO, &rme9652->spdif_ctl->id);
return 0;
}
static int snd_rme9652_capture_open(struct snd_pcm_substream *substream)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
spin_lock_irq(&rme9652->lock);
snd_pcm_set_sync(substream);
runtime->hw = snd_rme9652_capture_subinfo;
runtime->dma_area = rme9652->capture_buffer;
runtime->dma_bytes = RME9652_DMA_AREA_BYTES;
if (rme9652->playback_substream == NULL) {
rme9652_stop(rme9652);
rme9652_set_thru(rme9652, -1, 0);
}
rme9652->capture_pid = current->pid;
rme9652->capture_substream = substream;
spin_unlock_irq(&rme9652->lock);
snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_period_sizes);
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
snd_rme9652_hw_rule_channels, rme9652,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
snd_rme9652_hw_rule_channels_rate, rme9652,
SNDRV_PCM_HW_PARAM_RATE, -1);
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
snd_rme9652_hw_rule_rate_channels, rme9652,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
return 0;
}
static int snd_rme9652_capture_release(struct snd_pcm_substream *substream)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
spin_lock_irq(&rme9652->lock);
rme9652->capture_pid = -1;
rme9652->capture_substream = NULL;
spin_unlock_irq(&rme9652->lock);
return 0;
}
static const struct snd_pcm_ops snd_rme9652_playback_ops = {
.open = snd_rme9652_playback_open,
.close = snd_rme9652_playback_release,
.ioctl = snd_rme9652_ioctl,
.hw_params = snd_rme9652_hw_params,
.prepare = snd_rme9652_prepare,
.trigger = snd_rme9652_trigger,
.pointer = snd_rme9652_hw_pointer,
.copy = snd_rme9652_playback_copy,
.silence = snd_rme9652_hw_silence,
};
static const struct snd_pcm_ops snd_rme9652_capture_ops = {
.open = snd_rme9652_capture_open,
.close = snd_rme9652_capture_release,
.ioctl = snd_rme9652_ioctl,
.hw_params = snd_rme9652_hw_params,
.prepare = snd_rme9652_prepare,
.trigger = snd_rme9652_trigger,
.pointer = snd_rme9652_hw_pointer,
.copy = snd_rme9652_capture_copy,
};
static int snd_rme9652_create_pcm(struct snd_card *card,
struct snd_rme9652 *rme9652)
{
struct snd_pcm *pcm;
int err;
if ((err = snd_pcm_new(card,
rme9652->card_name,
0, 1, 1, &pcm)) < 0) {
return err;
}
rme9652->pcm = pcm;
pcm->private_data = rme9652;
strcpy(pcm->name, rme9652->card_name);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_rme9652_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_rme9652_capture_ops);
pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
return 0;
}
static int snd_rme9652_create(struct snd_card *card,
struct snd_rme9652 *rme9652,
int precise_ptr)
{
struct pci_dev *pci = rme9652->pci;
int err;
int status;
unsigned short rev;
rme9652->irq = -1;
rme9652->card = card;
pci_read_config_word(rme9652->pci, PCI_CLASS_REVISION, &rev);
switch (rev & 0xff) {
case 3:
case 4:
case 8:
case 9:
break;
default:
/* who knows? */
return -ENODEV;
}
if ((err = pci_enable_device(pci)) < 0)
return err;
spin_lock_init(&rme9652->lock);
if ((err = pci_request_regions(pci, "rme9652")) < 0)
return err;
rme9652->port = pci_resource_start(pci, 0);
rme9652->iobase = ioremap_nocache(rme9652->port, RME9652_IO_EXTENT);
if (rme9652->iobase == NULL) {
dev_err(card->dev, "unable to remap region 0x%lx-0x%lx\n",
rme9652->port, rme9652->port + RME9652_IO_EXTENT - 1);
return -EBUSY;
}
if (request_irq(pci->irq, snd_rme9652_interrupt, IRQF_SHARED,
KBUILD_MODNAME, rme9652)) {
dev_err(card->dev, "unable to request IRQ %d\n", pci->irq);
return -EBUSY;
}
rme9652->irq = pci->irq;
rme9652->precise_ptr = precise_ptr;
/* Determine the h/w rev level of the card. This seems like
a particularly kludgy way to encode it, but its what RME
chose to do, so we follow them ...
*/
status = rme9652_read(rme9652, RME9652_status_register);
if (rme9652_decode_spdif_rate(status&RME9652_F) == 1) {
rme9652->hw_rev = 15;
} else {
rme9652->hw_rev = 11;
}
/* Differentiate between the standard Hammerfall, and the
"Light", which does not have the expansion board. This
method comes from information received from Mathhias
Clausen at RME. Display the EEPROM and h/w revID where
relevant.
*/
switch (rev) {
case 8: /* original eprom */
strcpy(card->driver, "RME9636");
if (rme9652->hw_rev == 15) {
rme9652->card_name = "RME Digi9636 (Rev 1.5)";
} else {
rme9652->card_name = "RME Digi9636";
}
rme9652->ss_channels = RME9636_NCHANNELS;
break;
case 9: /* W36_G EPROM */
strcpy(card->driver, "RME9636");
rme9652->card_name = "RME Digi9636 (Rev G)";
rme9652->ss_channels = RME9636_NCHANNELS;
break;
case 4: /* W52_G EPROM */
strcpy(card->driver, "RME9652");
rme9652->card_name = "RME Digi9652 (Rev G)";
rme9652->ss_channels = RME9652_NCHANNELS;
break;
case 3: /* original eprom */
strcpy(card->driver, "RME9652");
if (rme9652->hw_rev == 15) {
rme9652->card_name = "RME Digi9652 (Rev 1.5)";
} else {
rme9652->card_name = "RME Digi9652";
}
rme9652->ss_channels = RME9652_NCHANNELS;
break;
}
rme9652->ds_channels = (rme9652->ss_channels - 2) / 2 + 2;
pci_set_master(rme9652->pci);
if ((err = snd_rme9652_initialize_memory(rme9652)) < 0) {
return err;
}
if ((err = snd_rme9652_create_pcm(card, rme9652)) < 0) {
return err;
}
if ((err = snd_rme9652_create_controls(card, rme9652)) < 0) {
return err;
}
snd_rme9652_proc_init(rme9652);
rme9652->last_spdif_sample_rate = -1;
rme9652->last_adat_sample_rate = -1;
rme9652->playback_pid = -1;
rme9652->capture_pid = -1;
rme9652->capture_substream = NULL;
rme9652->playback_substream = NULL;
snd_rme9652_set_defaults(rme9652);
if (rme9652->hw_rev == 15) {
rme9652_initialize_spdif_receiver (rme9652);
}
return 0;
}
static void snd_rme9652_card_free(struct snd_card *card)
{
struct snd_rme9652 *rme9652 = (struct snd_rme9652 *) card->private_data;
if (rme9652)
snd_rme9652_free(rme9652);
}
static int snd_rme9652_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
static int dev;
struct snd_rme9652 *rme9652;
struct snd_card *card;
int err;
if (dev >= SNDRV_CARDS)
return -ENODEV;
if (!enable[dev]) {
dev++;
return -ENOENT;
}
err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
sizeof(struct snd_rme9652), &card);
if (err < 0)
return err;
rme9652 = (struct snd_rme9652 *) card->private_data;
card->private_free = snd_rme9652_card_free;
rme9652->dev = dev;
rme9652->pci = pci;
if ((err = snd_rme9652_create(card, rme9652, precise_ptr[dev])) < 0) {
snd_card_free(card);
return err;
}
strcpy(card->shortname, rme9652->card_name);
sprintf(card->longname, "%s at 0x%lx, irq %d",
card->shortname, rme9652->port, rme9652->irq);
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
return err;
}
pci_set_drvdata(pci, card);
dev++;
return 0;
}
static void snd_rme9652_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
}
static struct pci_driver rme9652_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_rme9652_ids,
.probe = snd_rme9652_probe,
.remove = snd_rme9652_remove,
};
module_pci_driver(rme9652_driver);