mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-30 17:46:40 +07:00
V4L/DVB: IR/mceusb: add tx callback functions and wire up
mchehab: merged with IR/mceusb: userspace buffer copy moved out of driver Userspace buffer copy moved out of driver and into lirc bridge driver [mchehab@redhat.com: merged the patch to avoid compilation errors with allyesconfig ] Signed-off-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
9b7c54d926
commit
e23fb9643b
@ -15,10 +15,6 @@
|
||||
* Jon Smirl, which included enhancements and simplifications to the
|
||||
* incoming IR buffer parsing routines.
|
||||
*
|
||||
* TODO:
|
||||
* - add rc-core transmit support, once available
|
||||
* - enable support for forthcoming ir-lirc-codec interface
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -51,7 +47,6 @@
|
||||
#define DRIVER_NAME "mceusb"
|
||||
|
||||
#define USB_BUFLEN 32 /* USB reception buffer length */
|
||||
#define IRBUF_SIZE 256 /* IR work buffer length */
|
||||
#define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */
|
||||
#define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */
|
||||
|
||||
@ -263,14 +258,13 @@ struct mceusb_dev {
|
||||
u32 reserved:28;
|
||||
} flags;
|
||||
|
||||
/* handle sending (init strings) */
|
||||
/* transmit support */
|
||||
int send_flags;
|
||||
int carrier;
|
||||
u32 carrier;
|
||||
unsigned char tx_mask;
|
||||
|
||||
char name[128];
|
||||
char phys[64];
|
||||
|
||||
unsigned char tx_mask;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -520,6 +514,91 @@ static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size)
|
||||
mce_request_packet(ir, ir->usb_ep_in, data, size, MCEUSB_RX);
|
||||
}
|
||||
|
||||
/* Send data out the IR blaster port(s) */
|
||||
static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
|
||||
{
|
||||
struct mceusb_dev *ir = priv;
|
||||
int i, ret = 0;
|
||||
int count, cmdcount = 0;
|
||||
unsigned char *cmdbuf; /* MCE command buffer */
|
||||
long signal_duration = 0; /* Singnal length in us */
|
||||
struct timeval start_time, end_time;
|
||||
|
||||
do_gettimeofday(&start_time);
|
||||
|
||||
count = n / sizeof(int);
|
||||
|
||||
cmdbuf = kzalloc(sizeof(int) * MCE_CMDBUF_SIZE, GFP_KERNEL);
|
||||
if (!cmdbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
/* MCE tx init header */
|
||||
cmdbuf[cmdcount++] = MCE_CONTROL_HEADER;
|
||||
cmdbuf[cmdcount++] = 0x08;
|
||||
cmdbuf[cmdcount++] = ir->tx_mask;
|
||||
|
||||
/* Generate mce packet data */
|
||||
for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) {
|
||||
signal_duration += txbuf[i];
|
||||
txbuf[i] = txbuf[i] / MCE_TIME_UNIT;
|
||||
|
||||
do { /* loop to support long pulses/spaces > 127*50us=6.35ms */
|
||||
|
||||
/* Insert mce packet header every 4th entry */
|
||||
if ((cmdcount < MCE_CMDBUF_SIZE) &&
|
||||
(cmdcount - MCE_TX_HEADER_LENGTH) %
|
||||
MCE_CODE_LENGTH == 0)
|
||||
cmdbuf[cmdcount++] = MCE_PACKET_HEADER;
|
||||
|
||||
/* Insert mce packet data */
|
||||
if (cmdcount < MCE_CMDBUF_SIZE)
|
||||
cmdbuf[cmdcount++] =
|
||||
(txbuf[i] < MCE_PULSE_BIT ?
|
||||
txbuf[i] : MCE_MAX_PULSE_LENGTH) |
|
||||
(i & 1 ? 0x00 : MCE_PULSE_BIT);
|
||||
else {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
} while ((txbuf[i] > MCE_MAX_PULSE_LENGTH) &&
|
||||
(txbuf[i] -= MCE_MAX_PULSE_LENGTH));
|
||||
}
|
||||
|
||||
/* Fix packet length in last header */
|
||||
cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] =
|
||||
0x80 + (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH - 1;
|
||||
|
||||
/* Check if we have room for the empty packet at the end */
|
||||
if (cmdcount >= MCE_CMDBUF_SIZE) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* All mce commands end with an empty packet (0x80) */
|
||||
cmdbuf[cmdcount++] = 0x80;
|
||||
|
||||
/* Transmit the command to the mce device */
|
||||
mce_async_out(ir, cmdbuf, cmdcount);
|
||||
|
||||
/*
|
||||
* The lircd gap calculation expects the write function to
|
||||
* wait the time it takes for the ircommand to be sent before
|
||||
* it returns.
|
||||
*/
|
||||
do_gettimeofday(&end_time);
|
||||
signal_duration -= (end_time.tv_usec - start_time.tv_usec) +
|
||||
(end_time.tv_sec - start_time.tv_sec) * 1000000;
|
||||
|
||||
/* delay with the closest number of ticks */
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(usecs_to_jiffies(signal_duration));
|
||||
|
||||
out:
|
||||
kfree(cmdbuf);
|
||||
return ret ? ret : n;
|
||||
}
|
||||
|
||||
/* Sets active IR outputs -- mce devices typically (all?) have two */
|
||||
static int mceusb_set_tx_mask(void *priv, u32 mask)
|
||||
{
|
||||
@ -533,6 +612,49 @@ static int mceusb_set_tx_mask(void *priv, u32 mask)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sets the send carrier frequency and mode */
|
||||
static int mceusb_set_tx_carrier(void *priv, u32 carrier)
|
||||
{
|
||||
struct mceusb_dev *ir = priv;
|
||||
int clk = 10000000;
|
||||
int prescaler = 0, divisor = 0;
|
||||
unsigned char cmdbuf[4] = { 0x9f, 0x06, 0x00, 0x00 };
|
||||
|
||||
/* Carrier has changed */
|
||||
if (ir->carrier != carrier) {
|
||||
|
||||
if (carrier == 0) {
|
||||
ir->carrier = carrier;
|
||||
cmdbuf[2] = 0x01;
|
||||
cmdbuf[3] = 0x80;
|
||||
dev_dbg(ir->dev, "%s: disabling carrier "
|
||||
"modulation\n", __func__);
|
||||
mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
|
||||
return carrier;
|
||||
}
|
||||
|
||||
for (prescaler = 0; prescaler < 4; ++prescaler) {
|
||||
divisor = (clk >> (2 * prescaler)) / carrier;
|
||||
if (divisor <= 0xFF) {
|
||||
ir->carrier = carrier;
|
||||
cmdbuf[2] = prescaler;
|
||||
cmdbuf[3] = divisor;
|
||||
dev_dbg(ir->dev, "%s: requesting %u HZ "
|
||||
"carrier\n", __func__, carrier);
|
||||
|
||||
/* Transmit new carrier to mce device */
|
||||
mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
|
||||
return carrier;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
|
||||
return carrier;
|
||||
}
|
||||
|
||||
static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
|
||||
{
|
||||
struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
|
||||
@ -724,6 +846,9 @@ static void mceusb_gen2_init(struct mceusb_dev *ir)
|
||||
mce_sync_in(ir, NULL, maxp);
|
||||
mce_sync_in(ir, NULL, maxp);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(msecs_to_jiffies(100));
|
||||
|
||||
/* device reset */
|
||||
mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
|
||||
mce_sync_in(ir, NULL, maxp);
|
||||
@ -791,7 +916,7 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
|
||||
goto ir_dev_alloc_failed;
|
||||
}
|
||||
|
||||
snprintf(ir->name, sizeof(ir->name), "Media Center Edition eHome "
|
||||
snprintf(ir->name, sizeof(ir->name), "Media Center Ed. eHome "
|
||||
"Infrared Remote Transceiver (%04x:%04x)",
|
||||
le16_to_cpu(ir->usbdev->descriptor.idVendor),
|
||||
le16_to_cpu(ir->usbdev->descriptor.idProduct));
|
||||
@ -804,6 +929,9 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
|
||||
props->priv = ir;
|
||||
props->driver_type = RC_DRIVER_IR_RAW;
|
||||
props->allowed_protos = IR_TYPE_ALL;
|
||||
props->s_tx_mask = mceusb_set_tx_mask;
|
||||
props->s_tx_carrier = mceusb_set_tx_carrier;
|
||||
props->tx_ir = mceusb_tx_ir;
|
||||
|
||||
ir->props = props;
|
||||
ir->irdev = irdev;
|
||||
|
Loading…
Reference in New Issue
Block a user