451 lines
No EOL
13 KiB
Bash
Executable file
451 lines
No EOL
13 KiB
Bash
Executable file
#!/bin/bash
|
|
|
|
# FaceTime HD Camera Installation Script for Linux Kernel 6.8+
|
|
# Compatible with MacBook Air A1466 EMC 3178 and similar models
|
|
# Author: System Script
|
|
# Version: 1.0
|
|
# Last Updated: 2025
|
|
|
|
set -e
|
|
|
|
# Color codes for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Script name for logging
|
|
SCRIPT_NAME=$(basename "$0")
|
|
LOG_FILE="/tmp/facetimehd-install-$(date +%Y%m%d-%H%M%S).log"
|
|
|
|
# Function to print colored output
|
|
print_status() {
|
|
echo -e "${BLUE}[${SCRIPT_NAME}]${NC} $1" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
print_success() {
|
|
echo -e "${GREEN}[✓]${NC} $1" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
print_error() {
|
|
echo -e "${RED}[✗]${NC} $1" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
print_warning() {
|
|
echo -e "${YELLOW}[!]${NC} $1" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
# Function to check if running as root
|
|
check_root() {
|
|
if [[ $EUID -eq 0 ]]; then
|
|
print_error "This script should not be run as root!"
|
|
print_status "Please run without sudo: ./$SCRIPT_NAME"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Function to detect distribution
|
|
detect_distro() {
|
|
if [ -f /etc/os-release ]; then
|
|
. /etc/os-release
|
|
OS=$NAME
|
|
VER=$VERSION_ID
|
|
else
|
|
print_error "Cannot detect distribution"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Function to check kernel version
|
|
check_kernel() {
|
|
KERNEL_VERSION=$(uname -r)
|
|
KERNEL_MAJOR=$(echo $KERNEL_VERSION | cut -d. -f1)
|
|
KERNEL_MINOR=$(echo $KERNEL_VERSION | cut -d. -f2)
|
|
|
|
print_status "Detected kernel version: $KERNEL_VERSION"
|
|
|
|
if [[ $KERNEL_MAJOR -lt 5 ]] || ([[ $KERNEL_MAJOR -eq 5 ]] && [[ $KERNEL_MINOR -lt 7 ]]); then
|
|
print_warning "Kernel version is older than 5.7, using legacy installation method"
|
|
USE_LEGACY=true
|
|
else
|
|
USE_LEGACY=false
|
|
fi
|
|
}
|
|
|
|
# Function to check if camera is already working
|
|
check_camera() {
|
|
if [ -e /dev/video0 ] || [ -e /dev/video1 ]; then
|
|
if lsmod | grep -q facetimehd; then
|
|
print_warning "FaceTime HD camera driver appears to be already installed"
|
|
read -p "Do you want to reinstall? (y/N): " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
print_status "Exiting..."
|
|
exit 0
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Function to check and disable Secure Boot if needed
|
|
check_secure_boot() {
|
|
if command -v mokutil &> /dev/null; then
|
|
if mokutil --sb-state 2>&1 | grep -q "SecureBoot enabled"; then
|
|
print_warning "Secure Boot is enabled. The camera driver may not load."
|
|
print_status "You have three options:"
|
|
echo " 1. Disable Secure Boot in BIOS/UEFI (recommended)"
|
|
echo " 2. Sign the kernel module (advanced)"
|
|
echo " 3. Continue anyway (module may not load)"
|
|
read -p "Choose option (1-3): " -n 1 -r
|
|
echo
|
|
case $REPLY in
|
|
1)
|
|
print_status "Please reboot and disable Secure Boot in BIOS/UEFI settings"
|
|
print_status "Then run this script again"
|
|
exit 0
|
|
;;
|
|
2)
|
|
SIGN_MODULE=true
|
|
;;
|
|
3)
|
|
print_warning "Continuing with Secure Boot enabled..."
|
|
;;
|
|
esac
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Function to install dependencies
|
|
install_dependencies() {
|
|
print_status "Installing required dependencies..."
|
|
|
|
if [[ "$OS" == "Ubuntu" ]] || [[ "$OS" == "Linux Mint" ]] || [[ "$OS" == "Debian"* ]]; then
|
|
sudo apt update
|
|
sudo apt install -y \
|
|
git \
|
|
curl \
|
|
xz-utils \
|
|
cpio \
|
|
make \
|
|
gcc \
|
|
linux-headers-$(uname -r) \
|
|
libssl-dev \
|
|
checkinstall \
|
|
build-essential \
|
|
dkms \
|
|
v4l-utils || {
|
|
print_error "Failed to install dependencies"
|
|
exit 1
|
|
}
|
|
elif [[ "$OS" == "Fedora" ]]; then
|
|
sudo dnf install -y \
|
|
git \
|
|
curl \
|
|
xz \
|
|
cpio \
|
|
make \
|
|
gcc \
|
|
kernel-devel-$(uname -r) \
|
|
openssl-devel \
|
|
dkms \
|
|
v4l-utils || {
|
|
print_error "Failed to install dependencies"
|
|
exit 1
|
|
}
|
|
else
|
|
print_error "Unsupported distribution: $OS"
|
|
exit 1
|
|
fi
|
|
|
|
print_success "Dependencies installed successfully"
|
|
}
|
|
|
|
# Function to remove old installations
|
|
cleanup_old_installation() {
|
|
print_status "Cleaning up old installations..."
|
|
|
|
# Unload module if loaded
|
|
if lsmod | grep -q facetimehd; then
|
|
sudo modprobe -r facetimehd 2>/dev/null || true
|
|
fi
|
|
|
|
# Remove old DKMS installations
|
|
if dkms status | grep -q facetimehd; then
|
|
sudo dkms remove facetimehd/0.6.13 --all 2>/dev/null || true
|
|
sudo dkms remove facetimehd/0.1 --all 2>/dev/null || true
|
|
fi
|
|
|
|
# Remove old files
|
|
sudo rm -rf /usr/src/facetimehd* 2>/dev/null || true
|
|
sudo rm -f /lib/modules/*/extra/facetimehd.ko* 2>/dev/null || true
|
|
|
|
print_success "Cleanup completed"
|
|
}
|
|
|
|
# Function to download and install firmware
|
|
install_firmware() {
|
|
print_status "Downloading and installing camera firmware..."
|
|
|
|
WORK_DIR=$(mktemp -d)
|
|
cd "$WORK_DIR"
|
|
|
|
# Clone firmware repository
|
|
git clone https://github.com/patjak/facetimehd-firmware.git || {
|
|
print_error "Failed to download firmware repository"
|
|
exit 1
|
|
}
|
|
|
|
cd facetimehd-firmware
|
|
|
|
# Build and install firmware
|
|
make || {
|
|
print_error "Failed to build firmware"
|
|
exit 1
|
|
}
|
|
|
|
sudo make install || {
|
|
print_error "Failed to install firmware"
|
|
exit 1
|
|
}
|
|
|
|
# Verify firmware installation
|
|
if [ ! -f /lib/firmware/facetimehd/firmware.bin ]; then
|
|
print_warning "Firmware not found in expected location, creating symlink..."
|
|
sudo mkdir -p /lib/firmware/facetimehd
|
|
if [ -f /usr/lib/firmware/facetimehd/firmware.bin ]; then
|
|
sudo ln -sf /usr/lib/firmware/facetimehd/firmware.bin /lib/firmware/facetimehd/firmware.bin
|
|
else
|
|
print_error "Firmware installation failed"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
print_success "Firmware installed successfully"
|
|
cd ~
|
|
rm -rf "$WORK_DIR"
|
|
}
|
|
|
|
# Function to install driver for kernel 6.8+
|
|
install_driver() {
|
|
print_status "Downloading and installing FaceTime HD driver..."
|
|
|
|
WORK_DIR=$(mktemp -d)
|
|
cd "$WORK_DIR"
|
|
|
|
# For kernel 6.8+, try the updated repository first
|
|
if [[ $KERNEL_MAJOR -ge 6 ]] && [[ $KERNEL_MINOR -ge 8 ]]; then
|
|
print_status "Using updated driver for kernel 6.8+"
|
|
|
|
# Try multiple repositories in order of compatibility
|
|
REPOS=(
|
|
"https://github.com/patjak/facetimehd.git"
|
|
"https://github.com/kekrby/facetimehd.git"
|
|
"https://github.com/bartkessels/facetimehd.git"
|
|
)
|
|
|
|
CLONED=false
|
|
for repo in "${REPOS[@]}"; do
|
|
print_status "Trying repository: $repo"
|
|
if git clone "$repo" facetimehd 2>/dev/null; then
|
|
CLONED=true
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [ "$CLONED" = false ]; then
|
|
print_error "Failed to download any driver repository"
|
|
exit 1
|
|
fi
|
|
else
|
|
# For older kernels, use the standard repository
|
|
git clone https://github.com/patjak/facetimehd.git || {
|
|
print_error "Failed to download driver repository"
|
|
exit 1
|
|
}
|
|
fi
|
|
|
|
cd facetimehd
|
|
|
|
# Apply patches for kernel 6.8+ if needed
|
|
if [[ $KERNEL_MAJOR -ge 6 ]]; then
|
|
print_status "Applying kernel 6.x compatibility patches..."
|
|
|
|
# Fix for VFL_TYPE_GRABBER deprecation
|
|
if grep -q "VFL_TYPE_GRABBER" fthd_v4l2.c 2>/dev/null; then
|
|
sed -i 's/VFL_TYPE_GRABBER/VFL_TYPE_VIDEO/g' fthd_v4l2.c
|
|
fi
|
|
|
|
# Fix for other kernel 6.x API changes
|
|
if grep -q "v4l2_device_release" fthd_v4l2.c 2>/dev/null; then
|
|
sed -i 's/v4l2_device_release/video_device_release/g' fthd_v4l2.c
|
|
fi
|
|
fi
|
|
|
|
# Install via DKMS
|
|
print_status "Installing driver via DKMS..."
|
|
|
|
DRIVER_VERSION="0.6.13"
|
|
sudo cp -r . "/usr/src/facetimehd-$DRIVER_VERSION"
|
|
|
|
# Create DKMS configuration if it doesn't exist
|
|
if [ ! -f "/usr/src/facetimehd-$DRIVER_VERSION/dkms.conf" ]; then
|
|
sudo tee "/usr/src/facetimehd-$DRIVER_VERSION/dkms.conf" > /dev/null <<EOF
|
|
PACKAGE_NAME="facetimehd"
|
|
PACKAGE_VERSION="$DRIVER_VERSION"
|
|
BUILT_MODULE_NAME[0]="facetimehd"
|
|
DEST_MODULE_LOCATION[0]="/extra"
|
|
AUTOINSTALL="yes"
|
|
MAKE="make -C \${kernel_source_dir} M=\${dkms_tree}/\${PACKAGE_NAME}/\${PACKAGE_VERSION}/build modules"
|
|
CLEAN="make -C \${kernel_source_dir} M=\${dkms_tree}/\${PACKAGE_NAME}/\${PACKAGE_VERSION}/build clean"
|
|
EOF
|
|
fi
|
|
|
|
sudo dkms add -m facetimehd -v "$DRIVER_VERSION" || {
|
|
print_error "Failed to add driver to DKMS"
|
|
exit 1
|
|
}
|
|
|
|
sudo dkms build -m facetimehd -v "$DRIVER_VERSION" || {
|
|
print_error "Failed to build driver with DKMS"
|
|
exit 1
|
|
}
|
|
|
|
sudo dkms install -m facetimehd -v "$DRIVER_VERSION" || {
|
|
print_error "Failed to install driver with DKMS"
|
|
exit 1
|
|
}
|
|
|
|
print_success "Driver installed successfully"
|
|
cd ~
|
|
rm -rf "$WORK_DIR"
|
|
}
|
|
|
|
# Function to configure module loading
|
|
configure_module() {
|
|
print_status "Configuring module loading..."
|
|
|
|
# Blacklist conflicting modules
|
|
echo 'blacklist bdc_pci' | sudo tee /etc/modprobe.d/blacklist-facetimehd.conf > /dev/null
|
|
|
|
# Add facetimehd to modules
|
|
if ! grep -q "^facetimehd$" /etc/modules 2>/dev/null; then
|
|
echo 'facetimehd' | sudo tee -a /etc/modules > /dev/null
|
|
fi
|
|
|
|
# Load the module
|
|
print_status "Loading FaceTime HD module..."
|
|
sudo modprobe -r bdc_pci 2>/dev/null || true
|
|
sudo modprobe facetimehd || {
|
|
print_error "Failed to load module"
|
|
print_status "Check dmesg for errors: sudo dmesg | tail -20"
|
|
exit 1
|
|
}
|
|
|
|
print_success "Module configured and loaded"
|
|
}
|
|
|
|
# Function to verify installation
|
|
verify_installation() {
|
|
print_status "Verifying installation..."
|
|
|
|
# Check if module is loaded
|
|
if ! lsmod | grep -q facetimehd; then
|
|
print_error "Module is not loaded"
|
|
return 1
|
|
fi
|
|
|
|
# Check for video device
|
|
if [ ! -e /dev/video0 ] && [ ! -e /dev/video1 ] && [ ! -e /dev/video2 ]; then
|
|
print_error "No video device found"
|
|
return 1
|
|
fi
|
|
|
|
# Get video device
|
|
VIDEO_DEVICE=$(ls /dev/video* 2>/dev/null | head -1)
|
|
|
|
if [ -n "$VIDEO_DEVICE" ]; then
|
|
print_success "Camera device found at: $VIDEO_DEVICE"
|
|
|
|
# Show camera information
|
|
print_status "Camera information:"
|
|
v4l2-ctl -d "$VIDEO_DEVICE" --info 2>/dev/null || true
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# Function to test camera
|
|
test_camera() {
|
|
print_status "Would you like to test the camera now? (y/N): "
|
|
read -n 1 -r
|
|
echo
|
|
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
VIDEO_DEVICE=$(ls /dev/video* 2>/dev/null | head -1)
|
|
|
|
if command -v cheese &> /dev/null; then
|
|
print_status "Starting Cheese..."
|
|
cheese &
|
|
elif command -v guvcview &> /dev/null; then
|
|
print_status "Starting guvcview..."
|
|
guvcview &
|
|
else
|
|
print_warning "No camera application found. Install cheese or guvcview to test."
|
|
print_status "You can install with: sudo apt install cheese"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Main installation flow
|
|
main() {
|
|
clear
|
|
echo "======================================"
|
|
echo "FaceTime HD Camera Installation Script"
|
|
echo "======================================"
|
|
echo
|
|
print_status "Log file: $LOG_FILE"
|
|
echo
|
|
|
|
# Pre-installation checks
|
|
check_root
|
|
detect_distro
|
|
check_kernel
|
|
check_camera
|
|
check_secure_boot
|
|
|
|
# Installation
|
|
install_dependencies
|
|
cleanup_old_installation
|
|
install_firmware
|
|
install_driver
|
|
configure_module
|
|
|
|
# Post-installation
|
|
if verify_installation; then
|
|
print_success "Installation completed successfully!"
|
|
echo
|
|
print_status "Camera should now be working."
|
|
print_status "You can test it with applications like:"
|
|
echo " - cheese"
|
|
echo " - guvcview"
|
|
echo " - Google Chrome/Chromium"
|
|
echo " - Firefox"
|
|
echo
|
|
test_camera
|
|
else
|
|
print_error "Installation completed but verification failed"
|
|
print_status "Please check the log file: $LOG_FILE"
|
|
print_status "And kernel messages: sudo dmesg | grep -i facetime"
|
|
fi
|
|
|
|
echo
|
|
print_status "If you encounter issues, please check:"
|
|
echo " 1. Secure Boot status (disable if enabled)"
|
|
echo " 2. Kernel messages: sudo dmesg | grep -i facetime"
|
|
echo " 3. Module status: lsmod | grep facetimehd"
|
|
echo " 4. Log file: $LOG_FILE"
|
|
}
|
|
|
|
# Run main function
|
|
main "$@" |