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:
Родитель
633354d191
Коммит
6ac0aec6b0
|
@ -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)
|
||||||
|
@ -127,7 +139,7 @@ static void iforce_serio_write_wakeup(struct serio *serio)
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t iforce_serio_irq(struct serio *serio,
|
static irqreturn_t iforce_serio_irq(struct serio *serio,
|
||||||
unsigned char data, unsigned int flags)
|
unsigned char data, unsigned int flags)
|
||||||
{
|
{
|
||||||
struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
|
struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
|
||||||
struct iforce *iforce = &iforce_serio->iforce;
|
struct iforce *iforce = &iforce_serio->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 */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче