[media] af9005: don't do DMA on stack
The USB control messages require DMA to work. We cannot pass a stack-allocated buffer, as it is not warranted that the stack would be into a DMA enabled area. Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
This commit is contained in:
parent
9fce0c2265
commit
c58b84ee46
@ -52,17 +52,16 @@ u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
|
||||
struct af9005_device_state {
|
||||
u8 sequence;
|
||||
int led_state;
|
||||
unsigned char data[256];
|
||||
struct mutex data_mutex;
|
||||
};
|
||||
|
||||
static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
|
||||
int readwrite, int type, u8 * values, int len)
|
||||
{
|
||||
struct af9005_device_state *st = d->priv;
|
||||
u8 obuf[16] = { 0 };
|
||||
u8 ibuf[17] = { 0 };
|
||||
u8 command;
|
||||
int i;
|
||||
int ret;
|
||||
u8 command, seq;
|
||||
int i, ret;
|
||||
|
||||
if (len < 1) {
|
||||
err("generic read/write, less than 1 byte. Makes no sense.");
|
||||
@ -73,16 +72,17 @@ static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
obuf[0] = 14; /* rest of buffer length low */
|
||||
obuf[1] = 0; /* rest of buffer length high */
|
||||
mutex_lock(&st->data_mutex);
|
||||
st->data[0] = 14; /* rest of buffer length low */
|
||||
st->data[1] = 0; /* rest of buffer length high */
|
||||
|
||||
obuf[2] = AF9005_REGISTER_RW; /* register operation */
|
||||
obuf[3] = 12; /* rest of buffer length */
|
||||
st->data[2] = AF9005_REGISTER_RW; /* register operation */
|
||||
st->data[3] = 12; /* rest of buffer length */
|
||||
|
||||
obuf[4] = st->sequence++; /* sequence number */
|
||||
st->data[4] = seq = st->sequence++; /* sequence number */
|
||||
|
||||
obuf[5] = (u8) (reg >> 8); /* register address */
|
||||
obuf[6] = (u8) (reg & 0xff);
|
||||
st->data[5] = (u8) (reg >> 8); /* register address */
|
||||
st->data[6] = (u8) (reg & 0xff);
|
||||
|
||||
if (type == AF9005_OFDM_REG) {
|
||||
command = AF9005_CMD_OFDM_REG;
|
||||
@ -96,51 +96,52 @@ static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
|
||||
command |= readwrite;
|
||||
if (readwrite == AF9005_CMD_WRITE)
|
||||
for (i = 0; i < len; i++)
|
||||
obuf[8 + i] = values[i];
|
||||
st->data[8 + i] = values[i];
|
||||
else if (type == AF9005_TUNER_REG)
|
||||
/* read command for tuner, the first byte contains the i2c address */
|
||||
obuf[8] = values[0];
|
||||
obuf[7] = command;
|
||||
st->data[8] = values[0];
|
||||
st->data[7] = command;
|
||||
|
||||
ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
|
||||
ret = dvb_usb_generic_rw(d, st->data, 16, st->data, 17, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto ret;
|
||||
|
||||
/* sanity check */
|
||||
if (ibuf[2] != AF9005_REGISTER_RW_ACK) {
|
||||
if (st->data[2] != AF9005_REGISTER_RW_ACK) {
|
||||
err("generic read/write, wrong reply code.");
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto ret;
|
||||
}
|
||||
if (ibuf[3] != 0x0d) {
|
||||
if (st->data[3] != 0x0d) {
|
||||
err("generic read/write, wrong length in reply.");
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto ret;
|
||||
}
|
||||
if (ibuf[4] != obuf[4]) {
|
||||
if (st->data[4] != seq) {
|
||||
err("generic read/write, wrong sequence in reply.");
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto ret;
|
||||
}
|
||||
/*
|
||||
Windows driver doesn't check these fields, in fact sometimes
|
||||
the register in the reply is different that what has been sent
|
||||
|
||||
if (ibuf[5] != obuf[5] || ibuf[6] != obuf[6]) {
|
||||
err("generic read/write, wrong register in reply.");
|
||||
return -EIO;
|
||||
}
|
||||
if (ibuf[7] != command) {
|
||||
err("generic read/write wrong command in reply.");
|
||||
return -EIO;
|
||||
}
|
||||
* In thesis, both input and output buffers should have
|
||||
* identical values for st->data[5] to st->data[8].
|
||||
* However, windows driver doesn't check these fields, in fact
|
||||
* sometimes the register in the reply is different that what
|
||||
* has been sent
|
||||
*/
|
||||
if (ibuf[16] != 0x01) {
|
||||
if (st->data[16] != 0x01) {
|
||||
err("generic read/write wrong status code in reply.");
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
if (readwrite == AF9005_CMD_READ)
|
||||
for (i = 0; i < len; i++)
|
||||
values[i] = ibuf[8 + i];
|
||||
values[i] = st->data[8 + i];
|
||||
|
||||
return 0;
|
||||
ret:
|
||||
mutex_unlock(&st->data_mutex);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
@ -464,8 +465,7 @@ int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
|
||||
struct af9005_device_state *st = d->priv;
|
||||
|
||||
int ret, i, packet_len;
|
||||
u8 buf[64];
|
||||
u8 ibuf[64];
|
||||
u8 seq;
|
||||
|
||||
if (wlen < 0) {
|
||||
err("send command, wlen less than 0 bytes. Makes no sense.");
|
||||
@ -480,94 +480,97 @@ int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
|
||||
return -EINVAL;
|
||||
}
|
||||
packet_len = wlen + 5;
|
||||
buf[0] = (u8) (packet_len & 0xff);
|
||||
buf[1] = (u8) ((packet_len & 0xff00) >> 8);
|
||||
|
||||
buf[2] = 0x26; /* packet type */
|
||||
buf[3] = wlen + 3;
|
||||
buf[4] = st->sequence++;
|
||||
buf[5] = command;
|
||||
buf[6] = wlen;
|
||||
mutex_lock(&st->data_mutex);
|
||||
|
||||
st->data[0] = (u8) (packet_len & 0xff);
|
||||
st->data[1] = (u8) ((packet_len & 0xff00) >> 8);
|
||||
|
||||
st->data[2] = 0x26; /* packet type */
|
||||
st->data[3] = wlen + 3;
|
||||
st->data[4] = seq = st->sequence++;
|
||||
st->data[5] = command;
|
||||
st->data[6] = wlen;
|
||||
for (i = 0; i < wlen; i++)
|
||||
buf[7 + i] = wbuf[i];
|
||||
ret = dvb_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ibuf[2] != 0x27) {
|
||||
st->data[7 + i] = wbuf[i];
|
||||
ret = dvb_usb_generic_rw(d, st->data, wlen + 7, st->data, rlen + 7, 0);
|
||||
if (st->data[2] != 0x27) {
|
||||
err("send command, wrong reply code.");
|
||||
return -EIO;
|
||||
}
|
||||
if (ibuf[4] != buf[4]) {
|
||||
ret = -EIO;
|
||||
} else if (st->data[4] != seq) {
|
||||
err("send command, wrong sequence in reply.");
|
||||
return -EIO;
|
||||
}
|
||||
if (ibuf[5] != 0x01) {
|
||||
ret = -EIO;
|
||||
} else if (st->data[5] != 0x01) {
|
||||
err("send command, wrong status code in reply.");
|
||||
return -EIO;
|
||||
}
|
||||
if (ibuf[6] != rlen) {
|
||||
ret = -EIO;
|
||||
} else if (st->data[6] != rlen) {
|
||||
err("send command, invalid data length in reply.");
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
}
|
||||
for (i = 0; i < rlen; i++)
|
||||
rbuf[i] = ibuf[i + 7];
|
||||
return 0;
|
||||
if (!ret) {
|
||||
for (i = 0; i < rlen; i++)
|
||||
rbuf[i] = st->data[i + 7];
|
||||
}
|
||||
|
||||
mutex_unlock(&st->data_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values,
|
||||
int len)
|
||||
{
|
||||
struct af9005_device_state *st = d->priv;
|
||||
u8 obuf[16], ibuf[14];
|
||||
u8 seq;
|
||||
int ret, i;
|
||||
|
||||
memset(obuf, 0, sizeof(obuf));
|
||||
memset(ibuf, 0, sizeof(ibuf));
|
||||
mutex_lock(&st->data_mutex);
|
||||
|
||||
obuf[0] = 14; /* length of rest of packet low */
|
||||
obuf[1] = 0; /* length of rest of packer high */
|
||||
memset(st->data, 0, sizeof(st->data));
|
||||
|
||||
obuf[2] = 0x2a; /* read/write eeprom */
|
||||
st->data[0] = 14; /* length of rest of packet low */
|
||||
st->data[1] = 0; /* length of rest of packer high */
|
||||
|
||||
obuf[3] = 12; /* size */
|
||||
st->data[2] = 0x2a; /* read/write eeprom */
|
||||
|
||||
obuf[4] = st->sequence++;
|
||||
st->data[3] = 12; /* size */
|
||||
|
||||
obuf[5] = 0; /* read */
|
||||
st->data[4] = seq = st->sequence++;
|
||||
|
||||
obuf[6] = len;
|
||||
obuf[7] = address;
|
||||
ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ibuf[2] != 0x2b) {
|
||||
st->data[5] = 0; /* read */
|
||||
|
||||
st->data[6] = len;
|
||||
st->data[7] = address;
|
||||
ret = dvb_usb_generic_rw(d, st->data, 16, st->data, 14, 0);
|
||||
if (st->data[2] != 0x2b) {
|
||||
err("Read eeprom, invalid reply code");
|
||||
return -EIO;
|
||||
}
|
||||
if (ibuf[3] != 10) {
|
||||
ret = -EIO;
|
||||
} else if (st->data[3] != 10) {
|
||||
err("Read eeprom, invalid reply length");
|
||||
return -EIO;
|
||||
}
|
||||
if (ibuf[4] != obuf[4]) {
|
||||
ret = -EIO;
|
||||
} else if (st->data[4] != seq) {
|
||||
err("Read eeprom, wrong sequence in reply ");
|
||||
return -EIO;
|
||||
}
|
||||
if (ibuf[5] != 1) {
|
||||
ret = -EIO;
|
||||
} else if (st->data[5] != 1) {
|
||||
err("Read eeprom, wrong status in reply ");
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
values[i] = ibuf[6 + i];
|
||||
|
||||
if (!ret) {
|
||||
for (i = 0; i < len; i++)
|
||||
values[i] = st->data[6 + i];
|
||||
}
|
||||
return 0;
|
||||
mutex_unlock(&st->data_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply)
|
||||
static int af9005_boot_packet(struct usb_device *udev, int type, u8 *reply,
|
||||
u8 *buf, int size)
|
||||
{
|
||||
u8 buf[FW_BULKOUT_SIZE + 2];
|
||||
u16 checksum;
|
||||
int act_len, i, ret;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
memset(buf, 0, size);
|
||||
buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
|
||||
buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
|
||||
switch (type) {
|
||||
@ -720,15 +723,21 @@ static int af9005_download_firmware(struct usb_device *udev, const struct firmwa
|
||||
{
|
||||
int i, packets, ret, act_len;
|
||||
|
||||
u8 buf[FW_BULKOUT_SIZE + 2];
|
||||
u8 *buf;
|
||||
u8 reply;
|
||||
|
||||
ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
|
||||
buf = kmalloc(FW_BULKOUT_SIZE + 2, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = af9005_boot_packet(udev, FW_CONFIG, &reply, buf,
|
||||
FW_BULKOUT_SIZE + 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err;
|
||||
if (reply != 0x01) {
|
||||
err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply);
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
packets = fw->size / FW_BULKOUT_SIZE;
|
||||
buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
|
||||
@ -743,28 +752,35 @@ static int af9005_download_firmware(struct usb_device *udev, const struct firmwa
|
||||
buf, FW_BULKOUT_SIZE + 2, &act_len, 1000);
|
||||
if (ret) {
|
||||
err("firmware download failed at packet %d with code %d", i, ret);
|
||||
return ret;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
ret = af9005_boot_packet(udev, FW_CONFIRM, &reply);
|
||||
ret = af9005_boot_packet(udev, FW_CONFIRM, &reply,
|
||||
buf, FW_BULKOUT_SIZE + 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err;
|
||||
if (reply != (u8) (packets & 0xff)) {
|
||||
err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply);
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
ret = af9005_boot_packet(udev, FW_BOOT, &reply);
|
||||
ret = af9005_boot_packet(udev, FW_BOOT, &reply, buf,
|
||||
FW_BULKOUT_SIZE + 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
|
||||
goto err;
|
||||
ret = af9005_boot_packet(udev, FW_CONFIG, &reply, buf,
|
||||
FW_BULKOUT_SIZE + 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err;
|
||||
if (reply != 0x02) {
|
||||
err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply);
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
@ -823,53 +839,59 @@ static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state)
|
||||
{
|
||||
struct af9005_device_state *st = d->priv;
|
||||
int ret, len;
|
||||
|
||||
u8 obuf[5];
|
||||
u8 ibuf[256];
|
||||
u8 seq;
|
||||
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
if (rc_decode == NULL) {
|
||||
/* it shouldn't never come here */
|
||||
return 0;
|
||||
}
|
||||
|
||||
mutex_lock(&st->data_mutex);
|
||||
|
||||
/* deb_info("rc_query\n"); */
|
||||
obuf[0] = 3; /* rest of packet length low */
|
||||
obuf[1] = 0; /* rest of packet lentgh high */
|
||||
obuf[2] = 0x40; /* read remote */
|
||||
obuf[3] = 1; /* rest of packet length */
|
||||
obuf[4] = st->sequence++; /* sequence number */
|
||||
ret = dvb_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
|
||||
st->data[0] = 3; /* rest of packet length low */
|
||||
st->data[1] = 0; /* rest of packet lentgh high */
|
||||
st->data[2] = 0x40; /* read remote */
|
||||
st->data[3] = 1; /* rest of packet length */
|
||||
st->data[4] = seq = st->sequence++; /* sequence number */
|
||||
ret = dvb_usb_generic_rw(d, st->data, 5, st->data, 256, 0);
|
||||
if (ret) {
|
||||
err("rc query failed");
|
||||
return ret;
|
||||
goto ret;
|
||||
}
|
||||
if (ibuf[2] != 0x41) {
|
||||
if (st->data[2] != 0x41) {
|
||||
err("rc query bad header.");
|
||||
return -EIO;
|
||||
}
|
||||
if (ibuf[4] != obuf[4]) {
|
||||
ret = -EIO;
|
||||
goto ret;
|
||||
} else if (st->data[4] != seq) {
|
||||
err("rc query bad sequence.");
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto ret;
|
||||
}
|
||||
len = ibuf[5];
|
||||
len = st->data[5];
|
||||
if (len > 246) {
|
||||
err("rc query invalid length");
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto ret;
|
||||
}
|
||||
if (len > 0) {
|
||||
deb_rc("rc data (%d) ", len);
|
||||
debug_dump((ibuf + 6), len, deb_rc);
|
||||
ret = rc_decode(d, &ibuf[6], len, event, state);
|
||||
debug_dump((st->data + 6), len, deb_rc);
|
||||
ret = rc_decode(d, &st->data[6], len, event, state);
|
||||
if (ret) {
|
||||
err("rc_decode failed");
|
||||
return ret;
|
||||
goto ret;
|
||||
} else {
|
||||
deb_rc("rc_decode state %x event %x\n", *state, *event);
|
||||
if (*state == REMOTE_KEY_REPEAT)
|
||||
*event = d->last_event;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
ret:
|
||||
mutex_unlock(&st->data_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
@ -953,10 +975,16 @@ static int af9005_identify_state(struct usb_device *udev,
|
||||
int *cold)
|
||||
{
|
||||
int ret;
|
||||
u8 reply;
|
||||
ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
|
||||
u8 reply, *buf;
|
||||
|
||||
buf = kmalloc(FW_BULKOUT_SIZE + 2, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = af9005_boot_packet(udev, FW_CONFIG, &reply,
|
||||
buf, FW_BULKOUT_SIZE + 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err;
|
||||
deb_info("result of FW_CONFIG in identify state %d\n", reply);
|
||||
if (reply == 0x01)
|
||||
*cold = 1;
|
||||
@ -965,7 +993,10 @@ static int af9005_identify_state(struct usb_device *udev,
|
||||
else
|
||||
return -EIO;
|
||||
deb_info("Identify state cold = %d\n", *cold);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct dvb_usb_device_properties af9005_properties;
|
||||
@ -973,8 +1004,20 @@ static struct dvb_usb_device_properties af9005_properties;
|
||||
static int af9005_usb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
return dvb_usb_device_init(intf, &af9005_properties,
|
||||
THIS_MODULE, NULL, adapter_nr);
|
||||
struct dvb_usb_device *d;
|
||||
struct af9005_device_state *st;
|
||||
int ret;
|
||||
|
||||
ret = dvb_usb_device_init(intf, &af9005_properties,
|
||||
THIS_MODULE, &d, adapter_nr);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
st = d->priv;
|
||||
mutex_init(&st->data_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum af9005_usb_table_entry {
|
||||
|
Loading…
Reference in New Issue
Block a user