summaryrefslogtreecommitdiff
path: root/drivers/media/usb/b2c2/flexcop-usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/usb/b2c2/flexcop-usb.c')
-rw-r--r--drivers/media/usb/b2c2/flexcop-usb.c220
1 files changed, 135 insertions, 85 deletions
diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c
index 8b6275f85908..8033622543f2 100644
--- a/drivers/media/usb/b2c2/flexcop-usb.c
+++ b/drivers/media/usb/b2c2/flexcop-usb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
* flexcop-usb.c - covers the USB part
@@ -10,12 +11,12 @@
/* Version information */
#define DRIVER_VERSION "0.1"
#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver"
-#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
+#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@posteo.de>"
/* debug */
#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
-#define dprintk(level,args...) \
- do { if ((debug & level)) printk(args); } while (0)
+#define dprintk(level, args...) \
+ do { if ((debug & (level))) printk(args); } while (0)
#define debug_dump(b, l, method) do {\
int i; \
@@ -26,15 +27,14 @@
#define DEBSTATUS ""
#else
-#define dprintk(level, args...)
-#define debug_dump(b, l, method)
+#define dprintk(level, args...) no_printk(args)
+#define debug_dump(b, l, method) do { } while (0)
#define DEBSTATUS " (debugging is not enabled)"
#endif
static int debug;
module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,"
- "ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS);
#undef DEBSTATUS
#define deb_info(args...) dprintk(0x01, args)
@@ -73,23 +73,34 @@ static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI,
u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR;
u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) |
(read ? 0x80 : 0);
+ int ret;
+
+ mutex_lock(&fc_usb->data_mutex);
+ if (!read)
+ memcpy(fc_usb->data, val, sizeof(*val));
- int len = usb_control_msg(fc_usb->udev,
+ ret = usb_control_msg(fc_usb->udev,
read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT,
request,
request_type, /* 0xc0 read or 0x40 write */
wAddress,
0,
- val,
+ fc_usb->data,
sizeof(u32),
- B2C2_WAIT_FOR_OPERATION_RDW * HZ);
+ B2C2_WAIT_FOR_OPERATION_RDW);
- if (len != sizeof(u32)) {
+ if (ret != sizeof(u32)) {
err("error while %s dword from %d (%d).", read ? "reading" :
"writing", wAddress, wRegOffsPCI);
- return -EIO;
+ if (ret >= 0)
+ ret = -EIO;
}
- return 0;
+
+ if (read && ret >= 0)
+ memcpy(val, fc_usb->data, sizeof(*val));
+ mutex_unlock(&fc_usb->data_mutex);
+
+ return ret;
}
/*
* DKT 010817 - add support for V8 memory read/write and flash update
@@ -100,9 +111,14 @@ static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
{
u8 request_type = USB_TYPE_VENDOR;
u16 wIndex;
- int nWaitTime, pipe, len;
+ int nWaitTime, pipe, ret;
wIndex = page << 8;
+ if (buflen > sizeof(fc_usb->data)) {
+ err("Buffer size bigger than max URB control message\n");
+ return -EIO;
+ }
+
switch (req) {
case B2C2_USB_READ_V8_MEM:
nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
@@ -127,20 +143,35 @@ static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n", request_type, req,
wAddress, wIndex, buflen);
- len = usb_control_msg(fc_usb->udev, pipe,
+ mutex_lock(&fc_usb->data_mutex);
+
+ if ((request_type & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
+ memcpy(fc_usb->data, pbBuffer, buflen);
+
+ ret = usb_control_msg(fc_usb->udev, pipe,
req,
request_type,
wAddress,
wIndex,
- pbBuffer,
+ fc_usb->data,
buflen,
- nWaitTime * HZ);
+ nWaitTime);
+ if (ret != buflen)
+ ret = -EIO;
+
+ if (ret >= 0) {
+ ret = 0;
+ if ((request_type & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+ memcpy(pbBuffer, fc_usb->data, buflen);
+ }
+
+ mutex_unlock(&fc_usb->data_mutex);
- debug_dump(pbBuffer, len, deb_v8);
- return len == buflen ? 0 : -EIO;
+ debug_dump(pbBuffer, ret, deb_v8);
+ return ret;
}
-#define bytes_left_to_read_on_page(paddr,buflen) \
+#define bytes_left_to_read_on_page(paddr, buflen) \
((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \
? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)))
@@ -148,11 +179,11 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start,
u32 addr, int extended, u8 *buf, u32 len)
{
- int i,ret = 0;
+ int ret = 0;
u16 wMax;
u32 pagechunk = 0;
- switch(req) {
+ switch (req) {
case B2C2_USB_READ_V8_MEM:
wMax = USB_MEM_READ_MAX;
break;
@@ -164,13 +195,9 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
break;
default:
return -EINVAL;
- break;
}
- for (i = 0; i < len;) {
- pagechunk =
- wMax < bytes_left_to_read_on_page(addr, len) ?
- wMax :
- bytes_left_to_read_on_page(addr, len);
+ while (len) {
+ pagechunk = min(wMax, bytes_left_to_read_on_page(addr, len));
deb_info("%x\n",
(addr & V8_MEMORY_PAGE_MASK) |
(V8_MEMORY_EXTENDED*extended));
@@ -179,11 +206,12 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
page_start + (addr / V8_MEMORY_PAGE_SIZE),
(addr & V8_MEMORY_PAGE_MASK) |
(V8_MEMORY_EXTENDED*extended),
- &buf[i], pagechunk);
+ buf, pagechunk);
if (ret < 0)
return ret;
addr += pagechunk;
+ buf += pagechunk;
len -= pagechunk;
}
return 0;
@@ -196,29 +224,6 @@ static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended)
fc->dvb_adapter.proposed_mac, 6);
}
-#if 0
-static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set,
- flexcop_usb_utility_function_t func, u8 extra, u16 wIndex,
- u16 buflen, u8 *pvBuffer)
-{
- u16 wValue;
- u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR;
- int nWaitTime = 2,
- pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, len;
- wValue = (func << 8) | extra;
-
- len = usb_control_msg(fc_usb->udev,pipe,
- B2C2_USB_UTILITY,
- request_type,
- wValue,
- wIndex,
- pvBuffer,
- buflen,
- nWaitTime * HZ);
- return len == buflen ? 0 : -EIO;
-}
-#endif
-
/* usb i2c stuff */
static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
flexcop_usb_request_t req, flexcop_usb_i2c_function_t func,
@@ -226,9 +231,14 @@ static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
{
struct flexcop_usb *fc_usb = i2c->fc->bus_specific;
u16 wValue, wIndex;
- int nWaitTime,pipe,len;
+ int nWaitTime, pipe, ret;
u8 request_type = USB_TYPE_VENDOR;
+ if (buflen > sizeof(fc_usb->data)) {
+ err("Buffer size bigger than max URB control message\n");
+ return -EIO;
+ }
+
switch (func) {
case USB_FUNC_I2C_WRITE:
case USB_FUNC_I2C_MULTIWRITE:
@@ -236,13 +246,13 @@ static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
/* DKT 020208 - add this to support special case of DiSEqC */
case USB_FUNC_I2C_CHECKWRITE:
pipe = B2C2_USB_CTRL_PIPE_OUT;
- nWaitTime = 2;
+ nWaitTime = 2000;
request_type |= USB_DIR_OUT;
break;
case USB_FUNC_I2C_READ:
case USB_FUNC_I2C_REPEATREAD:
pipe = B2C2_USB_CTRL_PIPE_IN;
- nWaitTime = 2;
+ nWaitTime = 2000;
request_type |= USB_DIR_IN;
break;
default:
@@ -257,15 +267,32 @@ static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
wValue & 0xff, wValue >> 8,
wIndex & 0xff, wIndex >> 8);
- len = usb_control_msg(fc_usb->udev,pipe,
+ mutex_lock(&fc_usb->data_mutex);
+
+ if ((request_type & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
+ memcpy(fc_usb->data, buf, buflen);
+
+ ret = usb_control_msg(fc_usb->udev, pipe,
req,
request_type,
wValue,
wIndex,
- buf,
+ fc_usb->data,
buflen,
- nWaitTime * HZ);
- return len == buflen ? 0 : -EREMOTEIO;
+ nWaitTime);
+
+ if (ret != buflen)
+ ret = -EIO;
+
+ if (ret >= 0) {
+ ret = 0;
+ if ((request_type & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+ memcpy(buf, fc_usb->data, buflen);
+ }
+
+ mutex_unlock(&fc_usb->data_mutex);
+
+ return ret;
}
/* actual bus specific access functions,
@@ -312,8 +339,8 @@ static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb,
b = fc_usb->tmp_buffer;
l = fc_usb->tmp_buffer_length;
} else {
- b=buffer;
- l=buffer_length;
+ b = buffer;
+ l = buffer_length;
}
while (l >= 190) {
@@ -339,7 +366,7 @@ static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb,
}
}
- if (l>0)
+ if (l > 0)
memcpy(fc_usb->tmp_buffer, b, l);
fc_usb->tmp_buffer_length = l;
}
@@ -370,7 +397,7 @@ static void flexcop_usb_urb_complete(struct urb *urb)
urb->iso_frame_desc[i].status = 0;
urb->iso_frame_desc[i].actual_length = 0;
}
- usb_submit_urb(urb,GFP_ATOMIC);
+ usb_submit_urb(urb, GFP_ATOMIC);
}
static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff)
@@ -384,31 +411,32 @@ static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
int i;
for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
if (fc_usb->iso_urb[i] != NULL) {
- deb_ts("unlinking/killing urb no. %d\n",i);
+ deb_ts("unlinking/killing urb no. %d\n", i);
usb_kill_urb(fc_usb->iso_urb[i]);
usb_free_urb(fc_usb->iso_urb[i]);
}
- if (fc_usb->iso_buffer != NULL)
- pci_free_consistent(NULL,
- fc_usb->buffer_size, fc_usb->iso_buffer,
- fc_usb->dma_addr);
+ usb_free_coherent(fc_usb->udev, fc_usb->buffer_size,
+ fc_usb->iso_buffer, fc_usb->dma_addr);
+
}
static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
{
- u16 frame_size = le16_to_cpu(
- fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize);
- int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO *
- frame_size, i, j, ret;
+ struct usb_host_interface *alt = fc_usb->uintf->cur_altsetting;
+ u16 frame_size;
+ int bufsize, i, j, ret;
int buffer_offset = 0;
- deb_ts("creating %d iso-urbs with %d frames "
- "each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB,
+ frame_size = usb_endpoint_maxp(&alt->endpoint[0].desc);
+ bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size;
+
+ deb_ts("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n",
+ B2C2_USB_NUM_ISO_URB,
B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize);
- fc_usb->iso_buffer = pci_alloc_consistent(NULL,
- bufsize, &fc_usb->dma_addr);
+ fc_usb->iso_buffer = usb_alloc_coherent(fc_usb->udev,
+ bufsize, GFP_KERNEL, &fc_usb->dma_addr);
if (fc_usb->iso_buffer == NULL)
return -ENOMEM;
@@ -418,7 +446,7 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
/* creating iso urbs */
for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,
- GFP_ATOMIC);
+ GFP_KERNEL);
if (fc_usb->iso_urb[i] == NULL) {
ret = -ENOMEM;
goto urb_error;
@@ -429,8 +457,8 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
int frame_offset = 0;
struct urb *urb = fc_usb->iso_urb[i];
- deb_ts("initializing and submitting urb no. %d "
- "(buf_offset: %d).\n", i, buffer_offset);
+ deb_ts("initializing and submitting urb no. %d (buf_offset: %d).\n",
+ i, buffer_offset);
urb->dev = fc_usb->udev;
urb->context = fc_usb;
@@ -451,11 +479,11 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
frame_offset += frame_size;
}
- if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) {
+ if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_KERNEL))) {
err("submitting urb %d failed with %d.", i, ret);
goto urb_error;
}
- deb_ts("submitted urb no. %d.\n",i);
+ deb_ts("submitted urb no. %d.\n", i);
}
/* SRAM */
@@ -473,8 +501,23 @@ urb_error:
static int flexcop_usb_init(struct flexcop_usb *fc_usb)
{
- /* use the alternate setting with the larges buffer */
- usb_set_interface(fc_usb->udev,0,1);
+ struct usb_host_interface *alt;
+ int ret;
+
+ /* use the alternate setting with the largest buffer */
+ ret = usb_set_interface(fc_usb->udev, 0, 1);
+ if (ret) {
+ err("set interface failed.");
+ return ret;
+ }
+
+ alt = fc_usb->uintf->cur_altsetting;
+
+ if (alt->desc.bNumEndpoints < 2)
+ return -ENODEV;
+ if (!usb_endpoint_is_isoc_in(&alt->endpoint[0].desc))
+ return -ENODEV;
+
switch (fc_usb->udev->speed) {
case USB_SPEED_LOW:
err("cannot handle USB speed because it is too slow.");
@@ -486,7 +529,13 @@ static int flexcop_usb_init(struct flexcop_usb *fc_usb)
case USB_SPEED_HIGH:
info("running at HIGH speed.");
break;
- case USB_SPEED_UNKNOWN: /* fall through */
+ case USB_SPEED_SUPER:
+ info("running at SUPER speed.");
+ break;
+ case USB_SPEED_SUPER_PLUS:
+ info("running at SUPER+ speed.");
+ break;
+ case USB_SPEED_UNKNOWN:
default:
err("cannot handle USB speed because it is unknown.");
return -ENODEV;
@@ -516,6 +565,7 @@ static int flexcop_usb_probe(struct usb_interface *intf,
/* general flexcop init */
fc_usb = fc->bus_specific;
fc_usb->fc_dev = fc;
+ mutex_init(&fc_usb->data_mutex);
fc->read_ibi_reg = flexcop_usb_read_ibi_reg;
fc->write_ibi_reg = flexcop_usb_write_ibi_reg;
@@ -566,7 +616,7 @@ static void flexcop_usb_disconnect(struct usb_interface *intf)
info("%s successfully deinitialized and disconnected.", DRIVER_NAME);
}
-static struct usb_device_id flexcop_usb_table [] = {
+static const struct usb_device_id flexcop_usb_table[] = {
{ USB_DEVICE(0x0af7, 0x0101) },
{ }
};