1/* 2 * dell_rbu.c 3 * Bios Update driver for Dell systems 4 * Author: Dell Inc 5 * Abhay Salunke <abhay_salunke@dell.com> 6 * 7 * Copyright (C) 2005 Dell Inc. 8 * 9 * Remote BIOS Update (rbu) driver is used for updating DELL BIOS by 10 * creating entries in the /sys file systems on Linux 2.6 and higher 11 * kernels. The driver supports two mechanism to update the BIOS namely 12 * contiguous and packetized. Both these methods still require having some 13 * application to set the CMOS bit indicating the BIOS to update itself 14 * after a reboot. 15 * 16 * Contiguous method: 17 * This driver writes the incoming data in a monolithic image by allocating 18 * contiguous physical pages large enough to accommodate the incoming BIOS 19 * image size. 20 * 21 * Packetized method: 22 * The driver writes the incoming packet image by allocating a new packet 23 * on every time the packet data is written. This driver requires an 24 * application to break the BIOS image in to fixed sized packet chunks. 25 * 26 * See Documentation/dell_rbu.txt for more info. 27 * 28 * This program is free software; you can redistribute it and/or modify 29 * it under the terms of the GNU General Public License v2.0 as published by 30 * the Free Software Foundation 31 * 32 * This program is distributed in the hope that it will be useful, 33 * but WITHOUT ANY WARRANTY; without even the implied warranty of 34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 35 * GNU General Public License for more details. 36 */ 37#include <linux/init.h> 38#include <linux/module.h> 39#include <linux/string.h> 40#include <linux/errno.h> 41#include <linux/blkdev.h> 42#include <linux/platform_device.h> 43#include <linux/spinlock.h> 44#include <linux/moduleparam.h> 45#include <linux/firmware.h> 46#include <linux/dma-mapping.h> 47 48MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>"); 49MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems"); 50MODULE_LICENSE("GPL"); 51MODULE_VERSION("3.2"); 52 53#define BIOS_SCAN_LIMIT 0xffffffff 54#define MAX_IMAGE_LENGTH 16 55static struct _rbu_data { 56 void *image_update_buffer; 57 unsigned long image_update_buffer_size; 58 unsigned long bios_image_size; 59 int image_update_ordernum; 60 int dma_alloc; 61 spinlock_t lock; 62 unsigned long packet_read_count; 63 unsigned long num_packets; 64 unsigned long packetsize; 65 unsigned long imagesize; 66 int entry_created; 67} rbu_data; 68 69static char image_type[MAX_IMAGE_LENGTH + 1] = "mono"; 70module_param_string(image_type, image_type, sizeof (image_type), 0); 71MODULE_PARM_DESC(image_type, 72 "BIOS image type. choose- mono or packet or init"); 73 74static unsigned long allocation_floor = 0x100000; 75module_param(allocation_floor, ulong, 0644); 76MODULE_PARM_DESC(allocation_floor, 77 "Minimum address for allocations when using Packet mode"); 78 79struct packet_data { 80 struct list_head list; 81 size_t length; 82 void *data; 83 int ordernum; 84}; 85 86static struct packet_data packet_data_head; 87 88static struct platform_device *rbu_device; 89static int context; 90static dma_addr_t dell_rbu_dmaaddr; 91 92static void init_packet_head(void) 93{ 94 INIT_LIST_HEAD(&packet_data_head.list); 95 rbu_data.packet_read_count = 0; 96 rbu_data.num_packets = 0; 97 rbu_data.packetsize = 0; 98 rbu_data.imagesize = 0; 99} 100 101static int create_packet(void *data, size_t length) 102{ 103 struct packet_data *newpacket; 104 int ordernum = 0; 105 int retval = 0; 106 unsigned int packet_array_size = 0; 107 void **invalid_addr_packet_array = NULL; 108 void *packet_data_temp_buf = NULL; 109 unsigned int idx = 0; 110 111 pr_debug("create_packet: entry \n"); 112 113 if (!rbu_data.packetsize) { 114 pr_debug("create_packet: packetsize not specified\n"); 115 retval = -EINVAL; 116 goto out_noalloc; 117 } 118 119 spin_unlock(&rbu_data.lock); 120 121 newpacket = kzalloc(sizeof (struct packet_data), GFP_KERNEL); 122 123 if (!newpacket) { 124 printk(KERN_WARNING 125 "dell_rbu:%s: failed to allocate new " 126 "packet\n", __FUNCTION__); 127 retval = -ENOMEM; 128 spin_lock(&rbu_data.lock); 129 goto out_noalloc; 130 } 131 132 ordernum = get_order(length); 133 134 /* 135 * BIOS errata mean we cannot allocate packets below 1MB or they will 136 * be overwritten by BIOS. 137 * 138 * array to temporarily hold packets 139 * that are below the allocation floor 140 * 141 * NOTE: very simplistic because we only need the floor to be at 1MB 142 * due to BIOS errata. This shouldn't be used for higher floors 143 * or you will run out of mem trying to allocate the array. 144 */ 145 packet_array_size = max( 146 (unsigned int)(allocation_floor / rbu_data.packetsize), 147 (unsigned int)1); 148 invalid_addr_packet_array = kzalloc(packet_array_size * sizeof(void*), 149 GFP_KERNEL); 150 151 if (!invalid_addr_packet_array) { 152 printk(KERN_WARNING 153 "dell_rbu:%s: failed to allocate " 154 "invalid_addr_packet_array \n", 155 __FUNCTION__); 156 retval = -ENOMEM; 157 spin_lock(&rbu_data.lock); 158 goto out_alloc_packet; 159 } 160 161 while (!packet_data_temp_buf) { 162 packet_data_temp_buf = (unsigned char *) 163 __get_free_pages(GFP_KERNEL, ordernum); 164 if (!packet_data_temp_buf) { 165 printk(KERN_WARNING 166 "dell_rbu:%s: failed to allocate new " 167 "packet\n", __FUNCTION__); 168 retval = -ENOMEM; 169 spin_lock(&rbu_data.lock); 170 goto out_alloc_packet_array; 171 } 172 173 if ((unsigned long)virt_to_phys(packet_data_temp_buf) 174 < allocation_floor) { 175 pr_debug("packet 0x%lx below floor at 0x%lx.\n", 176 (unsigned long)virt_to_phys( 177 packet_data_temp_buf), 178 allocation_floor); 179 invalid_addr_packet_array[idx++] = packet_data_temp_buf; 180 packet_data_temp_buf = NULL; 181 } 182 } 183 spin_lock(&rbu_data.lock); 184 185 newpacket->data = packet_data_temp_buf; 186 187 pr_debug("create_packet: newpacket at physical addr %lx\n", 188 (unsigned long)virt_to_phys(newpacket->data)); 189 190 /* packets may not have fixed size */ 191 newpacket->length = length; 192 newpacket->ordernum = ordernum; 193 ++rbu_data.num_packets; 194 195 /* initialize the newly created packet headers */ 196 INIT_LIST_HEAD(&newpacket->list); 197 list_add_tail(&newpacket->list, &packet_data_head.list); 198 199 memcpy(newpacket->data, data, length); 200 201 pr_debug("create_packet: exit \n"); 202 203out_alloc_packet_array: 204 /* always free packet array */ 205 for (;idx>0;idx--) { 206 pr_debug("freeing unused packet below floor 0x%lx.\n", 207 (unsigned long)virt_to_phys( 208 invalid_addr_packet_array[idx-1])); 209 free_pages((unsigned long)invalid_addr_packet_array[idx-1], 210 ordernum); 211 } 212 kfree(invalid_addr_packet_array); 213 214out_alloc_packet: 215 /* if error, free data */ 216 if (retval) 217 kfree(newpacket); 218 219out_noalloc: 220 return retval; 221} 222 223static int packetize_data(void *data, size_t length) 224{ 225 int rc = 0; 226 int done = 0; 227 int packet_length; 228 u8 *temp; 229 u8 *end = (u8 *) data + length; 230 pr_debug("packetize_data: data length %zd\n", length); 231 if (!rbu_data.packetsize) { 232 printk(KERN_WARNING 233 "dell_rbu: packetsize not specified\n"); 234 return -EIO; 235 } 236 237 temp = (u8 *) data; 238 239 /* packetize the hunk */ 240 while (!done) { 241 if ((temp + rbu_data.packetsize) < end) 242 packet_length = rbu_data.packetsize; 243 else { 244 /* this is the last packet */ 245 packet_length = end - temp; 246 done = 1; 247 } 248 249 if ((rc = create_packet(temp, packet_length))) 250 return rc; 251 252 pr_debug("%p:%td\n", temp, (end - temp)); 253 temp += packet_length; 254 } 255 256 rbu_data.imagesize = length; 257 258 return rc; 259} 260 261static int do_packet_read(char *data, struct list_head *ptemp_list, 262 int length, int bytes_read, int *list_read_count) 263{ 264 void *ptemp_buf; 265 struct packet_data *newpacket = NULL; 266 int bytes_copied = 0; 267 int j = 0; 268 269 newpacket = list_entry(ptemp_list, struct packet_data, list); 270 *list_read_count += newpacket->length; 271 272 if (*list_read_count > bytes_read) { 273 /* point to the start of unread data */ 274 j = newpacket->length - (*list_read_count - bytes_read); 275 /* point to the offset in the packet buffer */ 276 ptemp_buf = (u8 *) newpacket->data + j; 277 /* 278 * check if there is enough room in 279 * * the incoming buffer 280 */ 281 if (length > (*list_read_count - bytes_read)) 282 /* 283 * copy what ever is there in this 284 * packet and move on 285 */ 286 bytes_copied = (*list_read_count - bytes_read); 287 else 288 /* copy the remaining */ 289 bytes_copied = length; 290 memcpy(data, ptemp_buf, bytes_copied); 291 } 292 return bytes_copied; 293} 294 295static int packet_read_list(char *data, size_t * pread_length) 296{ 297 struct list_head *ptemp_list; 298 int temp_count = 0; 299 int bytes_copied = 0; 300 int bytes_read = 0; 301 int remaining_bytes = 0; 302 char *pdest = data; 303 304 /* check if we have any packets */ 305 if (0 == rbu_data.num_packets) 306 return -ENOMEM; 307 308 remaining_bytes = *pread_length; 309 bytes_read = rbu_data.packet_read_count; 310 311 ptemp_list = (&packet_data_head.list)->next; 312 while (!list_empty(ptemp_list)) { 313 bytes_copied = do_packet_read(pdest, ptemp_list, 314 remaining_bytes, bytes_read, &temp_count); 315 remaining_bytes -= bytes_copied; 316 bytes_read += bytes_copied; 317 pdest += bytes_copied; 318 /* 319 * check if we reached end of buffer before reaching the 320 * last packet 321 */ 322 if (remaining_bytes == 0) 323 break; 324 325 ptemp_list = ptemp_list->next; 326 } 327 /*finally set the bytes read */ 328 *pread_length = bytes_read - rbu_data.packet_read_count; 329 rbu_data.packet_read_count = bytes_read; 330 return 0; 331} 332 333static void packet_empty_list(void) 334{ 335 struct list_head *ptemp_list; 336 struct list_head *pnext_list; 337 struct packet_data *newpacket; 338 339 ptemp_list = (&packet_data_head.list)->next; 340 while (!list_empty(ptemp_list)) { 341 newpacket = 342 list_entry(ptemp_list, struct packet_data, list); 343 pnext_list = ptemp_list->next; 344 list_del(ptemp_list); 345 ptemp_list = pnext_list; 346 /* 347 * zero out the RBU packet memory before freeing 348 * to make sure there are no stale RBU packets left in memory 349 */ 350 memset(newpacket->data, 0, rbu_data.packetsize); 351 free_pages((unsigned long) newpacket->data, 352 newpacket->ordernum); 353 kfree(newpacket); 354 } 355 rbu_data.packet_read_count = 0; 356 rbu_data.num_packets = 0; 357 rbu_data.imagesize = 0; 358} 359 360/* 361 * img_update_free: Frees the buffer allocated for storing BIOS image 362 * Always called with lock held and returned with lock held 363 */ 364static void img_update_free(void) 365{ 366 if (!rbu_data.image_update_buffer) 367 return; 368 /* 369 * zero out this buffer before freeing it to get rid of any stale 370 * BIOS image copied in memory. 371 */ 372 memset(rbu_data.image_update_buffer, 0, 373 rbu_data.image_update_buffer_size); 374 if (rbu_data.dma_alloc == 1) 375 dma_free_coherent(NULL, rbu_data.bios_image_size, 376 rbu_data.image_update_buffer, dell_rbu_dmaaddr); 377 else 378 free_pages((unsigned long) rbu_data.image_update_buffer, 379 rbu_data.image_update_ordernum); 380 381 /* 382 * Re-initialize the rbu_data variables after a free 383 */ 384 rbu_data.image_update_ordernum = -1; 385 rbu_data.image_update_buffer = NULL; 386 rbu_data.image_update_buffer_size = 0; 387 rbu_data.bios_image_size = 0; 388 rbu_data.dma_alloc = 0; 389} 390 391/* 392 * img_update_realloc: This function allocates the contiguous pages to 393 * accommodate the requested size of data. The memory address and size 394 * values are stored globally and on every call to this function the new 395 * size is checked to see if more data is required than the existing size. 396 * If true the previous memory is freed and new allocation is done to 397 * accommodate the new size. If the incoming size is less then than the 398 * already allocated size, then that memory is reused. This function is 399 * called with lock held and returns with lock held. 400 */ 401static int img_update_realloc(unsigned long size) 402{ 403 unsigned char *image_update_buffer = NULL; 404 unsigned long rc; 405 unsigned long img_buf_phys_addr; 406 int ordernum; 407 int dma_alloc = 0; 408 409 /* 410 * check if the buffer of sufficient size has been 411 * already allocated 412 */ 413 if (rbu_data.image_update_buffer_size >= size) { 414 /* 415 * check for corruption 416 */ 417 if ((size != 0) && (rbu_data.image_update_buffer == NULL)) { 418 printk(KERN_ERR "dell_rbu:%s: corruption " 419 "check failed\n", __FUNCTION__); 420 return -EINVAL; 421 } 422 /* 423 * we have a valid pre-allocated buffer with 424 * sufficient size 425 */ 426 return 0; 427 } 428 429 /* 430 * free any previously allocated buffer 431 */ 432 img_update_free(); 433 434 spin_unlock(&rbu_data.lock); 435 436 ordernum = get_order(size); 437 image_update_buffer = 438 (unsigned char *) __get_free_pages(GFP_KERNEL, ordernum); 439 440 img_buf_phys_addr = 441 (unsigned long) virt_to_phys(image_update_buffer); 442 443 if (img_buf_phys_addr > BIOS_SCAN_LIMIT) { 444 free_pages((unsigned long) image_update_buffer, ordernum); 445 ordernum = -1; 446 image_update_buffer = dma_alloc_coherent(NULL, size, 447 &dell_rbu_dmaaddr, GFP_KERNEL); 448 dma_alloc = 1; 449 } 450 451 spin_lock(&rbu_data.lock); 452 453 if (image_update_buffer != NULL) { 454 rbu_data.image_update_buffer = image_update_buffer; 455 rbu_data.image_update_buffer_size = size; 456 rbu_data.bios_image_size = 457 rbu_data.image_update_buffer_size; 458 rbu_data.image_update_ordernum = ordernum; 459 rbu_data.dma_alloc = dma_alloc; 460 rc = 0; 461 } else { 462 pr_debug("Not enough memory for image update:" 463 "size = %ld\n", size); 464 rc = -ENOMEM; 465 } 466 467 return rc; 468} 469 470static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count) 471{ 472 int retval; 473 size_t bytes_left; 474 size_t data_length; 475 char *ptempBuf = buffer; 476 477 /* check to see if we have something to return */ 478 if (rbu_data.num_packets == 0) { 479 pr_debug("read_packet_data: no packets written\n"); 480 retval = -ENOMEM; 481 goto read_rbu_data_exit; 482 } 483 484 if (pos > rbu_data.imagesize) { 485 retval = 0; 486 printk(KERN_WARNING "dell_rbu:read_packet_data: " 487 "data underrun\n"); 488 goto read_rbu_data_exit; 489 } 490 491 bytes_left = rbu_data.imagesize - pos; 492 data_length = min(bytes_left, count); 493 494 if ((retval = packet_read_list(ptempBuf, &data_length)) < 0) 495 goto read_rbu_data_exit; 496 497 if ((pos + count) > rbu_data.imagesize) { 498 rbu_data.packet_read_count = 0; 499 /* this was the last copy */ 500 retval = bytes_left; 501 } else 502 retval = count; 503 504 read_rbu_data_exit: 505 return retval; 506} 507 508static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count) 509{ 510 unsigned char *ptemp = NULL; 511 size_t bytes_left = 0; 512 size_t data_length = 0; 513 ssize_t ret_count = 0; 514 515 /* check to see if we have something to return */ 516 if ((rbu_data.image_update_buffer == NULL) || 517 (rbu_data.bios_image_size == 0)) { 518 pr_debug("read_rbu_data_mono: image_update_buffer %p ," 519 "bios_image_size %lu\n", 520 rbu_data.image_update_buffer, 521 rbu_data.bios_image_size); 522 ret_count = -ENOMEM; 523 goto read_rbu_data_exit; 524 } 525 526 if (pos > rbu_data.bios_image_size) { 527 ret_count = 0; 528 goto read_rbu_data_exit; 529 } 530 531 bytes_left = rbu_data.bios_image_size - pos; 532 data_length = min(bytes_left, count); 533 534 ptemp = rbu_data.image_update_buffer; 535 memcpy(buffer, (ptemp + pos), data_length); 536 537 if ((pos + count) > rbu_data.bios_image_size) 538 /* this was the last copy */ 539 ret_count = bytes_left; 540 else 541 ret_count = count; 542 read_rbu_data_exit: 543 return ret_count; 544} 545 546static ssize_t read_rbu_data(struct kobject *kobj, char *buffer, 547 loff_t pos, size_t count) 548{ 549 ssize_t ret_count = 0; 550 551 spin_lock(&rbu_data.lock); 552 553 if (!strcmp(image_type, "mono")) 554 ret_count = read_rbu_mono_data(buffer, pos, count); 555 else if (!strcmp(image_type, "packet")) 556 ret_count = read_packet_data(buffer, pos, count); 557 else 558 pr_debug("read_rbu_data: invalid image type specified\n"); 559 560 spin_unlock(&rbu_data.lock); 561 return ret_count; 562} 563 564static void callbackfn_rbu(const struct firmware *fw, void *context) 565{ 566 rbu_data.entry_created = 0; 567 568 if (!fw || !fw->size) 569 return; 570 571 spin_lock(&rbu_data.lock); 572 if (!strcmp(image_type, "mono")) { 573 if (!img_update_realloc(fw->size)) 574 memcpy(rbu_data.image_update_buffer, 575 fw->data, fw->size); 576 } else if (!strcmp(image_type, "packet")) { 577 /* 578 * we need to free previous packets if a 579 * new hunk of packets needs to be downloaded 580 */ 581 packet_empty_list(); 582 if (packetize_data(fw->data, fw->size)) 583 /* Incase something goes wrong when we are 584 * in middle of packetizing the data, we 585 * need to free up whatever packets might 586 * have been created before we quit. 587 */ 588 packet_empty_list(); 589 } else 590 pr_debug("invalid image type specified.\n"); 591 spin_unlock(&rbu_data.lock); 592} 593 594static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer, 595 loff_t pos, size_t count) 596{ 597 int size = 0; 598 if (!pos) 599 size = sprintf(buffer, "%s\n", image_type); 600 return size; 601} 602 603static ssize_t write_rbu_image_type(struct kobject *kobj, char *buffer, 604 loff_t pos, size_t count) 605{ 606 int rc = count; 607 int req_firm_rc = 0; 608 int i; 609 spin_lock(&rbu_data.lock); 610 /* 611 * Find the first newline or space 612 */ 613 for (i = 0; i < count; ++i) 614 if (buffer[i] == '\n' || buffer[i] == ' ') { 615 buffer[i] = '\0'; 616 break; 617 } 618 if (i == count) 619 buffer[count] = '\0'; 620 621 if (strstr(buffer, "mono")) 622 strcpy(image_type, "mono"); 623 else if (strstr(buffer, "packet")) 624 strcpy(image_type, "packet"); 625 else if (strstr(buffer, "init")) { 626 /* 627 * If due to the user error the driver gets in a bad 628 * state where even though it is loaded , the 629 * /sys/class/firmware/dell_rbu entries are missing. 630 * to cover this situation the user can recreate entries 631 * by writing init to image_type. 632 */ 633 if (!rbu_data.entry_created) { 634 spin_unlock(&rbu_data.lock); 635 req_firm_rc = request_firmware_nowait(THIS_MODULE, 636 FW_ACTION_NOHOTPLUG, "dell_rbu", 637 &rbu_device->dev, &context, 638 callbackfn_rbu); 639 if (req_firm_rc) { 640 printk(KERN_ERR 641 "dell_rbu:%s request_firmware_nowait" 642 " failed %d\n", __FUNCTION__, rc); 643 rc = -EIO; 644 } else 645 rbu_data.entry_created = 1; 646 647 spin_lock(&rbu_data.lock); 648 } 649 } else { 650 printk(KERN_WARNING "dell_rbu: image_type is invalid\n"); 651 spin_unlock(&rbu_data.lock); 652 return -EINVAL; 653 } 654 655 /* we must free all previous allocations */ 656 packet_empty_list(); 657 img_update_free(); 658 spin_unlock(&rbu_data.lock); 659 660 return rc; 661} 662 663static ssize_t read_rbu_packet_size(struct kobject *kobj, char *buffer, 664 loff_t pos, size_t count) 665{ 666 int size = 0; 667 if (!pos) { 668 spin_lock(&rbu_data.lock); 669 size = sprintf(buffer, "%lu\n", rbu_data.packetsize); 670 spin_unlock(&rbu_data.lock); 671 } 672 return size; 673} 674 675static ssize_t write_rbu_packet_size(struct kobject *kobj, char *buffer, 676 loff_t pos, size_t count) 677{ 678 unsigned long temp; 679 spin_lock(&rbu_data.lock); 680 packet_empty_list(); 681 sscanf(buffer, "%lu", &temp); 682 if (temp < 0xffffffff) 683 rbu_data.packetsize = temp; 684 685 spin_unlock(&rbu_data.lock); 686 return count; 687} 688 689static struct bin_attribute rbu_data_attr = { 690 .attr = {.name = "data",.owner = THIS_MODULE,.mode = 0444}, 691 .read = read_rbu_data, 692}; 693 694static struct bin_attribute rbu_image_type_attr = { 695 .attr = {.name = "image_type",.owner = THIS_MODULE,.mode = 0644}, 696 .read = read_rbu_image_type, 697 .write = write_rbu_image_type, 698}; 699 700static struct bin_attribute rbu_packet_size_attr = { 701 .attr = {.name = "packet_size",.owner = THIS_MODULE,.mode = 0644}, 702 .read = read_rbu_packet_size, 703 .write = write_rbu_packet_size, 704}; 705 706static int __init dcdrbu_init(void) 707{ 708 int rc; 709 spin_lock_init(&rbu_data.lock); 710 711 init_packet_head(); 712 rbu_device = platform_device_register_simple("dell_rbu", -1, NULL, 0); 713 if (IS_ERR(rbu_device)) { 714 printk(KERN_ERR 715 "dell_rbu:%s:platform_device_register_simple " 716 "failed\n", __FUNCTION__); 717 return PTR_ERR(rbu_device); 718 } 719 720 rc = sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr); 721 if (rc) 722 goto out_devreg; 723 rc = sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); 724 if (rc) 725 goto out_data; 726 rc = sysfs_create_bin_file(&rbu_device->dev.kobj, 727 &rbu_packet_size_attr); 728 if (rc) 729 goto out_imtype; 730 731 rbu_data.entry_created = 0; 732 return 0; 733 734out_imtype: 735 sysfs_remove_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); 736out_data: 737 sysfs_remove_bin_file(&rbu_device->dev.kobj, &rbu_data_attr); 738out_devreg: 739 platform_device_unregister(rbu_device); 740 return rc; 741} 742 743static __exit void dcdrbu_exit(void) 744{ 745 spin_lock(&rbu_data.lock); 746 packet_empty_list(); 747 img_update_free(); 748 spin_unlock(&rbu_data.lock); 749 platform_device_unregister(rbu_device); 750} 751 752module_exit(dcdrbu_exit); 753module_init(dcdrbu_init); 754 755/* vim:noet:ts=8:sw=8 756*/ 757