diff --git a/build-deb.sh b/build-deb.sh index a6e31a7..71d74fc 100755 --- a/build-deb.sh +++ b/build-deb.sh @@ -8,16 +8,10 @@ ETC_DIR="/etc" PKG_DIR="/pkg-debian" OPT_DIR="/opt/magicmouse-hid" -DEB="magicmouse-hid_1.1.0-0.deb" +DEB="magicmouse-hid_2.0.0-0.deb" cp -rf ${DIR}${ETC_DIR} ${DIR}${PKG_DIR} -mkdir -p ${DIR}${PKG_DIR}${OPT_DIR} -# Copy scripts to /opt -cp -f ${DIR}/scripts/magic-mouse-2-add.sh ${DIR}${PKG_DIR}${OPT_DIR}/magic-mouse-2-add.sh -# cp -f ${DIR}/install.sh ${DIR}${PKG_DIR}${OPT_DIR}/install.sh -# cp -f ${DIR}/remove.sh ${DIR}${PKG_DIR}${OPT_DIR}/remove.sh - mkdir -p ${DIR}${PKG_DIR}${OPT_DIR}/scripts cp -f ${DIR}/scripts/install.sh ${DIR}${PKG_DIR}${OPT_DIR}/scripts/install.sh cp -f ${DIR}/scripts/remove.sh ${DIR}${PKG_DIR}${OPT_DIR}/scripts/remove.sh diff --git a/etc/udev/rules.d/10-magicmouse.rules b/etc/udev/rules.d/10-magicmouse.rules deleted file mode 100644 index fa97432..0000000 --- a/etc/udev/rules.d/10-magicmouse.rules +++ /dev/null @@ -1,9 +0,0 @@ -SUBSYSTEM=="input", \ - KERNEL=="mouse*", \ - DRIVER=="", \ - SUBSYSTEMS=="hid", \ - KERNELS=="0005:004C:0269*", \ - DRIVERS=="hid-generic|magicmouse", \ - ACTION=="add", \ - SYMLINK+="input/magicmouse-%k", \ - RUN+="/opt/magicmouse-hid/magic-mouse-2-add.sh" diff --git a/install.sh b/install.sh index 5b46cdd..6500bb0 100755 --- a/install.sh +++ b/install.sh @@ -9,8 +9,6 @@ set -e set -x DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -OPT_DIR="/opt/magicmouse-hid" -UDEV_DIR="/etc/udev/rules.d" MODPROBE_DIR="/etc/modprobe.d" @@ -21,17 +19,11 @@ cp -f ${DIR}${MODPROBE_DIR}/hid-magicmouse.conf ${MODPROBE_DIR}/hid-magicmouse.c chmod u+x ${DIR}/scripts/install.sh ${DIR}/scripts/install.sh -# Copy script to load the driver to OPT directory -mkdir -p ${OPT_DIR} -cp -f ${DIR}/scripts/magic-mouse-2-add.sh ${OPT_DIR}/magic-mouse-2-add.sh -chmod +x ${OPT_DIR}/magic-mouse-2-add.sh - -# Copy udev rule and reload udev -cp -f ${DIR}${UDEV_DIR}/10-magicmouse.rules ${UDEV_DIR}/10-magicmouse.rules -udevadm control -R - # Disable eSCO mode in Bluetooth to fix disconnection problems with the mouse echo 1 | tee /sys/module/bluetooth/parameters/disable_esco systemctl restart bluetooth # persist eSCO mode in Bluetooth setting -echo "options bluetooth disable_esco=1" | tee /etc/modprobe.d/bluetooth-tweaks.conf \ No newline at end of file +echo "options bluetooth disable_esco=1" | tee /etc/modprobe.d/bluetooth-tweaks.conf + +# Load driver +sudo modprobe -a hid_magicmouse \ No newline at end of file diff --git a/linux/drivers/hid/hid-magicmouse.c b/linux/drivers/hid/hid-magicmouse.c index 003261a..92c5740 100644 --- a/linux/drivers/hid/hid-magicmouse.c +++ b/linux/drivers/hid/hid-magicmouse.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include "hid-ids.h" @@ -168,6 +168,9 @@ struct magicmouse_sc { u8 size; } touches[MAX_TOUCHES]; int tracking_ids[MAX_TOUCHES]; + + struct hid_device *hdev; + struct delayed_work work; }; static int magicmouse_firm_touch(struct magicmouse_sc *msc) @@ -570,6 +573,21 @@ static int magicmouse_raw_event(struct hid_device *hdev, return 1; } +static int magicmouse_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct magicmouse_sc *msc = hid_get_drvdata(hdev); + if (msc->input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 && + field->report->id == MOUSE2_REPORT_ID) { + // magic_mouse_raw_event has done all the work. Skip hidinput. + // + // Specifically, hidinput may modify BTN_LEFT and BTN_RIGHT, + // breaking emulate_3button. + return 1; + } + return 0; +} + static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev) { int error; @@ -743,26 +761,66 @@ static int magicmouse_input_configured(struct hid_device *hdev, } + +static int magicmouse_enable_multitouch(struct hid_device *hdev) +{ + const u8 *feature; + const u8 feature_mt[] = { 0xD7, 0x01 }; + const u8 feature_mt_mouse2[] = { 0xF1, 0x02, 0x01 }; + const u8 feature_mt_trackpad2_usb[] = { 0x02, 0x01 }; + const u8 feature_mt_trackpad2_bt[] = { 0xF1, 0x02, 0x01 }; + u8 *buf; + int ret; + int feature_size; + + if (hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { + if (hdev->vendor == BT_VENDOR_ID_APPLE) { + feature_size = sizeof(feature_mt_trackpad2_bt); + feature = feature_mt_trackpad2_bt; + } else { /* USB_VENDOR_ID_APPLE */ + feature_size = sizeof(feature_mt_trackpad2_usb); + feature = feature_mt_trackpad2_usb; + } + } else if (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) { + feature_size = sizeof(feature_mt_mouse2); + feature = feature_mt_mouse2; + } else { + feature_size = sizeof(feature_mt); + feature = feature_mt; + } + + buf = kmemdup(feature, feature_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = hid_hw_raw_request(hdev, buf[0], buf, feature_size, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + kfree(buf); + return ret; +} + +static void magicmouse_enable_mt_work(struct work_struct *work) +{ + struct magicmouse_sc *msc = + container_of(work, struct magicmouse_sc, work.work); + int ret; + + ret = magicmouse_enable_multitouch(msc->hdev); + if (ret < 0) + hid_err(msc->hdev, "unable to request touch data (%d)\n", ret); +} + static int magicmouse_probe(struct hid_device *hdev, const struct hid_device_id *id) { - __u8 feature_mt_mouse2_bt[] = { 0xF1, 0x02, 0x01 }; - __u8 feature_mt[] = { 0xD7, 0x01 }; - __u8 feature_mt_trackpad2_usb[] = { 0x02, 0x01 }; - __u8 feature_mt_trackpad2_bt[] = { 0xF1, 0x02, 0x01 }; - __u8 *feature; struct magicmouse_sc *msc; struct hid_report *report; int ret; - int feature_size; - struct usb_interface *intf; if (id->vendor == USB_VENDOR_ID_APPLE && - id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { - intf = to_usb_interface(hdev->dev.parent); - if (intf->cur_altsetting->desc.bInterfaceNumber != 1) - return 0; - } + id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && + hdev->type != HID_TYPE_USBMOUSE) + return 0; msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL); if (msc == NULL) { @@ -771,6 +829,8 @@ static int magicmouse_probe(struct hid_device *hdev, } msc->scroll_accel = SCROLL_ACCEL_DEFAULT; + msc->hdev = hdev; + INIT_DEFERRABLE_WORK(&msc->work, magicmouse_enable_mt_work); msc->quirks = id->driver_data; hid_set_drvdata(hdev, msc); @@ -829,36 +889,14 @@ static int magicmouse_probe(struct hid_device *hdev, * but there seems to be no other way of switching the mode. * Thus the super-ugly hacky success check below. */ - if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE || - id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD) { - feature_size = sizeof(feature_mt); - feature = kmemdup(feature_mt, feature_size, GFP_KERNEL); - } - else if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2){ - feature_size = sizeof(feature_mt_mouse2_bt); - feature = kmemdup(feature_mt_mouse2_bt, feature_size, GFP_KERNEL); - } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 */ - if (id->vendor == BT_VENDOR_ID_APPLE) { - feature_size = sizeof(feature_mt_trackpad2_bt); - feature = kmemdup(feature_mt_trackpad2_bt, feature_size, - GFP_KERNEL); - } else { /* USB_VENDOR_ID_APPLE */ - feature_size = sizeof(feature_mt_trackpad2_usb); - feature = kmemdup(feature_mt_trackpad2_usb, feature_size, - GFP_KERNEL); - } - } - if (!feature) { - ret = -ENOMEM; - goto err_stop_hw; - } - ret = hid_hw_raw_request(hdev, feature[0], feature, feature_size, - HID_FEATURE_REPORT, HID_REQ_SET_REPORT); - kfree(feature); - if (ret != -EIO && ret != feature_size) { + ret = magicmouse_enable_multitouch(hdev); + if (ret != -EIO && ret < 0) { hid_err(hdev, "unable to request touch data (%d)\n", ret); goto err_stop_hw; } + if (ret == -EIO && id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) { + schedule_delayed_work(&msc->work, msecs_to_jiffies(500)); + } return 0; err_stop_hw: @@ -866,6 +904,13 @@ static int magicmouse_probe(struct hid_device *hdev, return ret; } +static void magicmouse_remove(struct hid_device *hdev) +{ + struct magicmouse_sc *msc = hid_get_drvdata(hdev); + cancel_delayed_work_sync(&msc->work); + hid_hw_stop(hdev); +} + static const struct hid_device_id magic_mice[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 }, @@ -885,7 +930,9 @@ static struct hid_driver magicmouse_driver = { .name = "magicmouse", .id_table = magic_mice, .probe = magicmouse_probe, + .remove = magicmouse_remove, .raw_event = magicmouse_raw_event, + .event = magicmouse_event, .input_mapping = magicmouse_input_mapping, .input_configured = magicmouse_input_configured, }; diff --git a/pkg-debian/DEBIAN/postinst b/pkg-debian/DEBIAN/postinst index 126044c..7fd1707 100755 --- a/pkg-debian/DEBIAN/postinst +++ b/pkg-debian/DEBIAN/postinst @@ -7,11 +7,8 @@ cd ${DIR} chmod u+x ${DIR}/scripts/install.sh ${DIR}/scripts/install.sh -# Copy script to load the driver to OPT directory -chmod +x ${DIR}/magic-mouse-2-add.sh - -# Copy udev rule and reload udev -udevadm control -R +# Load driver +sudo modprobe -a hid_magicmouse # Disable eSCO mode in Bluetooth to fix disconnection problems with the mouse echo 1 | tee /sys/module/bluetooth/parameters/disable_esco diff --git a/pkg-debian/DEBIAN/prerm b/pkg-debian/DEBIAN/prerm index 3a9d6eb..4b34b82 100755 --- a/pkg-debian/DEBIAN/prerm +++ b/pkg-debian/DEBIAN/prerm @@ -7,8 +7,8 @@ cd ${DIR} chmod u+x ${DIR}/scripts/remove.sh ${DIR}/scripts/remove.sh -# Reload udev after removing the udev rule -udevadm control -R +# Remove loaded driver +modprobe -r hid_magicmouse # Restart Bluetooth systemctl restart bluetooth diff --git a/remove.sh b/remove.sh index cb15154..97a3b6f 100755 --- a/remove.sh +++ b/remove.sh @@ -1,26 +1,25 @@ #!/bin/bash +if [ "$EUID" -ne 0 ] + then echo "Please run as root" + exit +fi + set -e set -x DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -OPT_DIR="/opt/magicmouse-hid" -UDEV_DIR="/etc/udev/rules.d" MODPROBE_DIR="/etc/modprobe.d" # Remove drive through DKMS chmod u+x ${DIR}/scripts/remove.sh ${DIR}/scripts/remove.sh +# Remove loaded driver +modprobe -r hid_magicmouse + # Remove Modprobe configuration file rm -f ${MODPROBE_DIR}/hid-magicmouse.conf -# Copy `.ko` and script to activate it to OPT directory -rm -rf ${OPT_DIR} - -# Remove the udev rule and reload udev -rm -f ${UDEV_DIR}/10-magicmouse.rules -udevadm control -R - # Restart Bluetooth systemctl restart bluetooth diff --git a/scripts/magic-mouse-2-add.sh b/scripts/magic-mouse-2-add.sh deleted file mode 100755 index 48fc368..0000000 --- a/scripts/magic-mouse-2-add.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -FILE=/tmp/magicmouse.lock - -reload() { - # Check is Lock File exists, if not create it and set trap on exit - if { set -C; 2>/dev/null >$FILE; }; then - trap "rm -f $FILE" EXIT - else - # Lock file exists. exiting. - exit - fi - - modprobe -r hid_magicmouse - sleep 2 - modprobe -a hid-generic hid_magicmouse - sleep 2 -} - -reload &