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 | |