aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/usb/dvb-usb-v2/cypress_firmware.c
diff options
context:
space:
mode:
authorAntti Palosaari <crope@iki.fi>2012-09-21 18:44:51 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-09-27 14:14:20 -0400
commit2347e6836ad2a5a2f7e62bd12b8f52fe15f04f74 (patch)
tree2f18184689507c53a7de7870083bf923a2d61281 /drivers/media/usb/dvb-usb-v2/cypress_firmware.c
parentd6f35c7128201b78fe2cb2c1eca3a5c67929566c (diff)
[media] cypress_firmware: refactor firmware downloading
Refactor firmware download function. It also should fix one bug coming from usb_control_msg() message buffers. Taking buffers from the stack for usb_control_msg() is not allowed as it does not work on all architectures. Allocate buffers using kmalloc(). Signed-off-by: Antti Palosaari <crope@iki.fi> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/usb/dvb-usb-v2/cypress_firmware.c')
-rw-r--r--drivers/media/usb/dvb-usb-v2/cypress_firmware.c80
1 files changed, 43 insertions, 37 deletions
diff --git a/drivers/media/usb/dvb-usb-v2/cypress_firmware.c b/drivers/media/usb/dvb-usb-v2/cypress_firmware.c
index bb21eeea5495..211df549f26a 100644
--- a/drivers/media/usb/dvb-usb-v2/cypress_firmware.c
+++ b/drivers/media/usb/dvb-usb-v2/cypress_firmware.c
@@ -40,48 +40,59 @@ static int usb_cypress_writemem(struct usb_device *udev, u16 addr, u8 *data,
40int usbv2_cypress_load_firmware(struct usb_device *udev, 40int usbv2_cypress_load_firmware(struct usb_device *udev,
41 const struct firmware *fw, int type) 41 const struct firmware *fw, int type)
42{ 42{
43 struct hexline hx; 43 struct hexline *hx;
44 u8 reset;
45 int ret, pos = 0; 44 int ret, pos = 0;
46 45
46 hx = kmalloc(sizeof(struct hexline), GFP_KERNEL);
47 if (!hx) {
48 dev_err(&udev->dev, "%s: kmalloc() failed\n", KBUILD_MODNAME);
49 return -ENOMEM;
50 }
51
47 /* stop the CPU */ 52 /* stop the CPU */
48 reset = 1; 53 hx->data[0] = 1;
49 ret = usb_cypress_writemem(udev, cypress[type].cs_reg, &reset, 1); 54 ret = usb_cypress_writemem(udev, cypress[type].cs_reg, hx->data, 1);
50 if (ret != 1) 55 if (ret != 1) {
51 dev_err(&udev->dev, 56 dev_err(&udev->dev, "%s: CPU stop failed=%d\n",
52 "%s: could not stop the USB controller CPU\n", 57 KBUILD_MODNAME, ret);
53 KBUILD_MODNAME); 58 ret = -EIO;
54 59 goto err_kfree;
55 while ((ret = dvb_usbv2_get_hexline(fw, &hx, &pos)) > 0) { 60 }
56 ret = usb_cypress_writemem(udev, hx.addr, hx.data, hx.len); 61
57 if (ret != hx.len) { 62 /* write firmware to memory */
63 for (;;) {
64 ret = dvb_usbv2_get_hexline(fw, hx, &pos);
65 if (ret < 0)
66 goto err_kfree;
67 else if (ret == 0)
68 break;
69
70 ret = usb_cypress_writemem(udev, hx->addr, hx->data, hx->len);
71 if (ret < 0) {
72 goto err_kfree;
73 } else if (ret != hx->len) {
58 dev_err(&udev->dev, "%s: error while transferring " \ 74 dev_err(&udev->dev, "%s: error while transferring " \
59 "firmware (transferred size=%d, " \ 75 "firmware (transferred size=%d, " \
60 "block size=%d)\n", 76 "block size=%d)\n",
61 KBUILD_MODNAME, ret, hx.len); 77 KBUILD_MODNAME, ret, hx->len);
62 ret = -EINVAL; 78 ret = -EIO;
63 break; 79 goto err_kfree;
64 } 80 }
65 } 81 }
66 if (ret < 0) {
67 dev_err(&udev->dev,
68 "%s: firmware download failed at %d with %d\n",
69 KBUILD_MODNAME, pos, ret);
70 return ret;
71 }
72 82
73 if (ret == 0) { 83 /* start the CPU */
74 /* restart the CPU */ 84 hx->data[0] = 0;
75 reset = 0; 85 ret = usb_cypress_writemem(udev, cypress[type].cs_reg, hx->data, 1);
76 if (ret || usb_cypress_writemem( 86 if (ret != 1) {
77 udev, cypress[type].cs_reg, &reset, 1) != 1) { 87 dev_err(&udev->dev, "%s: CPU start failed=%d\n",
78 dev_err(&udev->dev, "%s: could not restart the USB " \ 88 KBUILD_MODNAME, ret);
79 "controller CPU\n", KBUILD_MODNAME);
80 ret = -EINVAL;
81 }
82 } else
83 ret = -EIO; 89 ret = -EIO;
90 goto err_kfree;
91 }
84 92
93 ret = 0;
94err_kfree:
95 kfree(hx);
85 return ret; 96 return ret;
86} 97}
87EXPORT_SYMBOL(usbv2_cypress_load_firmware); 98EXPORT_SYMBOL(usbv2_cypress_load_firmware);
@@ -96,7 +107,6 @@ int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx,
96 return 0; 107 return 0;
97 108
98 memset(hx, 0, sizeof(struct hexline)); 109 memset(hx, 0, sizeof(struct hexline));
99
100 hx->len = b[0]; 110 hx->len = b[0];
101 111
102 if ((*pos + hx->len + 4) >= fw->size) 112 if ((*pos + hx->len + 4) >= fw->size)
@@ -109,14 +119,10 @@ int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx,
109 /* b[4] and b[5] are the Extended linear address record data 119 /* b[4] and b[5] are the Extended linear address record data
110 * field */ 120 * field */
111 hx->addr |= (b[4] << 24) | (b[5] << 16); 121 hx->addr |= (b[4] << 24) | (b[5] << 16);
112 /*
113 hx->len -= 2;
114 data_offs += 2;
115 */
116 } 122 }
123
117 memcpy(hx->data, &b[data_offs], hx->len); 124 memcpy(hx->data, &b[data_offs], hx->len);
118 hx->chk = b[hx->len + data_offs]; 125 hx->chk = b[hx->len + data_offs];
119
120 *pos += hx->len + 5; 126 *pos += hx->len + 5;
121 127
122 return *pos; 128 return *pos;