// 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 &, 
}

// IoctlGetEthtoolTsInfo fetches ethtool timestamping and PHC
// association for the network device specified by ifname.
func ( int,  string) (*EthtoolTsInfo, error) {
	,  := NewIfreq()
	if  != nil {
		return nil, 
	}

	 := EthtoolTsInfo{Cmd: ETHTOOL_GET_TS_INFO}
	 := .withData(unsafe.Pointer(&))

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

// IoctlGetHwTstamp retrieves the hardware timestamping configuration
// for the network device specified by ifname.
func ( int,  string) (*HwTstampConfig, error) {
	,  := NewIfreq()
	if  != nil {
		return nil, 
	}

	 := HwTstampConfig{}
	 := .withData(unsafe.Pointer(&))

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

// IoctlSetHwTstamp updates the hardware timestamping configuration for
// the network device specified by ifname.
func ( int,  string,  *HwTstampConfig) error {
	,  := NewIfreq()
	if  != nil {
		return 
	}
	 := .withData(unsafe.Pointer())
	return ioctlIfreqData(, SIOCSHWTSTAMP, &)
}

// FdToClockID derives the clock ID from the file descriptor number
// - see clock_gettime(3), FD_TO_CLOCKID macros. The resulting ID is
// suitable for system calls like ClockGettime.
func ( int) int32 { return int32((int(^) << 3) | 3) }

// IoctlPtpClockGetcaps returns the description of a given PTP device.
func ( int) (*PtpClockCaps, error) {
	var  PtpClockCaps
	 := ioctlPtr(, PTP_CLOCK_GETCAPS2, unsafe.Pointer(&))
	return &, 
}

// IoctlPtpSysOffsetPrecise returns a description of the clock
// offset compared to the system clock.
func ( int) (*PtpSysOffsetPrecise, error) {
	var  PtpSysOffsetPrecise
	 := ioctlPtr(, PTP_SYS_OFFSET_PRECISE2, unsafe.Pointer(&))
	return &, 
}

// IoctlPtpSysOffsetExtended returns an extended description of the
// clock offset compared to the system clock. The samples parameter
// specifies the desired number of measurements.
func ( int,  uint) (*PtpSysOffsetExtended, error) {
	 := PtpSysOffsetExtended{Samples: uint32()}
	 := ioctlPtr(, PTP_SYS_OFFSET_EXTENDED2, unsafe.Pointer(&))
	return &, 
}

// IoctlPtpPinGetfunc returns the configuration of the specified
// I/O pin on given PTP device.
func ( int,  uint) (*PtpPinDesc, error) {
	 := PtpPinDesc{Index: uint32()}
	 := ioctlPtr(, PTP_PIN_GETFUNC2, unsafe.Pointer(&))
	return &, 
}

// IoctlPtpPinSetfunc updates configuration of the specified PTP
// I/O pin.
func ( int,  *PtpPinDesc) error {
	return ioctlPtr(, PTP_PIN_SETFUNC2, unsafe.Pointer())
}

// IoctlPtpPeroutRequest configures the periodic output mode of the
// PTP I/O pins.
func ( int,  *PtpPeroutRequest) error {
	return ioctlPtr(, PTP_PEROUT_REQUEST2, unsafe.Pointer())
}

// IoctlPtpExttsRequest configures the external timestamping mode
// of the PTP I/O pins.
func ( int,  *PtpExttsRequest) error {
	return ioctlPtr(, PTP_EXTTS_REQUEST2, unsafe.Pointer())
}

// 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 ( 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())
}

// IoctlLoopConfigure configures all loop device parameters in a single step
func ( int,  *LoopConfig) error {
	return ioctlPtr(, LOOP_CONFIGURE, unsafe.Pointer())
}