diff options
Diffstat (limited to 'drivers/firmware/dell_rbu.c')
-rw-r--r-- | drivers/firmware/dell_rbu.c | 361 |
1 files changed, 211 insertions, 150 deletions
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index 3b865f34a095..4f4ba9b6d182 100644 --- a/drivers/firmware/dell_rbu.c +++ b/drivers/firmware/dell_rbu.c | |||
@@ -50,7 +50,7 @@ | |||
50 | MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>"); | 50 | MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>"); |
51 | MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems"); | 51 | MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems"); |
52 | MODULE_LICENSE("GPL"); | 52 | MODULE_LICENSE("GPL"); |
53 | MODULE_VERSION("1.0"); | 53 | MODULE_VERSION("3.0"); |
54 | 54 | ||
55 | #define BIOS_SCAN_LIMIT 0xffffffff | 55 | #define BIOS_SCAN_LIMIT 0xffffffff |
56 | #define MAX_IMAGE_LENGTH 16 | 56 | #define MAX_IMAGE_LENGTH 16 |
@@ -62,14 +62,16 @@ static struct _rbu_data { | |||
62 | int dma_alloc; | 62 | int dma_alloc; |
63 | spinlock_t lock; | 63 | spinlock_t lock; |
64 | unsigned long packet_read_count; | 64 | unsigned long packet_read_count; |
65 | unsigned long packet_write_count; | ||
66 | unsigned long num_packets; | 65 | unsigned long num_packets; |
67 | unsigned long packetsize; | 66 | unsigned long packetsize; |
67 | unsigned long imagesize; | ||
68 | int entry_created; | ||
68 | } rbu_data; | 69 | } rbu_data; |
69 | 70 | ||
70 | static char image_type[MAX_IMAGE_LENGTH] = "mono"; | 71 | static char image_type[MAX_IMAGE_LENGTH + 1] = "mono"; |
71 | module_param_string(image_type, image_type, sizeof(image_type), 0); | 72 | module_param_string(image_type, image_type, sizeof (image_type), 0); |
72 | MODULE_PARM_DESC(image_type, "BIOS image type. choose- mono or packet"); | 73 | MODULE_PARM_DESC(image_type, |
74 | "BIOS image type. choose- mono or packet or init"); | ||
73 | 75 | ||
74 | struct packet_data { | 76 | struct packet_data { |
75 | struct list_head list; | 77 | struct list_head list; |
@@ -87,55 +89,13 @@ static dma_addr_t dell_rbu_dmaaddr; | |||
87 | static void init_packet_head(void) | 89 | static void init_packet_head(void) |
88 | { | 90 | { |
89 | INIT_LIST_HEAD(&packet_data_head.list); | 91 | INIT_LIST_HEAD(&packet_data_head.list); |
90 | rbu_data.packet_write_count = 0; | ||
91 | rbu_data.packet_read_count = 0; | 92 | rbu_data.packet_read_count = 0; |
92 | rbu_data.num_packets = 0; | 93 | rbu_data.num_packets = 0; |
93 | rbu_data.packetsize = 0; | 94 | rbu_data.packetsize = 0; |
95 | rbu_data.imagesize = 0; | ||
94 | } | 96 | } |
95 | 97 | ||
96 | static int fill_last_packet(void *data, size_t length) | 98 | static int create_packet(void *data, size_t length) |
97 | { | ||
98 | struct list_head *ptemp_list; | ||
99 | struct packet_data *packet = NULL; | ||
100 | int packet_count = 0; | ||
101 | |||
102 | pr_debug("fill_last_packet: entry \n"); | ||
103 | |||
104 | if (!rbu_data.num_packets) { | ||
105 | pr_debug("fill_last_packet: num_packets=0\n"); | ||
106 | return -ENOMEM; | ||
107 | } | ||
108 | |||
109 | packet_count = rbu_data.num_packets; | ||
110 | |||
111 | ptemp_list = (&packet_data_head.list)->prev; | ||
112 | |||
113 | packet = list_entry(ptemp_list, struct packet_data, list); | ||
114 | |||
115 | if ((rbu_data.packet_write_count + length) > rbu_data.packetsize) { | ||
116 | pr_debug("dell_rbu:%s: packet size data " | ||
117 | "overrun\n", __FUNCTION__); | ||
118 | return -EINVAL; | ||
119 | } | ||
120 | |||
121 | pr_debug("fill_last_packet : buffer = %p\n", packet->data); | ||
122 | |||
123 | memcpy((packet->data + rbu_data.packet_write_count), data, length); | ||
124 | |||
125 | if ((rbu_data.packet_write_count + length) == rbu_data.packetsize) { | ||
126 | /* | ||
127 | * this was the last data chunk in the packet | ||
128 | * so reinitialize the packet data counter to zero | ||
129 | */ | ||
130 | rbu_data.packet_write_count = 0; | ||
131 | } else | ||
132 | rbu_data.packet_write_count += length; | ||
133 | |||
134 | pr_debug("fill_last_packet: exit \n"); | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static int create_packet(size_t length) | ||
139 | { | 99 | { |
140 | struct packet_data *newpacket; | 100 | struct packet_data *newpacket; |
141 | int ordernum = 0; | 101 | int ordernum = 0; |
@@ -146,12 +106,14 @@ static int create_packet(size_t length) | |||
146 | pr_debug("create_packet: packetsize not specified\n"); | 106 | pr_debug("create_packet: packetsize not specified\n"); |
147 | return -EINVAL; | 107 | return -EINVAL; |
148 | } | 108 | } |
109 | spin_unlock(&rbu_data.lock); | ||
110 | newpacket = kmalloc(sizeof (struct packet_data), GFP_KERNEL); | ||
111 | spin_lock(&rbu_data.lock); | ||
149 | 112 | ||
150 | newpacket = kmalloc(sizeof(struct packet_data), GFP_KERNEL); | ||
151 | if (!newpacket) { | 113 | if (!newpacket) { |
152 | printk(KERN_WARNING | 114 | printk(KERN_WARNING |
153 | "dell_rbu:%s: failed to allocate new " | 115 | "dell_rbu:%s: failed to allocate new " |
154 | "packet\n", __FUNCTION__); | 116 | "packet\n", __FUNCTION__); |
155 | return -ENOMEM; | 117 | return -ENOMEM; |
156 | } | 118 | } |
157 | 119 | ||
@@ -160,15 +122,17 @@ static int create_packet(size_t length) | |||
160 | * there is no upper limit on memory | 122 | * there is no upper limit on memory |
161 | * address for packetized mechanism | 123 | * address for packetized mechanism |
162 | */ | 124 | */ |
163 | newpacket->data = (unsigned char *)__get_free_pages(GFP_KERNEL, | 125 | spin_unlock(&rbu_data.lock); |
164 | ordernum); | 126 | newpacket->data = (unsigned char *) __get_free_pages(GFP_KERNEL, |
127 | ordernum); | ||
128 | spin_lock(&rbu_data.lock); | ||
165 | 129 | ||
166 | pr_debug("create_packet: newpacket %p\n", newpacket->data); | 130 | pr_debug("create_packet: newpacket %p\n", newpacket->data); |
167 | 131 | ||
168 | if (!newpacket->data) { | 132 | if (!newpacket->data) { |
169 | printk(KERN_WARNING | 133 | printk(KERN_WARNING |
170 | "dell_rbu:%s: failed to allocate new " | 134 | "dell_rbu:%s: failed to allocate new " |
171 | "packet\n", __FUNCTION__); | 135 | "packet\n", __FUNCTION__); |
172 | kfree(newpacket); | 136 | kfree(newpacket); |
173 | return -ENOMEM; | 137 | return -ENOMEM; |
174 | } | 138 | } |
@@ -181,9 +145,11 @@ static int create_packet(size_t length) | |||
181 | INIT_LIST_HEAD(&newpacket->list); | 145 | INIT_LIST_HEAD(&newpacket->list); |
182 | list_add_tail(&newpacket->list, &packet_data_head.list); | 146 | list_add_tail(&newpacket->list, &packet_data_head.list); |
183 | /* | 147 | /* |
184 | * packets have fixed size | 148 | * packets may not have fixed size |
185 | */ | 149 | */ |
186 | newpacket->length = rbu_data.packetsize; | 150 | newpacket->length = length; |
151 | |||
152 | memcpy(newpacket->data, data, length); | ||
187 | 153 | ||
188 | pr_debug("create_packet: exit \n"); | 154 | pr_debug("create_packet: exit \n"); |
189 | 155 | ||
@@ -193,20 +159,43 @@ static int create_packet(size_t length) | |||
193 | static int packetize_data(void *data, size_t length) | 159 | static int packetize_data(void *data, size_t length) |
194 | { | 160 | { |
195 | int rc = 0; | 161 | int rc = 0; |
162 | int done = 0; | ||
163 | int packet_length; | ||
164 | u8 *temp; | ||
165 | u8 *end = (u8 *) data + length; | ||
166 | pr_debug("packetize_data: data length %d\n", length); | ||
167 | if (!rbu_data.packetsize) { | ||
168 | printk(KERN_WARNING | ||
169 | "dell_rbu: packetsize not specified\n"); | ||
170 | return -EIO; | ||
171 | } | ||
172 | |||
173 | temp = (u8 *) data; | ||
196 | 174 | ||
197 | if (!rbu_data.packet_write_count) { | 175 | /* packetize the hunk */ |
198 | if ((rc = create_packet(length))) | 176 | while (!done) { |
177 | if ((temp + rbu_data.packetsize) < end) | ||
178 | packet_length = rbu_data.packetsize; | ||
179 | else { | ||
180 | /* this is the last packet */ | ||
181 | packet_length = end - temp; | ||
182 | done = 1; | ||
183 | } | ||
184 | |||
185 | if ((rc = create_packet(temp, packet_length))) | ||
199 | return rc; | 186 | return rc; |
187 | |||
188 | pr_debug("%lu:%lu\n", temp, (end - temp)); | ||
189 | temp += packet_length; | ||
200 | } | 190 | } |
201 | if ((rc = fill_last_packet(data, length))) | 191 | |
202 | return rc; | 192 | rbu_data.imagesize = length; |
203 | 193 | ||
204 | return rc; | 194 | return rc; |
205 | } | 195 | } |
206 | 196 | ||
207 | static int | 197 | static int do_packet_read(char *data, struct list_head *ptemp_list, |
208 | do_packet_read(char *data, struct list_head *ptemp_list, | 198 | int length, int bytes_read, int *list_read_count) |
209 | int length, int bytes_read, int *list_read_count) | ||
210 | { | 199 | { |
211 | void *ptemp_buf; | 200 | void *ptemp_buf; |
212 | struct packet_data *newpacket = NULL; | 201 | struct packet_data *newpacket = NULL; |
@@ -258,8 +247,7 @@ static int packet_read_list(char *data, size_t * pread_length) | |||
258 | ptemp_list = (&packet_data_head.list)->next; | 247 | ptemp_list = (&packet_data_head.list)->next; |
259 | while (!list_empty(ptemp_list)) { | 248 | while (!list_empty(ptemp_list)) { |
260 | bytes_copied = do_packet_read(pdest, ptemp_list, | 249 | bytes_copied = do_packet_read(pdest, ptemp_list, |
261 | remaining_bytes, bytes_read, | 250 | remaining_bytes, bytes_read, &temp_count); |
262 | &temp_count); | ||
263 | remaining_bytes -= bytes_copied; | 251 | remaining_bytes -= bytes_copied; |
264 | bytes_read += bytes_copied; | 252 | bytes_read += bytes_copied; |
265 | pdest += bytes_copied; | 253 | pdest += bytes_copied; |
@@ -287,7 +275,7 @@ static void packet_empty_list(void) | |||
287 | ptemp_list = (&packet_data_head.list)->next; | 275 | ptemp_list = (&packet_data_head.list)->next; |
288 | while (!list_empty(ptemp_list)) { | 276 | while (!list_empty(ptemp_list)) { |
289 | newpacket = | 277 | newpacket = |
290 | list_entry(ptemp_list, struct packet_data, list); | 278 | list_entry(ptemp_list, struct packet_data, list); |
291 | pnext_list = ptemp_list->next; | 279 | pnext_list = ptemp_list->next; |
292 | list_del(ptemp_list); | 280 | list_del(ptemp_list); |
293 | ptemp_list = pnext_list; | 281 | ptemp_list = pnext_list; |
@@ -296,14 +284,13 @@ static void packet_empty_list(void) | |||
296 | * to make sure there are no stale RBU packets left in memory | 284 | * to make sure there are no stale RBU packets left in memory |
297 | */ | 285 | */ |
298 | memset(newpacket->data, 0, rbu_data.packetsize); | 286 | memset(newpacket->data, 0, rbu_data.packetsize); |
299 | free_pages((unsigned long)newpacket->data, | 287 | free_pages((unsigned long) newpacket->data, |
300 | newpacket->ordernum); | 288 | newpacket->ordernum); |
301 | kfree(newpacket); | 289 | kfree(newpacket); |
302 | } | 290 | } |
303 | rbu_data.packet_write_count = 0; | ||
304 | rbu_data.packet_read_count = 0; | 291 | rbu_data.packet_read_count = 0; |
305 | rbu_data.num_packets = 0; | 292 | rbu_data.num_packets = 0; |
306 | rbu_data.packetsize = 0; | 293 | rbu_data.imagesize = 0; |
307 | } | 294 | } |
308 | 295 | ||
309 | /* | 296 | /* |
@@ -319,14 +306,13 @@ static void img_update_free(void) | |||
319 | * BIOS image copied in memory. | 306 | * BIOS image copied in memory. |
320 | */ | 307 | */ |
321 | memset(rbu_data.image_update_buffer, 0, | 308 | memset(rbu_data.image_update_buffer, 0, |
322 | rbu_data.image_update_buffer_size); | 309 | rbu_data.image_update_buffer_size); |
323 | if (rbu_data.dma_alloc == 1) | 310 | if (rbu_data.dma_alloc == 1) |
324 | dma_free_coherent(NULL, rbu_data.bios_image_size, | 311 | dma_free_coherent(NULL, rbu_data.bios_image_size, |
325 | rbu_data.image_update_buffer, | 312 | rbu_data.image_update_buffer, dell_rbu_dmaaddr); |
326 | dell_rbu_dmaaddr); | ||
327 | else | 313 | else |
328 | free_pages((unsigned long)rbu_data.image_update_buffer, | 314 | free_pages((unsigned long) rbu_data.image_update_buffer, |
329 | rbu_data.image_update_ordernum); | 315 | rbu_data.image_update_ordernum); |
330 | 316 | ||
331 | /* | 317 | /* |
332 | * Re-initialize the rbu_data variables after a free | 318 | * Re-initialize the rbu_data variables after a free |
@@ -366,7 +352,7 @@ static int img_update_realloc(unsigned long size) | |||
366 | */ | 352 | */ |
367 | if ((size != 0) && (rbu_data.image_update_buffer == NULL)) { | 353 | if ((size != 0) && (rbu_data.image_update_buffer == NULL)) { |
368 | printk(KERN_ERR "dell_rbu:%s: corruption " | 354 | printk(KERN_ERR "dell_rbu:%s: corruption " |
369 | "check failed\n", __FUNCTION__); | 355 | "check failed\n", __FUNCTION__); |
370 | return -EINVAL; | 356 | return -EINVAL; |
371 | } | 357 | } |
372 | /* | 358 | /* |
@@ -385,17 +371,16 @@ static int img_update_realloc(unsigned long size) | |||
385 | 371 | ||
386 | ordernum = get_order(size); | 372 | ordernum = get_order(size); |
387 | image_update_buffer = | 373 | image_update_buffer = |
388 | (unsigned char *)__get_free_pages(GFP_KERNEL, ordernum); | 374 | (unsigned char *) __get_free_pages(GFP_KERNEL, ordernum); |
389 | 375 | ||
390 | img_buf_phys_addr = | 376 | img_buf_phys_addr = |
391 | (unsigned long)virt_to_phys(image_update_buffer); | 377 | (unsigned long) virt_to_phys(image_update_buffer); |
392 | 378 | ||
393 | if (img_buf_phys_addr > BIOS_SCAN_LIMIT) { | 379 | if (img_buf_phys_addr > BIOS_SCAN_LIMIT) { |
394 | free_pages((unsigned long)image_update_buffer, ordernum); | 380 | free_pages((unsigned long) image_update_buffer, ordernum); |
395 | ordernum = -1; | 381 | ordernum = -1; |
396 | image_update_buffer = dma_alloc_coherent(NULL, size, | 382 | image_update_buffer = dma_alloc_coherent(NULL, size, |
397 | &dell_rbu_dmaaddr, | 383 | &dell_rbu_dmaaddr, GFP_KERNEL); |
398 | GFP_KERNEL); | ||
399 | dma_alloc = 1; | 384 | dma_alloc = 1; |
400 | } | 385 | } |
401 | 386 | ||
@@ -405,13 +390,13 @@ static int img_update_realloc(unsigned long size) | |||
405 | rbu_data.image_update_buffer = image_update_buffer; | 390 | rbu_data.image_update_buffer = image_update_buffer; |
406 | rbu_data.image_update_buffer_size = size; | 391 | rbu_data.image_update_buffer_size = size; |
407 | rbu_data.bios_image_size = | 392 | rbu_data.bios_image_size = |
408 | rbu_data.image_update_buffer_size; | 393 | rbu_data.image_update_buffer_size; |
409 | rbu_data.image_update_ordernum = ordernum; | 394 | rbu_data.image_update_ordernum = ordernum; |
410 | rbu_data.dma_alloc = dma_alloc; | 395 | rbu_data.dma_alloc = dma_alloc; |
411 | rc = 0; | 396 | rc = 0; |
412 | } else { | 397 | } else { |
413 | pr_debug("Not enough memory for image update:" | 398 | pr_debug("Not enough memory for image update:" |
414 | "size = %ld\n", size); | 399 | "size = %ld\n", size); |
415 | rc = -ENOMEM; | 400 | rc = -ENOMEM; |
416 | } | 401 | } |
417 | 402 | ||
@@ -424,7 +409,6 @@ static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count) | |||
424 | size_t bytes_left; | 409 | size_t bytes_left; |
425 | size_t data_length; | 410 | size_t data_length; |
426 | char *ptempBuf = buffer; | 411 | char *ptempBuf = buffer; |
427 | unsigned long imagesize; | ||
428 | 412 | ||
429 | /* check to see if we have something to return */ | 413 | /* check to see if we have something to return */ |
430 | if (rbu_data.num_packets == 0) { | 414 | if (rbu_data.num_packets == 0) { |
@@ -433,22 +417,20 @@ static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count) | |||
433 | goto read_rbu_data_exit; | 417 | goto read_rbu_data_exit; |
434 | } | 418 | } |
435 | 419 | ||
436 | imagesize = rbu_data.num_packets * rbu_data.packetsize; | 420 | if (pos > rbu_data.imagesize) { |
437 | |||
438 | if (pos > imagesize) { | ||
439 | retval = 0; | 421 | retval = 0; |
440 | printk(KERN_WARNING "dell_rbu:read_packet_data: " | 422 | printk(KERN_WARNING "dell_rbu:read_packet_data: " |
441 | "data underrun\n"); | 423 | "data underrun\n"); |
442 | goto read_rbu_data_exit; | 424 | goto read_rbu_data_exit; |
443 | } | 425 | } |
444 | 426 | ||
445 | bytes_left = imagesize - pos; | 427 | bytes_left = rbu_data.imagesize - pos; |
446 | data_length = min(bytes_left, count); | 428 | data_length = min(bytes_left, count); |
447 | 429 | ||
448 | if ((retval = packet_read_list(ptempBuf, &data_length)) < 0) | 430 | if ((retval = packet_read_list(ptempBuf, &data_length)) < 0) |
449 | goto read_rbu_data_exit; | 431 | goto read_rbu_data_exit; |
450 | 432 | ||
451 | if ((pos + count) > imagesize) { | 433 | if ((pos + count) > rbu_data.imagesize) { |
452 | rbu_data.packet_read_count = 0; | 434 | rbu_data.packet_read_count = 0; |
453 | /* this was the last copy */ | 435 | /* this was the last copy */ |
454 | retval = bytes_left; | 436 | retval = bytes_left; |
@@ -468,11 +450,11 @@ static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count) | |||
468 | 450 | ||
469 | /* check to see if we have something to return */ | 451 | /* check to see if we have something to return */ |
470 | if ((rbu_data.image_update_buffer == NULL) || | 452 | if ((rbu_data.image_update_buffer == NULL) || |
471 | (rbu_data.bios_image_size == 0)) { | 453 | (rbu_data.bios_image_size == 0)) { |
472 | pr_debug("read_rbu_data_mono: image_update_buffer %p ," | 454 | pr_debug("read_rbu_data_mono: image_update_buffer %p ," |
473 | "bios_image_size %lu\n", | 455 | "bios_image_size %lu\n", |
474 | rbu_data.image_update_buffer, | 456 | rbu_data.image_update_buffer, |
475 | rbu_data.bios_image_size); | 457 | rbu_data.bios_image_size); |
476 | ret_count = -ENOMEM; | 458 | ret_count = -ENOMEM; |
477 | goto read_rbu_data_exit; | 459 | goto read_rbu_data_exit; |
478 | } | 460 | } |
@@ -497,8 +479,8 @@ static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count) | |||
497 | return ret_count; | 479 | return ret_count; |
498 | } | 480 | } |
499 | 481 | ||
500 | static ssize_t | 482 | static ssize_t read_rbu_data(struct kobject *kobj, char *buffer, |
501 | read_rbu_data(struct kobject *kobj, char *buffer, loff_t pos, size_t count) | 483 | loff_t pos, size_t count) |
502 | { | 484 | { |
503 | ssize_t ret_count = 0; | 485 | ssize_t ret_count = 0; |
504 | 486 | ||
@@ -515,9 +497,49 @@ read_rbu_data(struct kobject *kobj, char *buffer, loff_t pos, size_t count) | |||
515 | return ret_count; | 497 | return ret_count; |
516 | } | 498 | } |
517 | 499 | ||
518 | static ssize_t | 500 | static void callbackfn_rbu(const struct firmware *fw, void *context) |
519 | read_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos, | 501 | { |
520 | size_t count) | 502 | int rc = 0; |
503 | |||
504 | if (!fw || !fw->size) { | ||
505 | rbu_data.entry_created = 0; | ||
506 | return; | ||
507 | } | ||
508 | |||
509 | spin_lock(&rbu_data.lock); | ||
510 | if (!strcmp(image_type, "mono")) { | ||
511 | if (!img_update_realloc(fw->size)) | ||
512 | memcpy(rbu_data.image_update_buffer, | ||
513 | fw->data, fw->size); | ||
514 | } else if (!strcmp(image_type, "packet")) { | ||
515 | /* | ||
516 | * we need to free previous packets if a | ||
517 | * new hunk of packets needs to be downloaded | ||
518 | */ | ||
519 | packet_empty_list(); | ||
520 | if (packetize_data(fw->data, fw->size)) | ||
521 | /* Incase something goes wrong when we are | ||
522 | * in middle of packetizing the data, we | ||
523 | * need to free up whatever packets might | ||
524 | * have been created before we quit. | ||
525 | */ | ||
526 | packet_empty_list(); | ||
527 | } else | ||
528 | pr_debug("invalid image type specified.\n"); | ||
529 | spin_unlock(&rbu_data.lock); | ||
530 | |||
531 | rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, | ||
532 | "dell_rbu", &rbu_device->dev, &context, callbackfn_rbu); | ||
533 | if (rc) | ||
534 | printk(KERN_ERR | ||
535 | "dell_rbu:%s request_firmware_nowait failed" | ||
536 | " %d\n", __FUNCTION__, rc); | ||
537 | else | ||
538 | rbu_data.entry_created = 1; | ||
539 | } | ||
540 | |||
541 | static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer, | ||
542 | loff_t pos, size_t count) | ||
521 | { | 543 | { |
522 | int size = 0; | 544 | int size = 0; |
523 | if (!pos) | 545 | if (!pos) |
@@ -525,27 +547,90 @@ read_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos, | |||
525 | return size; | 547 | return size; |
526 | } | 548 | } |
527 | 549 | ||
528 | static ssize_t | 550 | static ssize_t write_rbu_image_type(struct kobject *kobj, char *buffer, |
529 | write_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos, | 551 | loff_t pos, size_t count) |
530 | size_t count) | ||
531 | { | 552 | { |
532 | int rc = count; | 553 | int rc = count; |
554 | int req_firm_rc = 0; | ||
555 | int i; | ||
533 | spin_lock(&rbu_data.lock); | 556 | spin_lock(&rbu_data.lock); |
534 | 557 | /* | |
535 | if (strlen(buffer) < MAX_IMAGE_LENGTH) | 558 | * Find the first newline or space |
536 | sscanf(buffer, "%s", image_type); | 559 | */ |
537 | else | 560 | for (i = 0; i < count; ++i) |
538 | printk(KERN_WARNING "dell_rbu: image_type is invalid" | 561 | if (buffer[i] == '\n' || buffer[i] == ' ') { |
539 | "max chars = %d, \n incoming str--%s-- \n", | 562 | buffer[i] = '\0'; |
540 | MAX_IMAGE_LENGTH, buffer); | 563 | break; |
564 | } | ||
565 | if (i == count) | ||
566 | buffer[count] = '\0'; | ||
567 | |||
568 | if (strstr(buffer, "mono")) | ||
569 | strcpy(image_type, "mono"); | ||
570 | else if (strstr(buffer, "packet")) | ||
571 | strcpy(image_type, "packet"); | ||
572 | else if (strstr(buffer, "init")) { | ||
573 | /* | ||
574 | * If due to the user error the driver gets in a bad | ||
575 | * state where even though it is loaded , the | ||
576 | * /sys/class/firmware/dell_rbu entries are missing. | ||
577 | * to cover this situation the user can recreate entries | ||
578 | * by writing init to image_type. | ||
579 | */ | ||
580 | if (!rbu_data.entry_created) { | ||
581 | spin_unlock(&rbu_data.lock); | ||
582 | req_firm_rc = request_firmware_nowait(THIS_MODULE, | ||
583 | FW_ACTION_NOHOTPLUG, "dell_rbu", | ||
584 | &rbu_device->dev, &context, | ||
585 | callbackfn_rbu); | ||
586 | if (req_firm_rc) { | ||
587 | printk(KERN_ERR | ||
588 | "dell_rbu:%s request_firmware_nowait" | ||
589 | " failed %d\n", __FUNCTION__, rc); | ||
590 | rc = -EIO; | ||
591 | } else | ||
592 | rbu_data.entry_created = 1; | ||
593 | |||
594 | spin_lock(&rbu_data.lock); | ||
595 | } | ||
596 | } else { | ||
597 | printk(KERN_WARNING "dell_rbu: image_type is invalid\n"); | ||
598 | spin_unlock(&rbu_data.lock); | ||
599 | return -EINVAL; | ||
600 | } | ||
541 | 601 | ||
542 | /* we must free all previous allocations */ | 602 | /* we must free all previous allocations */ |
543 | packet_empty_list(); | 603 | packet_empty_list(); |
544 | img_update_free(); | 604 | img_update_free(); |
545 | |||
546 | spin_unlock(&rbu_data.lock); | 605 | spin_unlock(&rbu_data.lock); |
606 | |||
547 | return rc; | 607 | return rc; |
608 | } | ||
548 | 609 | ||
610 | static ssize_t read_rbu_packet_size(struct kobject *kobj, char *buffer, | ||
611 | loff_t pos, size_t count) | ||
612 | { | ||
613 | int size = 0; | ||
614 | if (!pos) { | ||
615 | spin_lock(&rbu_data.lock); | ||
616 | size = sprintf(buffer, "%lu\n", rbu_data.packetsize); | ||
617 | spin_unlock(&rbu_data.lock); | ||
618 | } | ||
619 | return size; | ||
620 | } | ||
621 | |||
622 | static ssize_t write_rbu_packet_size(struct kobject *kobj, char *buffer, | ||
623 | loff_t pos, size_t count) | ||
624 | { | ||
625 | unsigned long temp; | ||
626 | spin_lock(&rbu_data.lock); | ||
627 | packet_empty_list(); | ||
628 | sscanf(buffer, "%lu", &temp); | ||
629 | if (temp < 0xffffffff) | ||
630 | rbu_data.packetsize = temp; | ||
631 | |||
632 | spin_unlock(&rbu_data.lock); | ||
633 | return count; | ||
549 | } | 634 | } |
550 | 635 | ||
551 | static struct bin_attribute rbu_data_attr = { | 636 | static struct bin_attribute rbu_data_attr = { |
@@ -559,38 +644,11 @@ static struct bin_attribute rbu_image_type_attr = { | |||
559 | .write = write_rbu_image_type, | 644 | .write = write_rbu_image_type, |
560 | }; | 645 | }; |
561 | 646 | ||
562 | static void callbackfn_rbu(const struct firmware *fw, void *context) | 647 | static struct bin_attribute rbu_packet_size_attr = { |
563 | { | 648 | .attr = {.name = "packet_size",.owner = THIS_MODULE,.mode = 0644}, |
564 | int rc = 0; | 649 | .read = read_rbu_packet_size, |
565 | 650 | .write = write_rbu_packet_size, | |
566 | if (!fw || !fw->size) | 651 | }; |
567 | return; | ||
568 | |||
569 | spin_lock(&rbu_data.lock); | ||
570 | if (!strcmp(image_type, "mono")) { | ||
571 | if (!img_update_realloc(fw->size)) | ||
572 | memcpy(rbu_data.image_update_buffer, | ||
573 | fw->data, fw->size); | ||
574 | } else if (!strcmp(image_type, "packet")) { | ||
575 | if (!rbu_data.packetsize) | ||
576 | rbu_data.packetsize = fw->size; | ||
577 | else if (rbu_data.packetsize != fw->size) { | ||
578 | packet_empty_list(); | ||
579 | rbu_data.packetsize = fw->size; | ||
580 | } | ||
581 | packetize_data(fw->data, fw->size); | ||
582 | } else | ||
583 | pr_debug("invalid image type specified.\n"); | ||
584 | spin_unlock(&rbu_data.lock); | ||
585 | |||
586 | rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, | ||
587 | "dell_rbu", &rbu_device->dev, | ||
588 | &context, callbackfn_rbu); | ||
589 | if (rc) | ||
590 | printk(KERN_ERR | ||
591 | "dell_rbu:%s request_firmware_nowait failed" | ||
592 | " %d\n", __FUNCTION__, rc); | ||
593 | } | ||
594 | 652 | ||
595 | static int __init dcdrbu_init(void) | 653 | static int __init dcdrbu_init(void) |
596 | { | 654 | { |
@@ -599,23 +657,26 @@ static int __init dcdrbu_init(void) | |||
599 | 657 | ||
600 | init_packet_head(); | 658 | init_packet_head(); |
601 | rbu_device = | 659 | rbu_device = |
602 | platform_device_register_simple("dell_rbu", -1, NULL, 0); | 660 | platform_device_register_simple("dell_rbu", -1, NULL, 0); |
603 | if (!rbu_device) { | 661 | if (!rbu_device) { |
604 | printk(KERN_ERR | 662 | printk(KERN_ERR |
605 | "dell_rbu:%s:platform_device_register_simple " | 663 | "dell_rbu:%s:platform_device_register_simple " |
606 | "failed\n", __FUNCTION__); | 664 | "failed\n", __FUNCTION__); |
607 | return -EIO; | 665 | return -EIO; |
608 | } | 666 | } |
609 | 667 | ||
610 | sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr); | 668 | sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr); |
611 | sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); | 669 | sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); |
670 | sysfs_create_bin_file(&rbu_device->dev.kobj, | ||
671 | &rbu_packet_size_attr); | ||
612 | 672 | ||
613 | rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, | 673 | rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, |
614 | "dell_rbu", &rbu_device->dev, | 674 | "dell_rbu", &rbu_device->dev, &context, callbackfn_rbu); |
615 | &context, callbackfn_rbu); | ||
616 | if (rc) | 675 | if (rc) |
617 | printk(KERN_ERR "dell_rbu:%s:request_firmware_nowait" | 676 | printk(KERN_ERR "dell_rbu:%s:request_firmware_nowait" |
618 | " failed %d\n", __FUNCTION__, rc); | 677 | " failed %d\n", __FUNCTION__, rc); |
678 | else | ||
679 | rbu_data.entry_created = 1; | ||
619 | 680 | ||
620 | return rc; | 681 | return rc; |
621 | 682 | ||