#!/bin/bash # ============================================================================== # FaceTime HD Camera Driver Installer for Linux # # Installs the FaceTime HD camera driver on Linux for MacBook Air, MacBook Pro, # and iMac models that have the Broadcom 1570 FaceTime HD camera (connected # via PCIe, not USB like newer models). # # Compatible with MacBook Air A1466 EMC 3178 and similar models. # # What this script does: # 1. Detects your distro (Ubuntu/Mint/Debian/Fedora) and kernel version # 2. Checks for Secure Boot (the unsigned module won't load with SB enabled) # 3. Installs build dependencies (gcc, kernel headers, DKMS, etc.) # 4. Cleans up any previous facetimehd installations # 5. Downloads and installs the camera firmware from Apple's macOS driver # 6. Downloads, patches, and installs the facetimehd kernel module via DKMS # 7. Blacklists the conflicting bdc_pci module # 8. Loads the module and verifies the camera appears as /dev/videoN # # DKMS ensures the module is automatically rebuilt when the kernel is updated. # # The firmware extraction step downloads Apple's Boot Camp driver package, # extracts the camera firmware binary, and places it where the kernel module # expects to find it (/lib/firmware/facetimehd/). # # Usage: # chmod +x facetimehd-installer.sh # ./facetimehd-installer.sh # (Do NOT run with sudo — the script uses sudo internally where needed) # ============================================================================== 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 < /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 "$@"