1use core::mem::MaybeUninit;
17
18use linux_unsafe::args::AsRawV;
19use linux_unsafe::{int, ulong};
20
21pub trait IoDevice {}
33
34pub unsafe trait SubDevice<Parent: IoDevice>: IoDevice {}
53
54unsafe impl<T: IoDevice> SubDevice<T> for T {}
58
59pub unsafe trait IoctlReq<'a, Device: IoDevice>: Copy {
64 type ExtArg
69 where
70 Self: 'a;
71
72 type TempMem;
79
80 type RawArg: AsRawV;
82
83 type Result
85 where
86 Self: 'a;
87
88 fn prepare_ioctl_args(
97 &self,
98 arg: &Self::ExtArg,
99 temp_mem: &mut MaybeUninit<Self::TempMem>,
100 ) -> (ulong, Self::RawArg);
101
102 fn prepare_ioctl_result(
104 &self,
105 raw: int,
106 arg: &Self::ExtArg,
107 temp_mem: &MaybeUninit<Self::TempMem>,
108 ) -> Self::Result;
109}
110
111pub const unsafe fn ioctl_no_arg<Device, Result>(request: ulong) -> IoctlReqNoArgs<Device, Result>
117where
118 *mut Result: AsRawV,
119 Device: IoDevice,
120 Result: FromIoctlResult<int>,
121{
122 IoctlReqNoArgs::<Device, Result> {
123 request,
124 _phantom: core::marker::PhantomData,
125 }
126}
127
128pub const unsafe fn ioctl_const_arg<Device, Result, const ARG: int>(
134 request: ulong,
135) -> IoctlReqConstArg<Device, Result, ARG>
136where
137 *mut Result: AsRawV,
138 Device: IoDevice,
139 Result: FromIoctlResult<int>,
140{
141 IoctlReqConstArg::<Device, Result, ARG> {
142 request,
143 _phantom: core::marker::PhantomData,
144 }
145}
146
147pub const unsafe fn ioctl_read<Device, Result>(request: ulong) -> IoctlReqRead<Device, Result>
156where
157 *mut Result: AsRawV,
158 Device: IoDevice,
159 Result: Copy,
160{
161 IoctlReqRead::<Device, Result> {
162 request,
163 _phantom: core::marker::PhantomData,
164 }
165}
166
167pub const unsafe fn ioctl_write_val<Device, Arg, Result>(
174 request: ulong,
175) -> IoctlReqWriteVal<Device, Arg, Result>
176where
177 Arg: AsRawV,
178 Device: IoDevice,
179 Result: FromIoctlResult<int>,
180{
181 IoctlReqWriteVal::<Device, Arg, Result> {
182 request,
183 _phantom: core::marker::PhantomData,
184 }
185}
186
187pub const unsafe fn ioctl_write<Device, Arg, Result>(
197 request: ulong,
198) -> IoctlReqWrite<Device, Arg, Result>
199where
200 *const Arg: AsRawV,
201 Device: IoDevice,
202 Result: FromIoctlResult<int>,
203{
204 IoctlReqWrite::<Device, Arg, Result> {
205 request,
206 _phantom: core::marker::PhantomData,
207 }
208}
209
210pub const unsafe fn ioctl_writeread<Device, Arg, Result>(
220 request: ulong,
221) -> IoctlReqWriteRead<Device, Arg, Result>
222where
223 *mut Result: AsRawV,
224 Device: IoDevice,
225 Result: Copy,
226{
227 IoctlReqWriteRead::<Device, Arg, Result> {
228 request,
229 _phantom: core::marker::PhantomData,
230 }
231}
232
233#[repr(transparent)]
239pub struct IoctlReqNoArgs<Device: IoDevice, Result> {
240 request: ulong,
241 _phantom: core::marker::PhantomData<(Device, Result)>,
242}
243
244impl<Device: IoDevice, Result> Clone for IoctlReqNoArgs<Device, Result> {
245 fn clone(&self) -> Self {
246 Self {
247 request: self.request,
248 _phantom: core::marker::PhantomData,
249 }
250 }
251}
252impl<Device: IoDevice, Result> Copy for IoctlReqNoArgs<Device, Result> {}
253
254unsafe impl<'a, Device, Result> IoctlReq<'a, Device> for IoctlReqNoArgs<Device, Result>
255where
256 Result: 'a + FromIoctlResult<int>,
257 Device: 'a + IoDevice,
258{
259 type ExtArg = ();
260 type TempMem = ();
261 type RawArg = ();
262 type Result = Result;
263
264 #[inline(always)]
265 fn prepare_ioctl_args(
266 &self,
267 _: &Self::ExtArg,
268 _: &mut MaybeUninit<Self::TempMem>,
269 ) -> (ulong, Self::RawArg) {
270 (self.request, ())
271 }
272
273 #[inline(always)]
274 fn prepare_ioctl_result(
275 &self,
276 raw: int,
277 _: &Self::ExtArg,
278 _: &MaybeUninit<Self::TempMem>,
279 ) -> Self::Result {
280 Self::Result::from_ioctl_result(&raw)
281 }
282}
283
284#[repr(transparent)]
287pub struct IoctlReqConstArg<Device: IoDevice, Result, const ARG: int> {
288 request: ulong,
289 _phantom: core::marker::PhantomData<(Device, Result)>,
290}
291
292impl<Device: IoDevice, Result, const ARG: int> Clone for IoctlReqConstArg<Device, Result, ARG> {
293 fn clone(&self) -> Self {
294 Self {
295 request: self.request,
296 _phantom: core::marker::PhantomData,
297 }
298 }
299}
300impl<Device: IoDevice, Result, const ARG: int> Copy for IoctlReqConstArg<Device, Result, ARG> {}
301
302unsafe impl<'a, Device, Result, const ARG: int> IoctlReq<'a, Device>
303 for IoctlReqConstArg<Device, Result, ARG>
304where
305 Result: 'a + FromIoctlResult<int>,
306 Device: 'a + IoDevice,
307{
308 type ExtArg = ();
309 type TempMem = ();
310 type RawArg = int;
311 type Result = Result;
312
313 #[inline(always)]
314 fn prepare_ioctl_args(
315 &self,
316 _: &Self::ExtArg,
317 _: &mut MaybeUninit<Self::TempMem>,
318 ) -> (ulong, Self::RawArg) {
319 (self.request, ARG)
320 }
321
322 #[inline(always)]
323 fn prepare_ioctl_result(
324 &self,
325 raw: int,
326 _: &Self::ExtArg,
327 _: &MaybeUninit<Self::TempMem>,
328 ) -> Self::Result {
329 Self::Result::from_ioctl_result(&raw)
330 }
331}
332
333#[repr(transparent)]
337pub struct IoctlReqRead<Device: IoDevice, Result>
338where
339 *mut Result: AsRawV,
340 Result: Copy,
341{
342 request: ulong,
343 _phantom: core::marker::PhantomData<(Device, Result)>,
344}
345
346impl<Device: IoDevice, Result: Copy> Clone for IoctlReqRead<Device, Result> {
347 fn clone(&self) -> Self {
348 Self {
349 request: self.request,
350 _phantom: core::marker::PhantomData,
351 }
352 }
353}
354impl<Device: IoDevice, Result: Copy> Copy for IoctlReqRead<Device, Result> {}
355
356unsafe impl<'a, Device, Result> IoctlReq<'a, Device> for IoctlReqRead<Device, Result>
357where
358 *mut Result: AsRawV,
359 Result: 'a + Copy,
360 Device: 'a + IoDevice,
361{
362 type ExtArg = ();
363 type TempMem = Result;
364 type RawArg = *mut Result;
365 type Result = Result;
366
367 #[inline(always)]
368 fn prepare_ioctl_args(
369 &self,
370 _: &Self::ExtArg,
371 temp_mem: &mut MaybeUninit<Self::TempMem>,
372 ) -> (ulong, Self::RawArg) {
373 (self.request, temp_mem.as_mut_ptr())
374 }
375
376 #[inline(always)]
377 fn prepare_ioctl_result(
378 &self,
379 _: int,
380 _: &Self::ExtArg,
381 temp_mem: &MaybeUninit<Self::TempMem>,
382 ) -> Self::Result {
383 unsafe { temp_mem.assume_init() }
384 }
385}
386
387#[repr(transparent)]
390pub struct IoctlReqWriteVal<Device: IoDevice, Arg, Result = int>
391where
392 Arg: AsRawV,
393{
394 request: ulong,
395 _phantom: core::marker::PhantomData<(Device, Arg, Result)>,
396}
397
398impl<Device: IoDevice, Arg: AsRawV, Result> Clone for IoctlReqWriteVal<Device, Arg, Result> {
399 fn clone(&self) -> Self {
400 Self {
401 request: self.request,
402 _phantom: core::marker::PhantomData,
403 }
404 }
405}
406impl<Device: IoDevice, Arg: AsRawV, Result> Copy for IoctlReqWriteVal<Device, Arg, Result> {}
407
408unsafe impl<'a, Device, Arg, Result> IoctlReq<'a, Device> for IoctlReqWriteVal<Device, Arg, Result>
409where
410 Arg: 'a + AsRawV,
411 Result: 'a + FromIoctlResult<int>,
412 Device: 'a + IoDevice,
413{
414 type ExtArg = Arg;
415 type TempMem = ();
416 type RawArg = Arg;
417 type Result = Result;
418
419 #[inline(always)]
420 fn prepare_ioctl_args(
421 &self,
422 arg: &Self::ExtArg,
423 _: &mut MaybeUninit<Self::TempMem>,
424 ) -> (ulong, Arg) {
425 (self.request, *arg)
426 }
427
428 #[inline(always)]
429 fn prepare_ioctl_result(
430 &self,
431 ret: int,
432 _: &Self::ExtArg,
433 _: &MaybeUninit<Self::TempMem>,
434 ) -> Self::Result {
435 Result::from_ioctl_result(&ret)
436 }
437}
438
439#[repr(transparent)]
442pub struct IoctlReqWrite<Device: IoDevice, Arg, Result = int>
443where
444 *const Arg: AsRawV,
445{
446 request: ulong,
447 _phantom: core::marker::PhantomData<(Device, Arg, Result)>,
448}
449
450impl<Device: IoDevice, Arg, Result> Clone for IoctlReqWrite<Device, Arg, Result> {
451 fn clone(&self) -> Self {
452 Self {
453 request: self.request,
454 _phantom: core::marker::PhantomData,
455 }
456 }
457}
458impl<Device: IoDevice, Arg, Result> Copy for IoctlReqWrite<Device, Arg, Result> {}
459
460unsafe impl<'a, Device, Arg, Result> IoctlReq<'a, Device> for IoctlReqWrite<Device, Arg, Result>
461where
462 *const Arg: AsRawV,
463 Arg: 'a,
464 Result: 'a + FromIoctlResult<int>,
465 Device: 'a + IoDevice,
466{
467 type ExtArg = &'a Arg;
468 type TempMem = ();
469 type RawArg = *const Arg;
470 type Result = Result;
471
472 #[inline(always)]
473 fn prepare_ioctl_args(
474 &self,
475 arg: &Self::ExtArg,
476 _: &mut MaybeUninit<Self::TempMem>,
477 ) -> (ulong, *const Arg) {
478 (self.request, (*arg) as *const Arg)
479 }
480
481 #[inline(always)]
482 fn prepare_ioctl_result(
483 &self,
484 ret: int,
485 _: &Self::ExtArg,
486 _: &MaybeUninit<Self::TempMem>,
487 ) -> Self::Result {
488 Result::from_ioctl_result(&ret)
489 }
490}
491
492#[repr(transparent)]
493pub struct IoctlReqWriteRead<Device: IoDevice, Arg, Result = int>
494where
495 *const Arg: AsRawV,
496{
497 request: ulong,
498 _phantom: core::marker::PhantomData<(Device, Arg, Result)>,
499}
500
501impl<Device: IoDevice, Arg, Result> Clone for IoctlReqWriteRead<Device, Arg, Result> {
502 fn clone(&self) -> Self {
503 Self {
504 request: self.request,
505 _phantom: core::marker::PhantomData,
506 }
507 }
508}
509impl<Device: IoDevice, Arg, Result> Copy for IoctlReqWriteRead<Device, Arg, Result> {}
510
511unsafe impl<'a, Device, Arg, Result> IoctlReq<'a, Device> for IoctlReqWriteRead<Device, Arg, Result>
512where
513 Device: IoDevice + 'a,
514 *const Arg: AsRawV,
515 Arg: 'a,
516 Result: 'a + FromIoctlResult<int>,
517{
518 type ExtArg = &'a mut Arg;
519 type TempMem = ();
520 type RawArg = *mut Arg;
521 type Result = Result;
522
523 #[inline(always)]
524 fn prepare_ioctl_args(
525 &self,
526 arg: &Self::ExtArg,
527 _: &mut MaybeUninit<Self::TempMem>,
528 ) -> (ulong, *mut Arg) {
529 (self.request, (*arg) as *const Arg as *mut Arg)
530 }
531
532 #[inline(always)]
533 fn prepare_ioctl_result(
534 &self,
535 ret: int,
536 _: &Self::ExtArg,
537 _: &MaybeUninit<Self::TempMem>,
538 ) -> Self::Result {
539 Result::from_ioctl_result(&ret)
540 }
541}
542
543pub trait FromIoctlResult<Raw> {
546 fn from_ioctl_result(raw: &Raw) -> Self;
547}
548
549impl FromIoctlResult<int> for int {
550 fn from_ioctl_result(raw: &int) -> Self {
551 *raw
552 }
553}
554
555impl<Device: IoDevice> FromIoctlResult<int> for super::File<Device> {
556 fn from_ioctl_result(raw: &int) -> Self {
557 unsafe { super::File::from_raw_fd(*raw) }
558 }
559}
560
561#[allow(non_snake_case)]
562const fn _IOC(dir: ulong, typ: ulong, nr: ulong, size: ulong) -> ulong {
563 (dir << 30) | (typ << 8) | (nr << 0) | (size << 16)
564}
565
566#[allow(non_snake_case)]
569pub const fn _IO(typ: ulong, nr: ulong) -> ulong {
570 _IOC(0, typ, nr, 0)
571}
572
573#[allow(non_snake_case)]
576pub const fn _IOR(typ: ulong, nr: ulong, size: ulong) -> ulong {
577 _IOC(2, typ, nr, size)
578}
579
580#[allow(non_snake_case)]
583pub const fn _IOW(typ: ulong, nr: ulong, size: ulong) -> ulong {
584 _IOC(1, typ, nr, size)
585}
586
587#[allow(non_snake_case)]
591pub const fn _IOWR(typ: ulong, nr: ulong, size: ulong) -> ulong {
592 _IOC(1 | 2, typ, nr, size)
593}