# Maintainer: Omarchy <packages@omarchy.org>

pkgname=intel-ipu7-camera
pkgver=1.0.6
pkgrel=3
pkgdesc="Intel IPU7 MIPI camera stack for Hurrican/Performance (OV08X40 + hardware ISP)"
arch=('x86_64')
url="https://github.com/TsaiGaggery/hurrican_omarchy_enabling"
license=('GPL-2.0-or-later')
depends=(
  'dkms'
  'v4l2loopback-dkms'
  'v4l2-relayd'
  'gstreamer'
  'gst-plugins-base'
  'gst-plugins-good'
  'gst-plugins-bad'
  'jsoncpp'
  'libdrm'
)
makedepends=(
  'git'
  'base-devel'
  'cmake'
  'autoconf'
  'automake'
  'libtool'
  'pkgconf'
)
checkdepends=('linux-omarchy-headers')
install=intel-ipu7-camera.install
options=('!strip')

_ipu7_drivers_commit="a88b19096a738d0708742a78d6540d6d4a3021ff"
_vision_drivers_commit="a8d772f261bc90376944956b7bfd49b325ffa2f2"
_ipu7_camera_bins_commit="403c67db6b279dd02752f11db6a34552f31a3ac5"
_ipu7_camera_hal_commit="b1f6ebef12111fb5da0133b144d69dd9b001836c"
_icamerasrc_commit="4fb31db76b618aae72184c59314b839dedb42689"

# Linux 7.2 moved the Intel CVS (Computer Vision Sensing) controller into the
# IPU media graph, so the sensor only appears once drivers/media/i2c/cvs is
# loaded. linux-omarchy builds that driver in-tree, signed and carrying the
# XPS 14 speaker-ID wake-IRQ fix, and camera-init loads it. Kernels before 7.2
# use the legacy misc driver from vision-drivers instead.
#
# 0008-0011 are image quality fixes for the XPS 14 / 16 camera:
# - 0011: the graph asks for ISP tuning mode 4, which the OV08X40 tuning does
#   not carry, so no ISP tuning at all (noise reduction, TNR, sharpening, ...)
#   reached the hardware. Fall back to the tuning's default ISP container.
# - 0010: the tuning makes AIQ emit the raw analog gain register code, but
#   the in-tree ov08x40 driver takes half of it, so the sensor ran at twice
#   the gain AE and the ISP noise model assumed.
# - 0008: the HAL ignored the requested YUV range and always produced
#   full-range frames that consumers decode as limited range.
# - 0009: icamerasrc pinned auto exposure to exactly 1/30 s; its new
#   fps-range property lets AE lengthen frames in dim light instead of
#   adding gain (see v4l2-relayd-ipu7.conf).

source=(
  "ipu7-drivers::git+https://github.com/intel/ipu7-drivers.git#commit=${_ipu7_drivers_commit}"
  "vision-drivers::git+https://github.com/intel/vision-drivers.git#commit=${_vision_drivers_commit}"
  "ipu7-camera-bins::git+https://github.com/intel/ipu7-camera-bins.git#commit=${_ipu7_camera_bins_commit}"
  "ipu7-camera-hal::git+https://github.com/intel/ipu7-camera-hal.git#commit=${_ipu7_camera_hal_commit}"
  "icamerasrc::git+https://github.com/intel/icamerasrc.git#commit=${_icamerasrc_commit}"
  "0004-ipu7-psys-register-device-bus.patch"
  "0005-ipu7-psys-harden-userptr-pinning.patch"
  "check-userptr-range.c"
  "0003-icvs-set-rgbcamera_pwrup_host-0-for-Panther-Lake.patch"
  "0005-camhal-MediaControl-route-through-Intel-CVS-bridge.patch"
  "0006-camhal-ipu75xa-ov08x40-Intel-CVS-formats.patch"
  "0012-camhal-ipu7x-ov08x40-Intel-CVS-formats.patch"
  "0008-camhal-honor-the-reduced-YUV-color-range.patch"
  "0009-icamerasrc-add-an-fps-range-property-for-auto-exposure.patch"
  "0010-camhal-scale-analog-gain-codes-to-the-ov08x40-driver-units.patch"
  "0011-camhal-fall-back-to-the-default-ISP-tuning-when-the-mode-is-missing.patch"
  "dkms-ipu7-drivers.conf"
  "dkms-vision-drivers.conf"
  "camera-deps.conf"
  "v4l2loopback-modprobe.conf"
  "camera-init.service"
  "intel-ipu7-camera.service"
  "hide-ipu7-v4l2.conf"
  "disable-libcamera.conf"
  "71-ipu7-hide-isys.rules"
  "70-ipu7-psys.rules"
  "camera-tmpfiles.conf"
  "ov08x40.yaml"
  "camera-sleep-hook"
  "v4l2-relayd-ipu7.conf"
  "v4l2-relayd-ipu7-override.conf"
  "camera-videosrc-init"
)
sha256sums=(
  'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP'
  'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP'
  'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP'
  'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP'
  'SKIP' 'SKIP' 'SKIP' 'SKIP'
)

prepare() {
  cd "${srcdir}/ipu7-drivers"
  # --fuzz=0: a security patch that lands somewhere other than its anchor still
  # compiles, and the build is the only place that can refuse it.
  patch -Np1 --fuzz=0 -i "${srcdir}/0004-ipu7-psys-register-device-bus.patch"
  patch -Np1 --fuzz=0 -i "${srcdir}/0005-ipu7-psys-harden-userptr-pinning.patch"

  cd "${srcdir}/vision-drivers"
  git config user.email "build@localhost"
  git config user.name "Build"
  if ! git log --oneline -1 | grep -q "rgbcamera_pwrup_host"; then
    git am "${srcdir}/0003-icvs-set-rgbcamera_pwrup_host-0-for-Panther-Lake.patch"
  fi

  # Route the media graph through the Linux 7.2 "Intel CVS" bridge entity
  cd "${srcdir}/ipu7-camera-hal"
  patch -Np1 -i "${srcdir}/0005-camhal-MediaControl-route-through-Intel-CVS-bridge.patch"
  patch -Np1 -i "${srcdir}/0006-camhal-ipu75xa-ov08x40-Intel-CVS-formats.patch"
  patch -Np1 -i "${srcdir}/0012-camhal-ipu7x-ov08x40-Intel-CVS-formats.patch"
  patch -Np1 -i "${srcdir}/0008-camhal-honor-the-reduced-YUV-color-range.patch"
  patch -Np1 -i "${srcdir}/0010-camhal-scale-analog-gain-codes-to-the-ov08x40-driver-units.patch"
  patch -Np1 -i "${srcdir}/0011-camhal-fall-back-to-the-default-ISP-tuning-when-the-mode-is-missing.patch"

  cd "${srcdir}/icamerasrc"
  patch -Np1 -i "${srcdir}/0009-icamerasrc-add-an-fps-range-property-for-auto-exposure.patch"

  # Stage proprietary libs/headers for build-time use
  local staging="${srcdir}/staging"
  rm -rf "${staging}"
  mkdir -p "${staging}/usr/lib" "${staging}/usr/include" "${staging}/usr/lib/pkgconfig"

  cd "${srcdir}/ipu7-camera-bins"
  cp -P lib/lib* "${staging}/usr/lib/"
  cp -r include/* "${staging}/usr/include/"
  cp -r lib/pkgconfig/* "${staging}/usr/lib/pkgconfig/"

  for pc in "${staging}"/usr/lib/pkgconfig/*.pc; do
    sed -i "s|^prefix=.*|prefix=${staging}/usr|" "$pc"
  done

  if [[ -d /usr/include/json ]] && [[ ! -e /usr/include/jsoncpp/json ]]; then
    mkdir -p "${staging}/usr/include/jsoncpp"
    ln -sf /usr/include/json "${staging}/usr/include/jsoncpp/json"
  fi
}

build() {
  local staging="${srcdir}/staging"

  export PKG_CONFIG_PATH="${staging}/usr/lib/pkgconfig:${PKG_CONFIG_PATH:-}"
  export LIBRARY_PATH="${staging}/usr/lib:${LIBRARY_PATH:-}"
  export LD_LIBRARY_PATH="${staging}/usr/lib:${LD_LIBRARY_PATH:-}"
  export CPATH="${staging}/usr/include:${CPATH:-}"

  cd "${srcdir}/ipu7-camera-hal"
  rm -rf build && mkdir -p build && cd build
  cmake -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_INSTALL_PREFIX=/usr \
    -DCMAKE_INSTALL_LIBDIR=lib \
    -DBUILD_CAMHAL_ADAPTOR=ON \
    -DBUILD_CAMHAL_PLUGIN=ON \
    -DIPU_VERSIONS="ipu7x;ipu75xa" \
    -DUSE_STATIC_GRAPH=ON \
    -DUSE_STATIC_GRAPH_AUTOGEN=ON \
    -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
    -DCMAKE_PREFIX_PATH="${staging}/usr" \
    -DCMAKE_LIBRARY_PATH="${staging}/usr/lib" \
    -DCMAKE_INCLUDE_PATH="${staging}/usr/include" \
    ..
  make -j"$(nproc)"

  make DESTDIR="${staging}" install
  install -Dm644 "${srcdir}/ipu7-camera-hal/libcamhal.pc" \
    "${staging}/usr/lib/pkgconfig/libcamhal.pc"
  sed -i "s|^prefix=.*|prefix=${staging}/usr|" "${staging}/usr/lib/pkgconfig/libcamhal.pc"

  cd "${srcdir}/icamerasrc"
  export CHROME_SLIM_CAMHAL=ON
  [[ ! -f configure ]] && ./autogen.sh
  ./configure --prefix=/usr
  make -j"$(nproc)"
}

check() {
  local driver_tree="${srcdir}/ipu7-drivers"
  local psys_source="${srcdir}/ipu7-drivers/drivers/media/pci/intel/ipu7/psys/ipu-psys.c"
  local check_tree="${srcdir}/ipu7-drivers-check"
  local kernel_build kernel_files grep_result result=0 attach_failure

  [[ -f $psys_source && -r $psys_source ]] || return 1
  grep -q 'kvmalloc_array(npages, sizeof(\*pages)' "${psys_source}" || return 1
  grep -q 'attach->len > MAX_RW_COUNT' "${psys_source}" || return 1
  if grep 'FOLL_FORCE' "${psys_source}" >/dev/null; then
    return 1
  else
    grep_result=$?
    (( grep_result == 1 )) || return 1
  fi
  attach_failure=$(sed -n '/^attach_fail:$/,+1p' "$psys_source") || return 1
  [[ $attach_failure == $'attach_fail:\n\tkbuf->db_attach = NULL;' ]] || return 1

  cc -std=c11 -O2 -Wall -Wextra -Werror \
    "${srcdir}/check-userptr-range.c" -o "${srcdir}/check-userptr-range" || return 1
  "${srcdir}/check-userptr-range" || return 1

  kernel_files=$(pacman -Qql linux-omarchy-headers) || return 1
  kernel_build="$(sed -n \
    '\#/build/Makefile$# { s#/Makefile$##; s#^#/#; p; q; }' <<<"$kernel_files")" || return 1
  if [[ ! -f "${kernel_build}/Makefile" ]]; then
    printf 'Unable to locate the linux-omarchy-headers build tree\n' >&2
    return 1
  fi

  (
    cd "${srcdir}"
    "${kernel_build}/scripts/checkpatch.pl" --no-tree --strict --no-signoff \
      0005-ipu7-psys-harden-userptr-pinning.patch
  ) || return 1

  rm -rf "${check_tree}" || return 1
  cp -a "${driver_tree}" "${check_tree}" || return 1
  if ! make -C "${check_tree}" BUILD_INTEL_IPU_ACPI=1 \
    KERNEL_SRC="${kernel_build}"; then
    rm -rf "${check_tree}"
    return 1
  fi
  [[ -s ${check_tree}/drivers/media/pci/intel/ipu7/psys/intel-ipu7-psys.ko ]] || result=1
  rm -rf "${check_tree}" || return 1
  return "$result"
}

package() {
  # DKMS: IPU7 drivers (ISYS + PSYS + ACPI)
  local ipu7_dkms_dir="${pkgdir}/usr/src/ipu7-drivers-${pkgver}"
  install -dm755 "${ipu7_dkms_dir}"
  cp -r "${srcdir}/ipu7-drivers/"* "${ipu7_dkms_dir}/"
  rm -rf "${ipu7_dkms_dir}/.git"
  install -Dm644 "${srcdir}/dkms-ipu7-drivers.conf" "${ipu7_dkms_dir}/dkms.conf"
  sed -i "s/@PKGVER@/${pkgver}/" "${ipu7_dkms_dir}/dkms.conf"

  # DKMS: legacy Vision drivers (CVS misc driver), kernels before 7.2
  local cvs_dkms_dir="${pkgdir}/usr/src/vision-drivers-${pkgver}"
  install -dm755 "${cvs_dkms_dir}"
  cp -r "${srcdir}/vision-drivers/"* "${cvs_dkms_dir}/"
  install -Dm644 "${srcdir}/dkms-vision-drivers.conf" "${cvs_dkms_dir}/dkms.conf"
  sed -i "s/@PKGVER@/${pkgver}/" "${cvs_dkms_dir}/dkms.conf"

  # Firmware
  install -dm755 "${pkgdir}/usr/lib/firmware/intel/ipu"
  install -Dm644 "${srcdir}/ipu7-camera-bins/lib/firmware/intel/ipu/"*.bin \
    -t "${pkgdir}/usr/lib/firmware/intel/ipu/"

  # Proprietary libraries + headers from ipu7-camera-bins
  cd "${srcdir}/ipu7-camera-bins"
  install -dm755 "${pkgdir}/usr/lib"
  cp -P lib/lib* "${pkgdir}/usr/lib/"
  install -dm755 "${pkgdir}/usr/include"
  cp -r include/* "${pkgdir}/usr/include/"
  install -dm755 "${pkgdir}/usr/lib/pkgconfig"
  cp -r lib/pkgconfig/* "${pkgdir}/usr/lib/pkgconfig/"

  # Camera HAL + config
  cd "${srcdir}/ipu7-camera-hal/build"
  make DESTDIR="${pkgdir}" install

  cd "${srcdir}/ipu7-camera-hal"
  install -dm755 "${pkgdir}/usr/share/defaults/etc/camera"
  install -Dm644 config/linux/ipu75xa/libcamhal_configs.json \
    "${pkgdir}/usr/share/defaults/etc/camera/"
  install -Dm644 config/linux/ipu75xa/*.aiqb \
    -t "${pkgdir}/usr/share/defaults/etc/camera/"

  install -dm755 "${pkgdir}/etc/camera/ipu75xa/gcss"
  install -Dm644 config/linux/ipu75xa/gcss/*.bin \
    -t "${pkgdir}/etc/camera/ipu75xa/gcss/"

  install -dm755 "${pkgdir}/etc/camera/ipu75xa/sensors"
  install -Dm644 config/linux/ipu75xa/sensors/*.json \
    -t "${pkgdir}/etc/camera/ipu75xa/sensors/"

  install -Dm644 config/linux/ipu75xa/pipe_scheduler_profiles.json \
    "${pkgdir}/etc/camera/ipu75xa/"
  install -Dm644 config/linux/ipu75xa/pnp_profiles.json \
    "${pkgdir}/etc/camera/ipu75xa/"

  # icamerasrc GStreamer plugin
  cd "${srcdir}/icamerasrc"
  make DESTDIR="${pkgdir}" install

  # modprobe / modules-load
  install -Dm644 "${srcdir}/camera-deps.conf" \
    "${pkgdir}/usr/lib/modprobe.d/camera-deps.conf"
  install -Dm644 "${srcdir}/v4l2loopback-modprobe.conf" \
    "${pkgdir}/usr/lib/modprobe.d/v4l2loopback-camera.conf"

  # systemd
  install -Dm644 "${srcdir}/camera-init.service" \
    "${pkgdir}/usr/lib/systemd/system/camera-init.service"
  install -Dm644 "${srcdir}/intel-ipu7-camera.service" \
    "${pkgdir}/usr/lib/systemd/system/intel-ipu7-camera.service"

  # WirePlumber
  install -Dm644 "${srcdir}/hide-ipu7-v4l2.conf" \
    "${pkgdir}/usr/share/wireplumber/wireplumber.conf.d/hide-ipu7-v4l2.conf"
  install -Dm644 "${srcdir}/disable-libcamera.conf" \
    "${pkgdir}/usr/share/wireplumber/wireplumber.conf.d/disable-libcamera.conf"

  # udev rules
  install -Dm644 "${srcdir}/71-ipu7-hide-isys.rules" \
    "${pkgdir}/usr/lib/udev/rules.d/71-ipu7-hide-isys.rules"
  # Root-only: the relay is the PSYS node's only user, and the driver's buffer
  # lifecycle has use-after-free bugs that anyone who can open it can reach.
  install -Dm644 "${srcdir}/70-ipu7-psys.rules" \
    "${pkgdir}/usr/lib/udev/rules.d/70-ipu7-psys.rules"

  # v4l2-relayd config for IPU7 camera
  install -Dm644 "${srcdir}/v4l2-relayd-ipu7.conf" \
    "${pkgdir}/etc/v4l2-relayd.d/ipu7.conf"
  install -Dm644 "${srcdir}/v4l2-relayd-ipu7-override.conf" \
    "${pkgdir}/etc/systemd/system/v4l2-relayd@ipu7.service.d/override.conf"
  install -Dm644 "${srcdir}/camera-tmpfiles.conf" \
    "${pkgdir}/usr/lib/tmpfiles.d/camera.conf"
  install -Dm644 "${srcdir}/ov08x40.yaml" \
    "${pkgdir}/usr/share/libcamera/ipa/simple/ov08x40.yaml"

  # Sleep hook — staged here, installed to system-sleep by the .install scriptlet
  install -Dm755 "${srcdir}/camera-sleep-hook" \
    "${pkgdir}/usr/share/intel-ipu7-camera/camera-sleep-hook"

  # Picks the relay pipeline for this board; run before each relay start
  install -Dm755 "${srcdir}/camera-videosrc-init" \
    "${pkgdir}/usr/share/intel-ipu7-camera/camera-videosrc-init"
}
