diff options
author | Antti Palosaari <crope@iki.fi> | 2012-09-21 18:44:51 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-09-27 14:14:20 -0400 |
commit | 2347e6836ad2a5a2f7e62bd12b8f52fe15f04f74 (patch) | |
tree | 2f18184689507c53a7de7870083bf923a2d61281 /drivers/media/usb/dvb-usb-v2/cypress_firmware.c | |
parent | d6f35c7128201b78fe2cb2c1eca3a5c67929566c (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.c | 80 |
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, | |||
40 | int usbv2_cypress_load_firmware(struct usb_device *udev, | 40 | int 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; | ||
94 | err_kfree: | ||
95 | kfree(hx); | ||
85 | return ret; | 96 | return ret; |
86 | } | 97 | } |
87 | EXPORT_SYMBOL(usbv2_cypress_load_firmware); | 98 | EXPORT_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; |