// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package unix

import 

// IoctlRetInt performs an ioctl operation specified by req on a device
// associated with opened file descriptor fd, and returns a non-negative
// integer that is returned by the ioctl syscall.
func ( int,  uint) (int, error) {
	, ,  := Syscall(SYS_IOCTL, uintptr(), uintptr(), 0)
	if  != 0 {
		return 0, 
	}
	return int(), nil
}

func ( int,  uint) (uint32, error) {
	var  uint32
	 := ioctlPtr(, , unsafe.Pointer(&))
	return , 
}

func ( int) (*RTCTime, error) {
	var  RTCTime
	 := ioctlPtr(, RTC_RD_TIME, unsafe.Pointer(&))
	return &, 
}

func ( int,  *RTCTime) error {
	return ioctlPtr(, RTC_SET_TIME, unsafe.Pointer())
}

func ( int) (*RTCWkAlrm, error) {
	var  RTCWkAlrm
	 := ioctlPtr(, RTC_WKALM_RD, unsafe.Pointer(&))
	return &, 
}

func ( int,  *RTCWkAlrm) error {
	return ioctlPtr(, RTC_WKALM_SET, unsafe.Pointer())
}

// IoctlGetEthtoolDrvinfo fetches ethtool driver information for the network
// device specified by ifname.
func ( int,  string) (*EthtoolDrvinfo, error) {
	,  := NewIfreq()
	if  != nil {
		return nil, 
	}

	 := EthtoolDrvinfo{Cmd: ETHTOOL_GDRVINFO}
	 := .withData(unsafe.Pointer(&))

	 = ioctlIfreqData(, SIOCETHTOOL, &)
	return &, 
}

// IoctlGetWatchdogInfo fetches information about a watchdog device from the
// Linux watchdog API. For more information, see:
// https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html.
func ( int) (*WatchdogInfo, error) {
	var  WatchdogInfo
	 := ioctlPtr(, WDIOC_GETSUPPORT, unsafe.Pointer(&))
	return &, 
}

// IoctlWatchdogKeepalive issues a keepalive ioctl to a watchdog device. For
// more information, see:
// https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html.
func ( int) error {
	// arg is ignored and not a pointer, so ioctl is fine instead of ioctlPtr.
	return ioctl(, WDIOC_KEEPALIVE, 0)
}

// IoctlFileCloneRange performs an FICLONERANGE ioctl operation to clone the
// range of data conveyed in value to the file associated with the file
// descriptor destFd. See the ioctl_ficlonerange(2) man page for details.
func ( int,  *FileCloneRange) error {
	return ioctlPtr(, FICLONERANGE, unsafe.Pointer())
}

// IoctlFileClone performs an FICLONE ioctl operation to clone the entire file
// associated with the file description srcFd to the file associated with the
// file descriptor destFd. See the ioctl_ficlone(2) man page for details.
func (,  int) error {
	return ioctl(, FICLONE, uintptr())
}

type FileDedupeRange struct {
	Src_offset uint64
	Src_length uint64
	Reserved1  uint16
	Reserved2  uint32
	Info       []FileDedupeRangeInfo
}

type FileDedupeRangeInfo struct {
	Dest_fd       int64
	Dest_offset   uint64
	Bytes_deduped uint64
	Status        int32
	Reserved      uint32
}

// IoctlFileDedupeRange performs an FIDEDUPERANGE ioctl operation to share the
// range of data conveyed in value from the file associated with the file
// descriptor srcFd to the value.Info destinations. See the
// ioctl_fideduperange(2) man page for details.
func ( int,  *FileDedupeRange) error {
	 := make([]byte, SizeofRawFileDedupeRange+
		len(.Info)*SizeofRawFileDedupeRangeInfo)
	 := (*RawFileDedupeRange)(unsafe.Pointer(&[0]))
	.Src_offset = .Src_offset
	.Src_length = .Src_length
	.Dest_count = uint16(len(.Info))
	.Reserved1 = .Reserved1
	.Reserved2 = .Reserved2

	for  := range .Info {
		 := (*RawFileDedupeRangeInfo)(unsafe.Pointer(
			uintptr(unsafe.Pointer(&[0])) + uintptr(SizeofRawFileDedupeRange) +
				uintptr(*SizeofRawFileDedupeRangeInfo)))
		.Dest_fd = .Info[].Dest_fd
		.Dest_offset = .Info[].Dest_offset
		.Bytes_deduped = .Info[].Bytes_deduped
		.Status = .Info[].Status
		.Reserved = .Info[].Reserved
	}

	 := ioctlPtr(, FIDEDUPERANGE, unsafe.Pointer(&[0]))

	// Output
	for  := range .Info {
		 := (*RawFileDedupeRangeInfo)(unsafe.Pointer(
			uintptr(unsafe.Pointer(&[0])) + uintptr(SizeofRawFileDedupeRange) +
				uintptr(*SizeofRawFileDedupeRangeInfo)))
		.Info[].Dest_fd = .Dest_fd
		.Info[].Dest_offset = .Dest_offset
		.Info[].Bytes_deduped = .Bytes_deduped
		.Info[].Status = .Status
		.Info[].Reserved = .Reserved
	}

	return 
}

func ( int,  *HIDRawReportDescriptor) error {
	return ioctlPtr(, HIDIOCGRDESC, unsafe.Pointer())
}

func ( int) (*HIDRawDevInfo, error) {
	var  HIDRawDevInfo
	 := ioctlPtr(, HIDIOCGRAWINFO, unsafe.Pointer(&))
	return &, 
}

func ( int) (string, error) {
	var  [_HIDIOCGRAWNAME_LEN]byte
	 := ioctlPtr(, _HIDIOCGRAWNAME, unsafe.Pointer(&[0]))
	return ByteSliceToString([:]), 
}

func ( int) (string, error) {
	var  [_HIDIOCGRAWPHYS_LEN]byte
	 := ioctlPtr(, _HIDIOCGRAWPHYS, unsafe.Pointer(&[0]))
	return ByteSliceToString([:]), 
}

func ( int) (string, error) {
	var  [_HIDIOCGRAWUNIQ_LEN]byte
	 := ioctlPtr(, _HIDIOCGRAWUNIQ, unsafe.Pointer(&[0]))
	return ByteSliceToString([:]), 
}

// IoctlIfreq performs an ioctl using an Ifreq structure for input and/or
// output. See the netdevice(7) man page for details.
func ( int,  uint,  *Ifreq) error {
	// It is possible we will add more fields to *Ifreq itself later to prevent
	// misuse, so pass the raw *ifreq directly.
	return ioctlPtr(, , unsafe.Pointer(&.raw))
}

// TODO(mdlayher): export if and when IfreqData is exported.

// ioctlIfreqData performs an ioctl using an ifreqData structure for input
// and/or output. See the netdevice(7) man page for details.
func ioctlIfreqData( int,  uint,  *ifreqData) error {
	// The memory layout of IfreqData (type-safe) and ifreq (not type-safe) are
	// identical so pass *IfreqData directly.
	return ioctlPtr(, , unsafe.Pointer())
}

// IoctlKCMClone attaches a new file descriptor to a multiplexor by cloning an
// existing KCM socket, returning a structure containing the file descriptor of
// the new socket.
func ( int) (*KCMClone, error) {
	var  KCMClone
	if  := ioctlPtr(, SIOCKCMCLONE, unsafe.Pointer(&));  != nil {
		return nil, 
	}

	return &, nil
}

// IoctlKCMAttach attaches a TCP socket and associated BPF program file
// descriptor to a multiplexor.
func ( int,  KCMAttach) error {
	return ioctlPtr(, SIOCKCMATTACH, unsafe.Pointer(&))
}

// IoctlKCMUnattach unattaches a TCP socket file descriptor from a multiplexor.
func ( int,  KCMUnattach) error {
	return ioctlPtr(, SIOCKCMUNATTACH, unsafe.Pointer(&))
}

// IoctlLoopGetStatus64 gets the status of the loop device associated with the
// file descriptor fd using the LOOP_GET_STATUS64 operation.
func ( int) (*LoopInfo64, error) {
	var  LoopInfo64
	if  := ioctlPtr(, LOOP_GET_STATUS64, unsafe.Pointer(&));  != nil {
		return nil, 
	}
	return &, nil
}

// IoctlLoopSetStatus64 sets the status of the loop device associated with the
// file descriptor fd using the LOOP_SET_STATUS64 operation.
func ( int,  *LoopInfo64) error {
	return ioctlPtr(, LOOP_SET_STATUS64, unsafe.Pointer())
}