Skip to content

Commit

Permalink
Merge branch 'for-4.20/i2c-hid' into for-linus
Browse files Browse the repository at this point in the history
- general cleanups of hid-i2c driver
- SPIODEV device descriptor fixes
  • Loading branch information
Jiri Kosina committed Oct 23, 2018
2 parents a600ffe + 9ee3e06 commit 4e7be68
Show file tree
Hide file tree
Showing 13 changed files with 627 additions and 117 deletions.
3 changes: 3 additions & 0 deletions drivers/hid/i2c-hid/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@
#

obj-$(CONFIG_I2C_HID) += i2c-hid.o

i2c-hid-objs = i2c-hid-core.o
i2c-hid-$(CONFIG_DMI) += i2c-hid-dmi-quirks.o
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include <linux/platform_data/i2c-hid.h>

#include "../hid-ids.h"
#include "i2c-hid.h"

/* quirks to control the device */
#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0)
Expand Down Expand Up @@ -668,6 +669,7 @@ static int i2c_hid_parse(struct hid_device *hid)
char *rdesc;
int ret;
int tries = 3;
char *use_override;

i2c_hid_dbg(ihid, "entering %s\n", __func__);

Expand All @@ -686,26 +688,37 @@ static int i2c_hid_parse(struct hid_device *hid)
if (ret)
return ret;

rdesc = kzalloc(rsize, GFP_KERNEL);
use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name,
&rsize);

if (!rdesc) {
dbg_hid("couldn't allocate rdesc memory\n");
return -ENOMEM;
}

i2c_hid_dbg(ihid, "asking HID report descriptor\n");

ret = i2c_hid_command(client, &hid_report_descr_cmd, rdesc, rsize);
if (ret) {
hid_err(hid, "reading report descriptor failed\n");
kfree(rdesc);
return -EIO;
if (use_override) {
rdesc = use_override;
i2c_hid_dbg(ihid, "Using a HID report descriptor override\n");
} else {
rdesc = kzalloc(rsize, GFP_KERNEL);

if (!rdesc) {
dbg_hid("couldn't allocate rdesc memory\n");
return -ENOMEM;
}

i2c_hid_dbg(ihid, "asking HID report descriptor\n");

ret = i2c_hid_command(client, &hid_report_descr_cmd,
rdesc, rsize);
if (ret) {
hid_err(hid, "reading report descriptor failed\n");
kfree(rdesc);
return -EIO;
}
}

i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc);

ret = hid_parse_report(hid, rdesc, rsize);
kfree(rdesc);
if (!use_override)
kfree(rdesc);

if (ret) {
dbg_hid("parsing report descriptor failed\n");
return ret;
Expand Down Expand Up @@ -832,12 +845,19 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
int ret;

/* i2c hid fetch using a fixed descriptor size (30 bytes) */
i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer,
sizeof(struct i2c_hid_desc));
if (ret) {
dev_err(&client->dev, "hid_descr_cmd failed\n");
return -ENODEV;
if (i2c_hid_get_dmi_i2c_hid_desc_override(client->name)) {
i2c_hid_dbg(ihid, "Using a HID descriptor override\n");
ihid->hdesc =
*i2c_hid_get_dmi_i2c_hid_desc_override(client->name);
} else {
i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
ret = i2c_hid_command(client, &hid_descr_cmd,
ihid->hdesc_buffer,
sizeof(struct i2c_hid_desc));
if (ret) {
dev_err(&client->dev, "hid_descr_cmd failed\n");
return -ENODEV;
}
}

/* Validate the length of HID descriptor, the 4 first bytes:
Expand Down
376 changes: 376 additions & 0 deletions drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions drivers/hid/i2c-hid/i2c-hid.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0+ */

#ifndef I2C_HID_H
#define I2C_HID_H


#ifdef CONFIG_DMI
struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name);
char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
unsigned int *size);
#else
static inline struct i2c_hid_desc
*i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
{ return NULL; }
static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
unsigned int *size)
{ return NULL; }
#endif

#endif
32 changes: 14 additions & 18 deletions drivers/hid/intel-ish-hid/ipc/ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -280,14 +280,14 @@ static int write_ipc_from_queue(struct ishtp_device *dev)
* if tx send list is empty - return 0;
* may happen, as RX_COMPLETE handler doesn't check list emptiness.
*/
if (list_empty(&dev->wr_processing_list_head.link)) {
if (list_empty(&dev->wr_processing_list)) {
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
out_ipc_locked = 0;
return 0;
}

ipc_link = list_entry(dev->wr_processing_list_head.link.next,
struct wr_msg_ctl_info, link);
ipc_link = list_first_entry(&dev->wr_processing_list,
struct wr_msg_ctl_info, link);
/* first 4 bytes of the data is the doorbell value (IPC header) */
length = ipc_link->length - sizeof(uint32_t);
doorbell_val = *(uint32_t *)ipc_link->inline_data;
Expand Down Expand Up @@ -338,7 +338,7 @@ static int write_ipc_from_queue(struct ishtp_device *dev)
ipc_send_compl = ipc_link->ipc_send_compl;
ipc_send_compl_prm = ipc_link->ipc_send_compl_prm;
list_del_init(&ipc_link->link);
list_add_tail(&ipc_link->link, &dev->wr_free_list_head.link);
list_add(&ipc_link->link, &dev->wr_free_list);
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);

/*
Expand Down Expand Up @@ -372,26 +372,26 @@ static int write_ipc_to_queue(struct ishtp_device *dev,
unsigned char *msg, int length)
{
struct wr_msg_ctl_info *ipc_link;
unsigned long flags;
unsigned long flags;

if (length > IPC_FULL_MSG_SIZE)
return -EMSGSIZE;

spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
if (list_empty(&dev->wr_free_list_head.link)) {
if (list_empty(&dev->wr_free_list)) {
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
return -ENOMEM;
}
ipc_link = list_entry(dev->wr_free_list_head.link.next,
struct wr_msg_ctl_info, link);
ipc_link = list_first_entry(&dev->wr_free_list,
struct wr_msg_ctl_info, link);
list_del_init(&ipc_link->link);

ipc_link->ipc_send_compl = ipc_send_compl;
ipc_link->ipc_send_compl_prm = ipc_send_compl_prm;
ipc_link->length = length;
memcpy(ipc_link->inline_data, msg, length);

list_add_tail(&ipc_link->link, &dev->wr_processing_list_head.link);
list_add_tail(&ipc_link->link, &dev->wr_processing_list);
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);

write_ipc_from_queue(dev);
Expand Down Expand Up @@ -487,17 +487,13 @@ static int ish_fw_reset_handler(struct ishtp_device *dev)
{
uint32_t reset_id;
unsigned long flags;
struct wr_msg_ctl_info *processing, *next;

/* Read reset ID */
reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF;

/* Clear IPC output queue */
spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
list_for_each_entry_safe(processing, next,
&dev->wr_processing_list_head.link, link) {
list_move_tail(&processing->link, &dev->wr_free_list_head.link);
}
list_splice_init(&dev->wr_processing_list, &dev->wr_free_list);
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);

/* ISHTP notification in IPC_RESET */
Expand Down Expand Up @@ -921,9 +917,9 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
spin_lock_init(&dev->out_ipc_spinlock);

/* Init IPC processing and free lists */
INIT_LIST_HEAD(&dev->wr_processing_list_head.link);
INIT_LIST_HEAD(&dev->wr_free_list_head.link);
for (i = 0; i < IPC_TX_FIFO_SIZE; ++i) {
INIT_LIST_HEAD(&dev->wr_processing_list);
INIT_LIST_HEAD(&dev->wr_free_list);
for (i = 0; i < IPC_TX_FIFO_SIZE; i++) {
struct wr_msg_ctl_info *tx_buf;

tx_buf = devm_kzalloc(&pdev->dev,
Expand All @@ -939,7 +935,7 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
i);
break;
}
list_add_tail(&tx_buf->link, &dev->wr_free_list_head.link);
list_add_tail(&tx_buf->link, &dev->wr_free_list);
}

dev->ops = &ish_hw_ops;
Expand Down
75 changes: 24 additions & 51 deletions drivers/hid/intel-ish-hid/ipc/pci-ish.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,84 +115,64 @@ static const struct pci_device_id ish_invalid_pci_ids[] = {
*/
static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct ishtp_device *dev;
int ret;
struct ish_hw *hw;
int ret;
struct ishtp_device *ishtp;
struct device *dev = &pdev->dev;

/* Check for invalid platforms for ISH support */
if (pci_dev_present(ish_invalid_pci_ids))
return -ENODEV;

/* enable pci dev */
ret = pci_enable_device(pdev);
ret = pcim_enable_device(pdev);
if (ret) {
dev_err(&pdev->dev, "ISH: Failed to enable PCI device\n");
dev_err(dev, "ISH: Failed to enable PCI device\n");
return ret;
}

/* set PCI host mastering */
pci_set_master(pdev);

/* pci request regions for ISH driver */
ret = pci_request_regions(pdev, KBUILD_MODNAME);
ret = pcim_iomap_regions(pdev, 1 << 0, KBUILD_MODNAME);
if (ret) {
dev_err(&pdev->dev, "ISH: Failed to get PCI regions\n");
goto disable_device;
dev_err(dev, "ISH: Failed to get PCI regions\n");
return ret;
}

/* allocates and initializes the ISH dev structure */
dev = ish_dev_init(pdev);
if (!dev) {
ishtp = ish_dev_init(pdev);
if (!ishtp) {
ret = -ENOMEM;
goto release_regions;
return ret;
}
hw = to_ish_hw(dev);
dev->print_log = ish_event_tracer;
hw = to_ish_hw(ishtp);
ishtp->print_log = ish_event_tracer;

/* mapping IO device memory */
hw->mem_addr = pci_iomap(pdev, 0, 0);
if (!hw->mem_addr) {
dev_err(&pdev->dev, "ISH: mapping I/O range failure\n");
ret = -ENOMEM;
goto free_device;
}

dev->pdev = pdev;

hw->mem_addr = pcim_iomap_table(pdev)[0];
ishtp->pdev = pdev;
pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;

/* request and enable interrupt */
ret = request_irq(pdev->irq, ish_irq_handler, IRQF_SHARED,
KBUILD_MODNAME, dev);
ret = devm_request_irq(dev, pdev->irq, ish_irq_handler,
IRQF_SHARED, KBUILD_MODNAME, ishtp);
if (ret) {
dev_err(&pdev->dev, "ISH: request IRQ failure (%d)\n",
pdev->irq);
goto free_device;
dev_err(dev, "ISH: request IRQ %d failed\n", pdev->irq);
return ret;
}

dev_set_drvdata(dev->devc, dev);
dev_set_drvdata(ishtp->devc, ishtp);

init_waitqueue_head(&dev->suspend_wait);
init_waitqueue_head(&dev->resume_wait);
init_waitqueue_head(&ishtp->suspend_wait);
init_waitqueue_head(&ishtp->resume_wait);

ret = ish_init(dev);
ret = ish_init(ishtp);
if (ret)
goto free_irq;
return ret;

return 0;

free_irq:
free_irq(pdev->irq, dev);
free_device:
pci_iounmap(pdev, hw->mem_addr);
release_regions:
pci_release_regions(pdev);
disable_device:
pci_clear_master(pdev);
pci_disable_device(pdev);
dev_err(&pdev->dev, "ISH: PCI driver initialization failed.\n");

return ret;
}

/**
Expand All @@ -204,16 +184,9 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
static void ish_remove(struct pci_dev *pdev)
{
struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev);
struct ish_hw *hw = to_ish_hw(ishtp_dev);

ishtp_bus_remove_all_clients(ishtp_dev, false);
ish_device_disable(ishtp_dev);

free_irq(pdev->irq, ishtp_dev);
pci_iounmap(pdev, hw->mem_addr);
pci_release_regions(pdev);
pci_clear_master(pdev);
pci_disable_device(pdev);
}

static struct device __maybe_unused *ish_resume_device;
Expand Down
Loading

0 comments on commit 4e7be68

Please sign in to comment.