- roadrunner2/macbook12-spi-driver is at
commit 3b58c7b3b2e814abd5347372d842328c88801f76 (HEAD -> touchbar-driver-hid-driver, origin/touchbar-driver-hid-driver, origin/HEAD)
- torvalds/linux is at
commit b0be0eff1a5ab77d588b76bd8b1c92d5d17b3f73 (HEAD -> master, origin/master, origin/HEAD)
[user@personal linux]$ diff -Nur ~/git/macbook12-spi-driver/applespi.c ~/git/linux/drivers/input/keyboard/applespi.c | xclip -selection clipboard
--- /home/user/git/macbook12-spi-driver/applespi.c 2020-01-28 13:15:41.561000000 +0100
+++ /home/user/git/linux/drivers/input/keyboard/applespi.c 2020-01-28 13:07:22.311000000 +0100
@@ -48,15 +48,12 @@
#include <linux/efi.h>
#include <linux/input.h>
#include <linux/input/mt.h>
-#include <linux/jiffies.h>
-#include <linux/ktime.h>
#include <linux/leds.h>
#include <linux/module.h>
-#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/spi/spi.h>
-#include <linux/version.h>
#include <linux/wait.h>
+#include <linux/workqueue.h>
#include <asm/barrier.h>
#include <asm/unaligned.h>
@@ -65,14 +62,6 @@
#include "applespi.h"
#include "applespi_trace.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
-#define PRE_SPI_PROPERTIES
-#endif
-
-#ifdef PRE_SPI_PROPERTIES
-#include <linux/notifier.h>
-#endif
-
#define APPLESPI_PACKET_SIZE 256
#define APPLESPI_STATUS_SIZE 4
@@ -355,13 +344,6 @@
};
struct spi_settings {
-#ifdef PRE_SPI_PROPERTIES
- u64 spi_sclk_period; /* period in ns */
- u64 spi_word_size; /* in number of bits */
- u64 spi_bit_order; /* 1 = MSB_FIRST, 0 = LSB_FIRST */
- u64 spi_spo; /* clock polarity: 0 = low, 1 = high */
- u64 spi_sph; /* clock phase: 0 = first, 1 = second */
-#endif
u64 spi_cs_delay; /* cs-to-clk delay in us */
u64 reset_a2r_usec; /* active-to-receive delay? */
u64 reset_rec_usec; /* ? (cur val: 10) */
@@ -418,7 +400,7 @@
unsigned int cmd_msg_cntr;
/* lock to protect the above parameters and flags below */
spinlock_t cmd_msg_lock;
- ktime_t cmd_msg_queued;
+ bool cmd_msg_queued;
enum applespi_evt_type cmd_evt_type;
struct led_classdev backlight_info;
@@ -429,13 +411,7 @@
bool read_active;
bool write_active;
- struct applespi_complete_info {
- void (*complete)(void *context);
- struct applespi_data *applespi;
- } spi_complete[2];
- bool cancel_spi;
-
- wait_queue_head_t tp_info_complete;
+ struct work_struct work;
struct touchpad_info_protocol rcvd_tp_info;
struct dentry *debugfs_root;
@@ -617,61 +593,13 @@
spi_message_add_tail(st_t, msg);
}
-static bool applespi_async_outstanding(struct applespi_data *applespi)
-{
- return applespi->spi_complete[0].complete ||
- applespi->spi_complete[1].complete;
-}
-
-static void applespi_async_complete(void *context)
-{
- struct applespi_complete_info *info = context;
- struct applespi_data *applespi = info->applespi;
- unsigned long flags;
-
- info->complete(applespi);
-
- spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
-
- info->complete = NULL;
-
- if (applespi->cancel_spi && !applespi_async_outstanding(applespi))
- wake_up_all(&applespi->drain_complete);
-
- spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
-}
-
static int applespi_async(struct applespi_data *applespi,
struct spi_message *message, void (*complete)(void *))
{
- struct applespi_complete_info *info;
- int sts;
-
- if (applespi->cancel_spi) {
- if (!applespi_async_outstanding(applespi))
- wake_up_all(&applespi->drain_complete);
- return -ESHUTDOWN;
- }
-
- /*
- * There can only be at most 2 spi requests in flight, one for "reads"
- * and one for "writes".
- */
- if (!applespi->spi_complete[0].complete)
- info = &applespi->spi_complete[0];
- else
- info = &applespi->spi_complete[1];
- info->complete = complete;
- info->applespi = applespi;
-
- message->complete = applespi_async_complete;
- message->context = info;
+ message->complete = complete;
+ message->context = applespi;
- sts = spi_async(applespi->spi, message);
- if (sts)
- info->complete = NULL;
-
- return sts;
+ return spi_async(applespi->spi, message);
}
static inline bool applespi_check_write_status(struct applespi_data *applespi,
@@ -694,114 +622,6 @@
return true;
}
-#ifdef PRE_SPI_PROPERTIES
-
-struct appleacpi_spi_registration_info {
- struct class_interface cif;
- struct acpi_device *adev;
- struct spi_device *spi;
- struct spi_master *spi_master;
- struct delayed_work work;
- struct notifier_block slave_notifier;
-};
-
-struct applespi_acpi_map_entry {
- char *name;
- size_t field_offset;
-};
-
-static const struct applespi_acpi_map_entry applespi_spi_settings_map[] = {
- { "spiSclkPeriod", offsetof(struct spi_settings, spi_sclk_period) },
- { "spiWordSize", offsetof(struct spi_settings, spi_word_size) },
- { "spiBitOrder", offsetof(struct spi_settings, spi_bit_order) },
- { "spiSPO", offsetof(struct spi_settings, spi_spo) },
- { "spiSPH", offsetof(struct spi_settings, spi_sph) },
- { "spiCSDelay", offsetof(struct spi_settings, spi_cs_delay) },
- { "resetA2RUsec", offsetof(struct spi_settings, reset_a2r_usec) },
- { "resetRecUsec", offsetof(struct spi_settings, reset_rec_usec) },
-};
-
-static u8 *acpi_dsm_uuid = "a0b5b7c6-1318-441c-b0c9-fe695eaf949b";
-
-static int applespi_find_settings_field(const char *name)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(applespi_spi_settings_map); i++) {
- if (strcmp(applespi_spi_settings_map[i].name, name) == 0)
- return applespi_spi_settings_map[i].field_offset;
- }
-
- return -1;
-}
-
-static int applespi_get_spi_settings(acpi_handle handle,
- struct spi_settings *settings)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
- guid_t guid, *uuid = &guid;
-#else
- u8 uuid[16];
-#endif
- union acpi_object *spi_info;
- union acpi_object name;
- union acpi_object value;
- int i;
- int field_off;
- u64 *field;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
- guid_parse(acpi_dsm_uuid, uuid);
-#else
- acpi_str_to_uuid(acpi_dsm_uuid, uuid);
-#endif
-
- spi_info = acpi_evaluate_dsm(handle, uuid, 1, 1, NULL);
- if (!spi_info) {
- pr_err("Failed to get SPI info from _DSM method\n");
- return -ENODEV;
- }
- if (spi_info->type != ACPI_TYPE_PACKAGE) {
- pr_err("Unexpected data returned from SPI _DSM method: type=%d\n",
- spi_info->type);
- ACPI_FREE(spi_info);
- return -ENODEV;
- }
-
- /*
- * The data is stored in pairs of items, first a string containing
- * the name of the item, followed by an 8-byte buffer containing the
- * value in little-endian.
- */
- for (i = 0; i < spi_info->package.count - 1; i += 2) {
- name = spi_info->package.elements[i];
- value = spi_info->package.elements[i + 1];
-
- if (!(name.type == ACPI_TYPE_STRING &&
- value.type == ACPI_TYPE_BUFFER &&
- value.buffer.length == 8)) {
- pr_warn("Unexpected data returned from SPI _DSM method: name.type=%d, value.type=%d\n",
- name.type, value.type);
- continue;
- }
-
- field_off = applespi_find_settings_field(name.string.pointer);
- if (field_off < 0) {
- pr_debug("Skipping unknown SPI setting '%s'\n",
- name.string.pointer);
- continue;
- }
-
- field = (u64 *)((char *)settings + field_off);
- *field = le64_to_cpu(*((__le64 *)value.buffer.pointer));
- }
- ACPI_FREE(spi_info);
-
- return 0;
-}
-
-#else
-
static int applespi_get_spi_settings(struct applespi_data *applespi)
{
struct acpi_device *adev = ACPI_COMPANION(&applespi->spi->dev);
@@ -834,27 +654,16 @@
return 0;
}
-#endif
-
-static int applespi_setup_spi(struct applespi_data *applespi
-#ifdef PRE_SPI_PROPERTIES
- , acpi_handle spi_handle
-#endif
- )
+static int applespi_setup_spi(struct applespi_data *applespi)
{
int sts;
-#ifdef PRE_SPI_PROPERTIES
- sts = applespi_get_spi_settings(spi_handle, &applespi->spi_settings);
-#else
sts = applespi_get_spi_settings(applespi);
-#endif
if (sts)
return sts;
spin_lock_init(&applespi->cmd_msg_lock);
init_waitqueue_head(&applespi->drain_complete);
- init_waitqueue_head(&applespi->tp_info_complete);
return 0;
}
@@ -907,7 +716,7 @@
wake_up_all(&applespi->drain_complete);
if (is_write_msg) {
- applespi->cmd_msg_queued = 0;
+ applespi->cmd_msg_queued = false;
applespi_send_cmd_msg(applespi);
}
@@ -949,16 +758,8 @@
return 0;
/* check whether send is in progress */
- if (applespi->cmd_msg_queued) {
- if (ktime_ms_delta(ktime_get(), applespi->cmd_msg_queued) < 1000)
- return 0;
-
- dev_warn(&applespi->spi->dev, "Command %d timed out\n",
- applespi->cmd_evt_type);
-
- applespi->cmd_msg_queued = 0;
- applespi->write_active = false;
- }
+ if (applespi->cmd_msg_queued)
+ return 0;
/* set up packet */
memset(packet, 0, APPLESPI_PACKET_SIZE);
@@ -1055,7 +856,7 @@
return sts;
}
- applespi->cmd_msg_queued = ktime_get();
+ applespi->cmd_msg_queued = true;
applespi->write_active = true;
return 0;
@@ -1214,7 +1015,7 @@
const struct applespi_tp_info *tp_info = &applespi->tp_info;
int i, n;
- /* touchpad_input_dev is set async in probe */
+ /* touchpad_input_dev is set async in worker */
input = smp_load_acquire(&applespi->touchpad_input_dev);
if (!input)
return; /* touchpad isn't initialized yet */
@@ -1468,15 +1269,15 @@
/* finger touch area */
input_set_abs_params(touchpad_input_dev, ABS_MT_TOUCH_MAJOR,
- 0, 2048, 0, 0);
+ 0, 5000, 0, 0);
input_set_abs_params(touchpad_input_dev, ABS_MT_TOUCH_MINOR,
- 0, 2048, 0, 0);
+ 0, 5000, 0, 0);
/* finger approach area */
input_set_abs_params(touchpad_input_dev, ABS_MT_WIDTH_MAJOR,
- 0, 2048, 0, 0);
+ 0, 5000, 0, 0);
input_set_abs_params(touchpad_input_dev, ABS_MT_WIDTH_MINOR,
- 0, 2048, 0, 0);
+ 0, 5000, 0, 0);
/* finger orientation */
input_set_abs_params(touchpad_input_dev, ABS_MT_ORIENTATION,
@@ -1518,14 +1319,26 @@
return 0;
}
+static void applespi_worker(struct work_struct *work)
+{
+ struct applespi_data *applespi =
+ container_of(work, struct applespi_data, work);
+
+ applespi_register_touchpad_device(applespi, &applespi->rcvd_tp_info);
+}
+
static void applespi_handle_cmd_response(struct applespi_data *applespi,
struct spi_packet *packet,
struct message *message)
{
if (packet->device == PACKET_DEV_INFO &&
le16_to_cpu(message->type) == 0x1020) {
+ /*
+ * We're not allowed to sleep here, but registering an input
+ * device can sleep.
+ */
applespi->rcvd_tp_info = message->tp_info;
- wake_up_all(&applespi->tp_info_complete);
+ schedule_work(&applespi->work);
return;
}
@@ -1813,7 +1626,6 @@
struct applespi_data *applespi;
acpi_handle spi_handle = ACPI_HANDLE(&spi->dev);
acpi_status acpi_sts;
- unsigned long flags;
int sts, i;
unsigned long long gpe, usb_status;
@@ -1832,6 +1644,8 @@
applespi->spi = spi;
+ INIT_WORK(&applespi->work, applespi_worker);
+
/* store the driver data */
spi_set_drvdata(spi, applespi);
@@ -1872,11 +1686,7 @@
}
/* switch on the SPI interface */
- sts = applespi_setup_spi(applespi
-#ifdef PRE_SPI_PROPERTIES
- , spi_handle
-#endif
- );
+ sts = applespi_setup_spi(applespi);
if (sts)
return sts;
@@ -1963,22 +1773,6 @@
/* trigger touchpad setup */
applespi_init(applespi, false);
- /* set up the touchpad as a separate input device */
- sts = wait_event_timeout(applespi->tp_info_complete,
- applespi->rcvd_tp_info.model_no,
- msecs_to_jiffies(3000));
- if (!sts) {
- dev_err(&applespi->spi->dev,
- "Timed out waiting for device info\n");
- sts = -ETIMEDOUT;
- goto cancel_spi;
- }
-
- sts = applespi_register_touchpad_device(applespi,
- &applespi->rcvd_tp_info);
- if (sts)
- goto cancel_spi;
-
/*
* By default this device is not enabled for wakeup; but USB keyboards
* generally are, so the expectation is that by default the keyboard
@@ -2011,19 +1805,6 @@
&applespi_tp_dim_fops);
return 0;
-
-cancel_spi:
- acpi_disable_gpe(NULL, applespi->gpe);
- acpi_remove_gpe_handler(NULL, applespi->gpe, applespi_notify);
-
- spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
- applespi->cancel_spi = true;
- wait_event_lock_irq(applespi->drain_complete,
- !applespi_async_outstanding(applespi),
- applespi->cmd_msg_lock);
- spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
-
- return sts;
}
static void applespi_drain_writes(struct applespi_data *applespi)
@@ -2033,10 +1814,8 @@
spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
applespi->drain = true;
- wait_event_lock_irq_timeout(applespi->drain_complete,
- !applespi->write_active,
- applespi->cmd_msg_lock,
- msecs_to_jiffies(3000));
+ wait_event_lock_irq(applespi->drain_complete, !applespi->write_active,
+ applespi->cmd_msg_lock);
spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
}
@@ -2047,10 +1826,8 @@
spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
- wait_event_lock_irq_timeout(applespi->drain_complete,
- !applespi->read_active,
- applespi->cmd_msg_lock,
- msecs_to_jiffies(3000));
+ wait_event_lock_irq(applespi->drain_complete, !applespi->read_active,
+ applespi->cmd_msg_lock);
applespi->suspended = true;
@@ -2131,7 +1908,7 @@
applespi->drain = false;
applespi->have_cl_led_on = false;
applespi->have_bl_level = 0;
- applespi->cmd_msg_queued = 0;
+ applespi->cmd_msg_queued = false;
applespi->read_active = false;
applespi->write_active = false;
@@ -2177,406 +1954,8 @@
.shutdown = applespi_shutdown,
};
-#ifdef PRE_SPI_PROPERTIES
-
-#define SPI_DEV_CHIP_SEL 0 /* from DSDT UBUF */
-
-/*
- * All the following code is to deal with the fact that the _CRS method for
- * the SPI device in the DSDT returns an empty resource, and the real info is
- * available from the _DSM method. So we need to hook into the ACPI device
- * registration and create and register the SPI device ourselves.
- *
- * All of this can be removed and replaced with
- * module_spi_driver(applespi_driver)
- * when the core adds support for this sort of setup.
- */
-
-/*
- * Configure the spi device with the info from the _DSM method.
- */
-static int appleacpi_config_spi_dev(struct spi_device *spi,
- struct acpi_device *adev)
-{
- struct spi_settings settings;
- int ret;
-
- ret = applespi_get_spi_settings(acpi_device_handle(adev), &settings);
- if (ret)
- return ret;
-
- spi->max_speed_hz = 1000000000 / settings.spi_sclk_period;
- spi->chip_select = SPI_DEV_CHIP_SEL;
- spi->bits_per_word = settings.spi_word_size;
-
- spi->mode =
- (settings.spi_spo * SPI_CPOL) |
- (settings.spi_sph * SPI_CPHA) |
- (settings.spi_bit_order == 0 ? SPI_LSB_FIRST : 0);
-
- spi->irq = -1; /* uses GPE */
-
- spi->dev.platform_data = NULL;
- spi->controller_data = NULL;
- spi->controller_state = NULL;
-
- pr_debug("spi-config: max_speed_hz=%d, chip_select=%d, bits_per_word=%d, mode=%x, irq=%d\n",
- spi->max_speed_hz, spi->chip_select, spi->bits_per_word,
- spi->mode, spi->irq);
-
- return 0;
-}
-
-static int appleacpi_is_device_registered(struct device *dev, void *data)
-{
- struct spi_device *spi = to_spi_device(dev);
- struct spi_master *spi_master = data;
-
- if (spi->master == spi_master && spi->chip_select == SPI_DEV_CHIP_SEL)
- return -EBUSY;
- return 0;
-}
-
-/*
- * Unregister all physical devices devices associated with the acpi device,
- * so that the new SPI device becomes the first physical device for it.
- * Otherwise we don't get properly registered as the driver for the spi
- * device.
- */
-static void appleacpi_unregister_phys_devs(struct acpi_device *adev)
-{
- struct acpi_device_physical_node *entry;
- struct device *dev;
-
- while (true) {
- mutex_lock(&adev->physical_node_lock);
-
- if (list_empty(&adev->physical_node_list)) {
- mutex_unlock(&adev->physical_node_lock);
- break;
- }
-
- entry = list_first_entry(&adev->physical_node_list,
- struct acpi_device_physical_node,
- node);
- dev = get_device(entry->dev);
-
- mutex_unlock(&adev->physical_node_lock);
-
- platform_device_unregister(to_platform_device(dev));
- put_device(dev);
- }
-}
-
-/*
- * Create the spi device for the keyboard and touchpad and register it with
- * the master spi device.
- */
-static int appleacpi_register_spi_device(struct spi_master *spi_master,
- struct acpi_device *adev)
-{
- struct appleacpi_spi_registration_info *reg_info;
- struct spi_device *spi;
- int ret;
-
- reg_info = acpi_driver_data(adev);
-
- /* check if an spi device is already registered */
- ret = bus_for_each_dev(&spi_bus_type, NULL, spi_master,
- appleacpi_is_device_registered);
- if (ret == -EBUSY) {
- pr_info("Spi Device already registered - patched DSDT?\n");
- ret = 0;
- goto release_master;
- } else if (ret) {
- pr_err("Error checking for spi device registered: %d\n", ret);
- goto release_master;
- }
-
- /* none is; check if acpi device is there */
- if (acpi_bus_get_status(adev) || !adev->status.present) {
- pr_info("ACPI device is not present\n");
- ret = 0;
- goto release_master;
- }
-
- /*
- * acpi device is there.
- *
- * First unregister any physical devices already associated with this
- * acpi device (done by acpi_generic_device_attach).
- */
- appleacpi_unregister_phys_devs(adev);
-
- /* create spi device */
- spi = spi_alloc_device(spi_master);
- if (!spi) {
- pr_err("Failed to allocate spi device\n");
- ret = -ENOMEM;
- goto release_master;
- }
-
- ret = appleacpi_config_spi_dev(spi, adev);
- if (ret)
- goto free_spi;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
- acpi_set_modalias(adev, acpi_device_hid(adev), spi->modalias,
- sizeof(spi->modalias));
-#else
- strlcpy(spi->modalias, acpi_device_hid(adev), sizeof(spi->modalias));
-#endif
-
- adev->power.flags.ignore_parent = true;
-
- ACPI_COMPANION_SET(&spi->dev, adev);
- acpi_device_set_enumerated(adev);
-
- /* add spi device */
- ret = spi_add_device(spi);
- if (ret) {
- adev->power.flags.ignore_parent = false;
- pr_err("Failed to add spi device: %d\n", ret);
- goto free_spi;
- }
-
- reg_info->spi = spi;
-
- pr_info("Added spi device %s\n", dev_name(&spi->dev));
-
- goto release_master;
-
-free_spi:
- spi_dev_put(spi);
-release_master:
- spi_master_put(spi_master);
- reg_info->spi_master = NULL;
-
- return ret;
-}
-
-static void appleacpi_dev_registration_worker(struct work_struct *work)
-{
- struct appleacpi_spi_registration_info *info =
- container_of(work, struct appleacpi_spi_registration_info,
- work.work);
-
- if (info->spi_master && !info->spi_master->running) {
- pr_debug_ratelimited("spi-master device is not running yet\n");
- schedule_delayed_work(&info->work, usecs_to_jiffies(100));
- return;
- }
-
- appleacpi_register_spi_device(info->spi_master, info->adev);
-}
-
-/*
- * Callback for whenever a new master spi device is added.
- */
-static int appleacpi_spi_master_added(struct device *dev,
- struct class_interface *cif)
-{
- struct spi_master *spi_master =
- container_of(dev, struct spi_master, dev);
- struct appleacpi_spi_registration_info *info =
- container_of(cif, struct appleacpi_spi_registration_info, cif);
- struct acpi_device *master_adev = spi_master->dev.parent ?
- ACPI_COMPANION(spi_master->dev.parent) : NULL;
-
- pr_debug("New spi-master device %s (%s) with bus-number %d was added\n",
- dev_name(&spi_master->dev),
- master_adev ? acpi_device_hid(master_adev) : "-no-acpi-dev-",
- spi_master->bus_num);
-
- if (master_adev != info->adev->parent)
- return 0;
-
- pr_info("Got spi-master device for device %s\n",
- acpi_device_hid(info->adev));
-
- /*
- * mutexes are held here, preventing unregistering of physical devices,
- * so need to do the actual registration in a worker.
- */
- info->spi_master = spi_master_get(spi_master);
- schedule_delayed_work(&info->work, usecs_to_jiffies(100));
-
- return 0;
-}
-
-/*
- * Callback for whenever a slave spi device is added or removed.
- */
-static int appleacpi_spi_slave_changed(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct appleacpi_spi_registration_info *info =
- container_of(nb, struct appleacpi_spi_registration_info,
- slave_notifier);
- struct spi_device *spi = data;
-
- pr_debug("SPI slave device changed: action=%lu, dev=%s\n",
- action, dev_name(&spi->dev));
-
- switch (action) {
- case BUS_NOTIFY_DEL_DEVICE:
- if (spi == info->spi) {
- info->spi = NULL;
- return NOTIFY_OK;
- }
- break;
-
- default:
- break;
- }
-
- return NOTIFY_DONE;
-}
-
-/*
- * spi_master_class is not exported, so this is an ugly hack to get it anyway.
- */
-static struct class *appleacpi_get_spi_master_class(void)
-{
- struct spi_master *spi_master;
- struct device dummy;
- struct class *cls = NULL;
-
- memset(&dummy, 0, sizeof(dummy));
-
- spi_master = spi_alloc_master(&dummy, 0);
- if (spi_master) {
- cls = spi_master->dev.class;
- spi_master_put(spi_master);
- }
-
- return cls;
-}
-
-static int appleacpi_probe(struct acpi_device *adev)
-{
- struct appleacpi_spi_registration_info *reg_info;
- int ret;
-
- pr_debug("Probing acpi-device %s: bus-id='%s', adr=%lu, uid='%s'\n",
- acpi_device_hid(adev), acpi_device_bid(adev),
- acpi_device_adr(adev), acpi_device_uid(adev));
-
- ret = spi_register_driver(&applespi_driver);
- if (ret) {
- pr_err("Failed to register spi-driver: %d\n", ret);
- return ret;
- }
-
- /*
- * Ideally we would just call spi_register_board_info() here,
- * but that function is not exported. Additionally, we need to
- * perform some extra work during device creation, such as
- * unregistering physical devices. So instead we have do the
- * registration ourselves. For that we see if our spi-master
- * has been registered already, and if not jump through some
- * hoops to make sure we are notified when it does.
- */
-
- reg_info = kzalloc(sizeof(*reg_info), GFP_KERNEL);
- if (!reg_info) {
- ret = -ENOMEM;
- goto unregister_driver;
- }
-
- reg_info->adev = adev;
- INIT_DELAYED_WORK(®_info->work, appleacpi_dev_registration_worker);
-
- adev->driver_data = reg_info;
-
- /*
- * Set up listening for spi slave removals so we can properly
- * handle them.
- */
- reg_info->slave_notifier.notifier_call =
- appleacpi_spi_slave_changed;
- ret = bus_register_notifier(&spi_bus_type,
- ®_info->slave_notifier);
- if (ret) {
- pr_err("Failed to register notifier for spi slaves: %d\n", ret);
- goto free_reg_info;
- }
-
- /*
- * Listen for additions of spi-master devices so we can register our spi
- * device when the relevant master is added. Note that our callback
- * gets called immediately for all existing master devices, so this
- * takes care of registration when the master already exists too.
- */
- reg_info->cif.class = appleacpi_get_spi_master_class();
- reg_info->cif.add_dev = appleacpi_spi_master_added;
-
- ret = class_interface_register(®_info->cif);
- if (ret) {
- pr_err("Failed to register watcher for spi-master: %d\n", ret);
- goto unregister_notifier;
- }
-
- if (!reg_info->spi_master) {
- pr_info("No spi-master device found for device %s - waiting for it to be registered\n",
- acpi_device_hid(adev));
- }
-
- pr_info("acpi-device probe done: %s\n", acpi_device_hid(adev));
-
- return 0;
-
-unregister_notifier:
- bus_unregister_notifier(&spi_bus_type, ®_info->slave_notifier);
-free_reg_info:
- adev->driver_data = NULL;
- kfree(reg_info);
-unregister_driver:
- spi_unregister_driver(&applespi_driver);
- return ret;
-}
-
-static int appleacpi_remove(struct acpi_device *adev)
-{
- struct appleacpi_spi_registration_info *reg_info;
-
- reg_info = acpi_driver_data(adev);
- if (reg_info) {
- class_interface_unregister(®_info->cif);
- bus_unregister_notifier(&spi_bus_type,
- ®_info->slave_notifier);
- cancel_delayed_work_sync(®_info->work);
- if (reg_info->spi)
- spi_unregister_device(reg_info->spi);
- kfree(reg_info);
- }
-
- spi_unregister_driver(&applespi_driver);
-
- pr_info("acpi-device remove done: %s\n", acpi_device_hid(adev));
-
- return 0;
-}
-
-static struct acpi_driver appleacpi_driver = {
- .name = "appleacpi",
- .class = "topcase", /* ? */
- .owner = THIS_MODULE,
- .ids = applespi_acpi_match,
- .ops = {
- .add = appleacpi_probe,
- .remove = appleacpi_remove,
- },
-};
-
-module_acpi_driver(appleacpi_driver)
-
-#else
-
module_spi_driver(applespi_driver)
-#endif
-
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MacBook(Pro) SPI Keyboard/Touchpad driver");
MODULE_AUTHOR("Federico Lorenzi");