| 1 | //! Some definitions from the kernel headers |
| 2 | |
| 3 | #![allow (non_camel_case_types)] |
| 4 | |
| 5 | use cfg_if::cfg_if; |
| 6 | |
| 7 | // const SNDRV_PCM_MMAP_OFFSET_DATA: c_uint = 0x00000000; |
| 8 | pub const SNDRV_PCM_MMAP_OFFSET_STATUS: libc::c_uint = 0x80000000; |
| 9 | pub const SNDRV_PCM_MMAP_OFFSET_CONTROL: libc::c_uint = 0x81000000; |
| 10 | |
| 11 | pub const SNDRV_PCM_SYNC_PTR_HWSYNC: libc::c_uint = 1; |
| 12 | pub const SNDRV_PCM_SYNC_PTR_APPL: libc::c_uint = 2; |
| 13 | pub const SNDRV_PCM_SYNC_PTR_AVAIL_MIN: libc::c_uint = 4; |
| 14 | |
| 15 | // #[repr(C)] |
| 16 | #[allow (non_camel_case_types)] |
| 17 | pub type snd_pcm_state_t = libc::c_int; |
| 18 | |
| 19 | // #[repr(C)] |
| 20 | #[allow (non_camel_case_types)] |
| 21 | pub type snd_pcm_uframes_t = libc::c_ulong; |
| 22 | |
| 23 | // I think?! Not sure how this will work with X32 ABI?! |
| 24 | #[allow (non_camel_case_types)] |
| 25 | pub type __kernel_off_t = libc::c_long; |
| 26 | |
| 27 | #[repr (C)] |
| 28 | #[derive (Copy, Clone)] |
| 29 | pub struct snd_pcm_mmap_status { |
| 30 | pub state: snd_pcm_state_t, /* RO: state - SNDRV_PCM_STATE_XXXX */ |
| 31 | pub pad1: libc::c_int, /* Needed for 64 bit alignment */ |
| 32 | pub hw_ptr: snd_pcm_uframes_t, /* RO: hw ptr (0...boundary-1) */ |
| 33 | pub tstamp: libc::timespec, /* Timestamp */ |
| 34 | pub suspended_state: snd_pcm_state_t, /* RO: suspended stream state */ |
| 35 | pub audio_tstamp: libc::timespec, /* from sample counter or wall clock */ |
| 36 | } |
| 37 | |
| 38 | #[repr (C)] |
| 39 | #[derive (Debug, Copy, Clone)] |
| 40 | pub struct snd_pcm_mmap_control { |
| 41 | pub appl_ptr: snd_pcm_uframes_t, /* RW: appl ptr (0...boundary-1) */ |
| 42 | pub avail_min: snd_pcm_uframes_t, /* RW: min available frames for wakeup */ |
| 43 | } |
| 44 | |
| 45 | #[repr (C)] |
| 46 | #[derive (Debug)] |
| 47 | pub struct snd_pcm_channel_info { |
| 48 | pub channel: libc::c_uint, |
| 49 | pub offset: __kernel_off_t, /* mmap offset */ |
| 50 | pub first: libc::c_uint, /* offset to first sample in bits */ |
| 51 | pub step: libc::c_uint, /* samples distance in bits */ |
| 52 | } |
| 53 | |
| 54 | #[repr (C)] |
| 55 | #[derive (Copy, Clone)] |
| 56 | pub union snd_pcm_mmap_status_r { |
| 57 | pub status: snd_pcm_mmap_status, |
| 58 | pub reserved: [libc::c_uchar; 64], |
| 59 | } |
| 60 | |
| 61 | #[repr (C)] |
| 62 | #[derive (Copy, Clone)] |
| 63 | pub union snd_pcm_mmap_control_r { |
| 64 | pub control: snd_pcm_mmap_control, |
| 65 | pub reserved: [libc::c_uchar; 64], |
| 66 | } |
| 67 | |
| 68 | #[repr (C)] |
| 69 | #[derive (Copy, Clone)] |
| 70 | pub struct snd_pcm_sync_ptr { |
| 71 | pub flags: libc::c_uint, |
| 72 | pub s: snd_pcm_mmap_status_r, |
| 73 | pub c: snd_pcm_mmap_control_r, |
| 74 | } |
| 75 | |
| 76 | cfg_if! { |
| 77 | if #[cfg(any(target_os = "linux" , target_os = "android" ))] { |
| 78 | // See <https://github.com/nix-rust/nix/blob/197f55b3ccbce3273bf6ce119d1a8541b5df5d66/src/sys/ioctl/linux.rs> |
| 79 | |
| 80 | cfg_if! { |
| 81 | if #[cfg(any(target_os = "android" , target_env = "musl" ))] { |
| 82 | pub(super) type ioctl_num_type = libc::c_int; |
| 83 | } else { |
| 84 | pub(super) type ioctl_num_type = libc::c_ulong; |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | // The READ dir is consistent across arches |
| 89 | pub(super) const READ: ioctl_num_type = 2; |
| 90 | |
| 91 | // But WRITE is not, as well as having a different number of bits for the SIZEBITS |
| 92 | cfg_if!{ |
| 93 | if #[cfg(any( |
| 94 | target_arch = "mips" , |
| 95 | target_arch = "mips32r6" , |
| 96 | target_arch = "mips64" , |
| 97 | target_arch = "mips64r6" , |
| 98 | target_arch = "powerpc" , |
| 99 | target_arch = "powerpc64" , |
| 100 | target_arch = "sparc64" |
| 101 | ))] { |
| 102 | pub(super) const WRITE: ioctl_num_type = 4; |
| 103 | const SIZEBITS: ioctl_num_type = 13; |
| 104 | } else { |
| 105 | pub(super) const WRITE: ioctl_num_type = 1; |
| 106 | const SIZEBITS: ioctl_num_type = 14; |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | const NRSHIFT: ioctl_num_type = 0; |
| 111 | const NRBITS: ioctl_num_type = 8; |
| 112 | const TYPEBITS: ioctl_num_type = 8; |
| 113 | const TYPESHIFT: ioctl_num_type = NRSHIFT + NRBITS; |
| 114 | const SIZESHIFT: ioctl_num_type = TYPESHIFT + TYPEBITS; |
| 115 | const DIRSHIFT: ioctl_num_type = SIZESHIFT + SIZEBITS; |
| 116 | |
| 117 | /// Replication of the [`nix::ioc!`](https://github.com/nix-rust/nix/blob/197f55b3ccbce3273bf6ce119d1a8541b5df5d66/src/sys/ioctl/linux.rs#L78-L96) |
| 118 | pub(super) const fn make_request( |
| 119 | dir: ioctl_num_type, |
| 120 | typ: u8, |
| 121 | nr: u8, |
| 122 | size: usize, |
| 123 | ) -> ioctl_num_type { |
| 124 | dir << DIRSHIFT |
| 125 | | (typ as ioctl_num_type) << TYPESHIFT |
| 126 | | (nr as ioctl_num_type) << NRSHIFT |
| 127 | | (size as ioctl_num_type) << SIZESHIFT |
| 128 | } |
| 129 | } else if #[cfg(any( |
| 130 | target_os = "dragonfly" , |
| 131 | target_os = "freebsd" , |
| 132 | target_os = "netbsd" , |
| 133 | target_os = "openbsd" , |
| 134 | target_os = "solaris" , |
| 135 | target_os = "illumos" |
| 136 | ))] { |
| 137 | // See <https://github.com/nix-rust/nix/blob/197f55b3ccbce3273bf6ce119d1a8541b5df5d66/src/sys/ioctl/bsd.rs> |
| 138 | |
| 139 | cfg_if! { |
| 140 | if #[cfg(not(any(target_os = "illumos" , target_os = "solaris" )))] { |
| 141 | pub(super) type ioctl_num_type = libc::c_ulong; |
| 142 | } else { |
| 143 | pub(super) type ioctl_num_type = libc::c_int; |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | #[allow(overflowing_literals)] |
| 148 | pub(super) const READ: ioctl_num_type = 0x4000_0000; |
| 149 | #[allow(overflowing_literals)] |
| 150 | pub(super) const WRITE: ioctl_num_type = 0x8000_0000; |
| 151 | |
| 152 | const IOCPARM_MASK: ioctl_num_type = 0x1fff; |
| 153 | |
| 154 | /// Replication of [`nix::ioc!`](https://github.com/nix-rust/nix/blob/197f55b3ccbce3273bf6ce119d1a8541b5df5d66/src/sys/ioctl/bsd.rs#L31-L42) |
| 155 | pub(super) const fn make_request( |
| 156 | dir: ioctl_num_type, |
| 157 | typ: u8, |
| 158 | nr: u8, |
| 159 | size: usize, |
| 160 | ) -> ioctl_num_type { |
| 161 | dir | ((size as ioctl_num_type) & IOCPARM_MASK) << 16 |
| 162 | | (typ as ioctl_num_type) << 8 |
| 163 | | nr as ioctl_num_type |
| 164 | } |
| 165 | } else { |
| 166 | compile_error!("unknown target platform" ); |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | pub(crate) unsafe fn sndrv_pcm_ioctl_channel_info( |
| 171 | fd: libc::c_int, |
| 172 | data: *mut snd_pcm_channel_info, |
| 173 | ) -> Result<(), crate::Error> { |
| 174 | const REQUEST: ioctl_num_type = make_request( |
| 175 | READ, |
| 176 | typ:b'A' , |
| 177 | nr:0x32, |
| 178 | size:std::mem::size_of::<snd_pcm_channel_info>(), |
| 179 | ); |
| 180 | |
| 181 | unsafe { |
| 182 | if libc::ioctl(fd, REQUEST, data) == -1 { |
| 183 | Err(crate::Error::last(func:"SNDRV_PCM_IOCTL_CHANNEL_INFO" )) |
| 184 | } else { |
| 185 | Ok(()) |
| 186 | } |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | pub(crate) unsafe fn sndrv_pcm_ioctl_sync_ptr( |
| 191 | fd: libc::c_int, |
| 192 | data: *mut snd_pcm_sync_ptr, |
| 193 | ) -> Result<(), crate::Error> { |
| 194 | const REQUEST: ioctl_num_type = make_request( |
| 195 | READ | WRITE, |
| 196 | typ:b'A' , |
| 197 | nr:0x23, |
| 198 | size:std::mem::size_of::<snd_pcm_sync_ptr>(), |
| 199 | ); |
| 200 | |
| 201 | unsafe { |
| 202 | if libc::ioctl(fd, REQUEST, data) == -1 { |
| 203 | Err(crate::Error::last(func:"SNDRV_PCM_IOCTL_SYNC_PTR" )) |
| 204 | } else { |
| 205 | Ok(()) |
| 206 | } |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | pub fn pagesize() -> usize { |
| 211 | unsafe { libc::sysconf(name:libc::_SC_PAGESIZE) as usize } |
| 212 | } |
| 213 | |