Input: iforce - allow callers supply data buffer when fetching device IDs

We want to move buffer handling into transport layers as the properties of
buffers (DMA-safety, alignment, etc) are different for different
transports. To allow this, let's allow caller to specify their own buffers
for the results of iforce_get_id_packet() and let transport drivers to
figure what buffers they need to use for transfers.

Tested-by: Tim Schumacher <timschumi@gmx.de>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
Dmitry Torokhov 2018-08-09 17:28:35 -07:00
Родитель 633354d191
Коммит 6ac0aec6b0
4 изменённых файлов: 47 добавлений и 30 удалений

Просмотреть файл

@ -225,7 +225,9 @@ int iforce_init_device(struct device *parent, u16 bustype,
{ {
struct input_dev *input_dev; struct input_dev *input_dev;
struct ff_device *ff; struct ff_device *ff;
unsigned char c[] = "CEOV"; u8 c[] = "CEOV";
u8 buf[IFORCE_MAX_LENGTH];
size_t len;
int i, error; int i, error;
int ff_effects = 0; int ff_effects = 0;
@ -269,7 +271,7 @@ int iforce_init_device(struct device *parent, u16 bustype,
*/ */
for (i = 0; i < 20; i++) for (i = 0; i < 20; i++)
if (!iforce_get_id_packet(iforce, "O")) if (!iforce_get_id_packet(iforce, 'O', buf, &len))
break; break;
if (i == 20) { /* 5 seconds */ if (i == 20) { /* 5 seconds */
@ -283,23 +285,23 @@ int iforce_init_device(struct device *parent, u16 bustype,
* Get device info. * Get device info.
*/ */
if (!iforce_get_id_packet(iforce, "M")) if (!iforce_get_id_packet(iforce, 'M', buf, &len) || len < 3)
input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1]; input_dev->id.vendor = (buf[2] << 8) | buf[1];
else else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet M\n"); dev_warn(&iforce->dev->dev, "Device does not respond to id packet M\n");
if (!iforce_get_id_packet(iforce, "P")) if (!iforce_get_id_packet(iforce, 'P', buf, &len) || len < 3)
input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1]; input_dev->id.product = (buf[2] << 8) | buf[1];
else else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet P\n"); dev_warn(&iforce->dev->dev, "Device does not respond to id packet P\n");
if (!iforce_get_id_packet(iforce, "B")) if (!iforce_get_id_packet(iforce, 'B', buf, &len) || len < 3)
iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1]; iforce->device_memory.end = (buf[2] << 8) | buf[1];
else else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet B\n"); dev_warn(&iforce->dev->dev, "Device does not respond to id packet B\n");
if (!iforce_get_id_packet(iforce, "N")) if (!iforce_get_id_packet(iforce, 'N', buf, &len) || len < 2)
ff_effects = iforce->edata[1]; ff_effects = buf[1];
else else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet N\n"); dev_warn(&iforce->dev->dev, "Device does not respond to id packet N\n");
@ -315,8 +317,9 @@ int iforce_init_device(struct device *parent, u16 bustype,
*/ */
for (i = 0; c[i]; i++) for (i = 0; c[i]; i++)
if (!iforce_get_id_packet(iforce, c + i)) if (!iforce_get_id_packet(iforce, c[i], buf, &len))
iforce_dump_packet(iforce, "info", iforce->ecmd, iforce->edata); iforce_dump_packet(iforce, "info",
(FF_CMD_QUERY & 0xff00) | len, buf);
/* /*
* Disable spring, enable force feedback. * Disable spring, enable force feedback.

Просмотреть файл

@ -31,6 +31,8 @@ struct iforce_serio {
int idx, pkt, len, id; int idx, pkt, len, id;
u8 csum; u8 csum;
u8 expect_packet; u8 expect_packet;
u8 cmd_response[IFORCE_MAX_LENGTH];
u8 cmd_response_len;
}; };
static void iforce_serio_xmit(struct iforce *iforce) static void iforce_serio_xmit(struct iforce *iforce)
@ -81,24 +83,34 @@ again:
spin_unlock_irqrestore(&iforce->xmit_lock, flags); spin_unlock_irqrestore(&iforce->xmit_lock, flags);
} }
static int iforce_serio_get_id(struct iforce *iforce, u8 *packet) static int iforce_serio_get_id(struct iforce *iforce, u8 id,
u8 *response_data, size_t *response_len)
{ {
struct iforce_serio *iforce_serio = container_of(iforce, struct iforce_serio *iforce_serio = container_of(iforce,
struct iforce_serio, struct iforce_serio,
iforce); iforce);
iforce_serio->expect_packet = HI(FF_CMD_QUERY); iforce_serio->expect_packet = HI(FF_CMD_QUERY);
iforce_send_packet(iforce, FF_CMD_QUERY, packet); iforce_serio->cmd_response_len = 0;
iforce_send_packet(iforce, FF_CMD_QUERY, &id);
wait_event_interruptible_timeout(iforce->wait, wait_event_interruptible_timeout(iforce->wait,
!iforce_serio->expect_packet, HZ); !iforce_serio->expect_packet, HZ);
if (iforce_serio->expect_packet) { if (iforce_serio->expect_packet) {
iforce_serio->expect_packet = 0; iforce_serio->expect_packet = 0;
return -EIO; return -ETIMEDOUT;
} }
return -(iforce->edata[0] != packet[0]); if (iforce_serio->cmd_response[0] != id)
return -EIO;
memcpy(response_data, iforce_serio->cmd_response,
iforce_serio->cmd_response_len);
*response_len = iforce_serio->cmd_response_len;
return 0;
} }
static int iforce_serio_start_io(struct iforce *iforce) static int iforce_serio_start_io(struct iforce *iforce)
@ -166,9 +178,9 @@ static irqreturn_t iforce_serio_irq(struct serio *serio,
/* Handle command completion */ /* Handle command completion */
if (iforce_serio->expect_packet == iforce_serio->id) { if (iforce_serio->expect_packet == iforce_serio->id) {
iforce_serio->expect_packet = 0; iforce_serio->expect_packet = 0;
iforce->ecmd = (iforce_serio->id << 8) | memcpy(iforce_serio->cmd_response, iforce->data,
iforce_serio->idx; IFORCE_MAX_LENGTH);
memcpy(iforce->edata, iforce->data, IFORCE_MAX_LENGTH); iforce_serio->cmd_response_len = iforce_serio->len;
/* Signal that command is done */ /* Signal that command is done */
wake_up(&iforce->wait); wake_up(&iforce->wait);

Просмотреть файл

@ -87,7 +87,8 @@ static void iforce_usb_xmit(struct iforce *iforce)
__iforce_usb_xmit(iforce); __iforce_usb_xmit(iforce);
} }
static int iforce_usb_get_id(struct iforce *iforce, u8 *packet) static int iforce_usb_get_id(struct iforce *iforce, u8 id,
u8 *response_data, size_t *response_len)
{ {
struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb, struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
iforce); iforce);
@ -100,18 +101,18 @@ static int iforce_usb_get_id(struct iforce *iforce, u8 *packet)
status = usb_control_msg(iforce_usb->usbdev, status = usb_control_msg(iforce_usb->usbdev,
usb_rcvctrlpipe(iforce_usb->usbdev, 0), usb_rcvctrlpipe(iforce_usb->usbdev, 0),
packet[0], id,
USB_TYPE_VENDOR | USB_DIR_IN | USB_TYPE_VENDOR | USB_DIR_IN |
USB_RECIP_INTERFACE, USB_RECIP_INTERFACE,
0, 0, buf, IFORCE_MAX_LENGTH, HZ); 0, 0, buf, IFORCE_MAX_LENGTH, HZ);
if (status < 0) { if (status < 0) {
dev_err(&iforce_usb->intf->dev, dev_err(&iforce_usb->intf->dev,
"usb_submit_urb failed: %d\n", status); "usb_submit_urb failed: %d\n", status);
} else if (buf[0] != packet[0]) { } else if (buf[0] != id) {
status = -EIO; status = -EIO;
} else { } else {
iforce->ecmd = 0xff00 | status; memcpy(response_data, buf, status);
memcpy(iforce->edata, buf, status); *response_len = status;
status = 0; status = 0;
} }

Просмотреть файл

@ -95,7 +95,8 @@ struct iforce;
struct iforce_xport_ops { struct iforce_xport_ops {
void (*xmit)(struct iforce *iforce); void (*xmit)(struct iforce *iforce);
int (*get_id)(struct iforce *iforce, u8* id); int (*get_id)(struct iforce *iforce, u8 id,
u8 *response_data, size_t *response_len);
int (*start_io)(struct iforce *iforce); int (*start_io)(struct iforce *iforce);
void (*stop_io)(struct iforce *iforce); void (*stop_io)(struct iforce *iforce);
}; };
@ -107,8 +108,6 @@ struct iforce {
int bus; int bus;
unsigned char data[IFORCE_MAX_LENGTH]; unsigned char data[IFORCE_MAX_LENGTH];
unsigned char edata[IFORCE_MAX_LENGTH];
u16 ecmd;
spinlock_t xmit_lock; spinlock_t xmit_lock;
/* Buffer used for asynchronous sending of bytes to the device */ /* Buffer used for asynchronous sending of bytes to the device */
@ -135,9 +134,11 @@ struct iforce {
/* Encode a time value */ /* Encode a time value */
#define TIME_SCALE(a) (a) #define TIME_SCALE(a) (a)
static inline int iforce_get_id_packet(struct iforce *iforce, u8* id) static inline int iforce_get_id_packet(struct iforce *iforce, u8 id,
u8 *response_data, size_t *response_len)
{ {
return iforce->xport_ops->get_id(iforce, id); return iforce->xport_ops->get_id(iforce, id,
response_data, response_len);
} }
/* Public functions */ /* Public functions */