Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/olof/chrome-platform

Pull chrome platform cleanups and improvements from Olof Johansson:
- Use deferred probing on Chrome OS platforms for the i2c device
registration. This fixes a long-standing race of initialization of
touchpad/screen on Chromebooks.
- Added in platform device registration for pstore console on supported
hardware
- Misc smaller fixes (__initdata, module exit cleanup, etc)

* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/olof/chrome-platform:
platform/chrome: unregister platform driver/device when module exit
platform/chrome: Make i2c_adapter_names static
platform/chrome: chromeos_laptop - fix incorrect placement of __initdata tag
platform/chrome: chromeos_laptop - Use deferred probing
platform/chrome: chromeos_laptop - Restructure device associations
platform/chrome: Add pstore platform_device

+338 -106
+14
drivers/platform/chrome/Kconfig
··· 25 25 If you have a supported Chromebook, choose Y or M here. 26 26 The module will be called chromeos_laptop. 27 27 28 + config CHROMEOS_PSTORE 29 + tristate "Chrome OS pstore support" 30 + ---help--- 31 + This module instantiates the persistent storage on x86 ChromeOS 32 + devices. It can be used to store away console logs and crash 33 + information across reboots. 34 + 35 + The range of memory used is 0xf00000-0x1000000, traditionally 36 + the memory used to back VGA controller memory. 37 + 38 + If you have a supported Chromebook, choose Y or M here. 39 + The module will be called chromeos_pstore. 40 + 41 + 28 42 endif # CHROMEOS_PLATFORMS
+1
drivers/platform/chrome/Makefile
··· 1 1 2 2 obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o 3 + obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o
+222 -106
drivers/platform/chrome/chromeos_laptop.c
··· 27 27 #include <linux/input.h> 28 28 #include <linux/interrupt.h> 29 29 #include <linux/module.h> 30 + #include <linux/platform_device.h> 30 31 31 32 #define ATMEL_TP_I2C_ADDR 0x4b 32 33 #define ATMEL_TP_I2C_BL_ADDR 0x25 ··· 41 40 static struct i2c_client *tp; 42 41 static struct i2c_client *ts; 43 42 44 - const char *i2c_adapter_names[] = { 43 + static const char *i2c_adapter_names[] = { 45 44 "SMBus I801 adapter", 46 45 "i915 gmbus vga", 47 46 "i915 gmbus panel", ··· 54 53 I2C_ADAPTER_PANEL, 55 54 }; 56 55 57 - static struct i2c_board_info __initdata cyapa_device = { 56 + struct i2c_peripheral { 57 + int (*add)(enum i2c_adapter_type type); 58 + enum i2c_adapter_type type; 59 + }; 60 + 61 + #define MAX_I2C_PERIPHERALS 3 62 + 63 + struct chromeos_laptop { 64 + struct i2c_peripheral i2c_peripherals[MAX_I2C_PERIPHERALS]; 65 + }; 66 + 67 + static struct chromeos_laptop *cros_laptop; 68 + 69 + static struct i2c_board_info cyapa_device = { 58 70 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), 59 71 .flags = I2C_CLIENT_WAKE, 60 72 }; 61 73 62 - static struct i2c_board_info __initdata isl_als_device = { 74 + static struct i2c_board_info isl_als_device = { 63 75 I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR), 64 76 }; 65 77 66 - static struct i2c_board_info __initdata tsl2583_als_device = { 78 + static struct i2c_board_info tsl2583_als_device = { 67 79 I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR), 68 80 }; 69 81 70 - static struct i2c_board_info __initdata tsl2563_als_device = { 82 + static struct i2c_board_info tsl2563_als_device = { 71 83 I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR), 72 84 }; 73 85 ··· 103 89 .config_length = 0, 104 90 }; 105 91 106 - static struct i2c_board_info __initdata atmel_224s_tp_device = { 92 + static struct i2c_board_info atmel_224s_tp_device = { 107 93 I2C_BOARD_INFO("atmel_mxt_tp", ATMEL_TP_I2C_ADDR), 108 94 .platform_data = &atmel_224s_tp_platform_data, 109 95 .flags = I2C_CLIENT_WAKE, ··· 124 110 .config_length = 0, 125 111 }; 126 112 127 - static struct i2c_board_info __initdata atmel_1664s_device = { 113 + static struct i2c_board_info atmel_1664s_device = { 128 114 I2C_BOARD_INFO("atmel_mxt_ts", ATMEL_TS_I2C_ADDR), 129 115 .platform_data = &atmel_1664s_platform_data, 130 116 .flags = I2C_CLIENT_WAKE, 131 117 }; 132 118 133 - static struct i2c_client __init *__add_probed_i2c_device( 119 + static struct i2c_client *__add_probed_i2c_device( 134 120 const char *name, 135 121 int bus, 136 122 struct i2c_board_info *info, ··· 183 169 return client; 184 170 } 185 171 186 - static int __init __find_i2c_adap(struct device *dev, void *data) 172 + static int __find_i2c_adap(struct device *dev, void *data) 187 173 { 188 174 const char *name = data; 189 175 static const char *prefix = "i2c-"; ··· 194 180 return (strncmp(adapter->name, name, strlen(name)) == 0); 195 181 } 196 182 197 - static int __init find_i2c_adapter_num(enum i2c_adapter_type type) 183 + static int find_i2c_adapter_num(enum i2c_adapter_type type) 198 184 { 199 185 struct device *dev = NULL; 200 186 struct i2c_adapter *adapter; ··· 203 189 dev = bus_find_device(&i2c_bus_type, NULL, (void *)name, 204 190 __find_i2c_adap); 205 191 if (!dev) { 206 - pr_err("%s: i2c adapter %s not found on system.\n", __func__, 207 - name); 192 + /* Adapters may appear later. Deferred probing will retry */ 193 + pr_notice("%s: i2c adapter %s not found on system.\n", __func__, 194 + name); 208 195 return -ENODEV; 209 196 } 210 197 adapter = to_i2c_adapter(dev); ··· 220 205 * Returns NULL if no devices found. 221 206 * See Documentation/i2c/instantiating-devices for more information. 222 207 */ 223 - static __init struct i2c_client *add_probed_i2c_device( 208 + static struct i2c_client *add_probed_i2c_device( 224 209 const char *name, 225 210 enum i2c_adapter_type type, 226 211 struct i2c_board_info *info, ··· 237 222 * info->addr. 238 223 * Returns NULL if no device found. 239 224 */ 240 - static __init struct i2c_client *add_i2c_device(const char *name, 225 + static struct i2c_client *add_i2c_device(const char *name, 241 226 enum i2c_adapter_type type, 242 227 struct i2c_board_info *info) 243 228 { ··· 248 233 addr_list); 249 234 } 250 235 251 - 252 - static struct i2c_client __init *add_smbus_device(const char *name, 253 - struct i2c_board_info *info) 236 + static int setup_cyapa_tp(enum i2c_adapter_type type) 254 237 { 255 - return add_i2c_device(name, I2C_ADAPTER_SMBUS, info); 238 + if (tp) 239 + return 0; 240 + 241 + /* add cyapa touchpad */ 242 + tp = add_i2c_device("trackpad", type, &cyapa_device); 243 + return (!tp) ? -EAGAIN : 0; 256 244 } 257 245 258 - static int __init setup_cyapa_smbus_tp(const struct dmi_system_id *id) 259 - { 260 - /* add cyapa touchpad on smbus */ 261 - tp = add_smbus_device("trackpad", &cyapa_device); 262 - return 0; 263 - } 264 - 265 - static int __init setup_atmel_224s_tp(const struct dmi_system_id *id) 246 + static int setup_atmel_224s_tp(enum i2c_adapter_type type) 266 247 { 267 248 const unsigned short addr_list[] = { ATMEL_TP_I2C_BL_ADDR, 268 249 ATMEL_TP_I2C_ADDR, 269 250 I2C_CLIENT_END }; 251 + if (tp) 252 + return 0; 270 253 271 - /* add atmel mxt touchpad on VGA DDC GMBus */ 272 - tp = add_probed_i2c_device("trackpad", I2C_ADAPTER_VGADDC, 254 + /* add atmel mxt touchpad */ 255 + tp = add_probed_i2c_device("trackpad", type, 273 256 &atmel_224s_tp_device, addr_list); 274 - return 0; 257 + return (!tp) ? -EAGAIN : 0; 275 258 } 276 259 277 - static int __init setup_atmel_1664s_ts(const struct dmi_system_id *id) 260 + static int setup_atmel_1664s_ts(enum i2c_adapter_type type) 278 261 { 279 262 const unsigned short addr_list[] = { ATMEL_TS_I2C_BL_ADDR, 280 263 ATMEL_TS_I2C_ADDR, 281 264 I2C_CLIENT_END }; 265 + if (ts) 266 + return 0; 282 267 283 - /* add atmel mxt touch device on PANEL GMBus */ 284 - ts = add_probed_i2c_device("touchscreen", I2C_ADAPTER_PANEL, 268 + /* add atmel mxt touch device */ 269 + ts = add_probed_i2c_device("touchscreen", type, 285 270 &atmel_1664s_device, addr_list); 286 - return 0; 271 + return (!ts) ? -EAGAIN : 0; 287 272 } 288 273 289 - 290 - static int __init setup_isl29018_als(const struct dmi_system_id *id) 274 + static int setup_isl29018_als(enum i2c_adapter_type type) 291 275 { 276 + if (als) 277 + return 0; 278 + 292 279 /* add isl29018 light sensor */ 293 - als = add_smbus_device("lightsensor", &isl_als_device); 294 - return 0; 280 + als = add_i2c_device("lightsensor", type, &isl_als_device); 281 + return (!als) ? -EAGAIN : 0; 295 282 } 296 283 297 - static int __init setup_isl29023_als(const struct dmi_system_id *id) 284 + static int setup_tsl2583_als(enum i2c_adapter_type type) 298 285 { 299 - /* add isl29023 light sensor on Panel GMBus */ 300 - als = add_i2c_device("lightsensor", I2C_ADAPTER_PANEL, 301 - &isl_als_device); 302 - return 0; 286 + if (als) 287 + return 0; 288 + 289 + /* add tsl2583 light sensor */ 290 + als = add_i2c_device(NULL, type, &tsl2583_als_device); 291 + return (!als) ? -EAGAIN : 0; 303 292 } 304 293 305 - static int __init setup_tsl2583_als(const struct dmi_system_id *id) 294 + static int setup_tsl2563_als(enum i2c_adapter_type type) 306 295 { 307 - /* add tsl2583 light sensor on smbus */ 308 - als = add_smbus_device(NULL, &tsl2583_als_device); 309 - return 0; 296 + if (als) 297 + return 0; 298 + 299 + /* add tsl2563 light sensor */ 300 + als = add_i2c_device(NULL, type, &tsl2563_als_device); 301 + return (!als) ? -EAGAIN : 0; 310 302 } 311 303 312 - static int __init setup_tsl2563_als(const struct dmi_system_id *id) 304 + static int __init chromeos_laptop_dmi_matched(const struct dmi_system_id *id) 313 305 { 314 - /* add tsl2563 light sensor on smbus */ 315 - als = add_smbus_device(NULL, &tsl2563_als_device); 316 - return 0; 306 + cros_laptop = (void *)id->driver_data; 307 + pr_debug("DMI Matched %s.\n", id->ident); 308 + 309 + /* Indicate to dmi_scan that processing is done. */ 310 + return 1; 317 311 } 318 312 319 - static struct dmi_system_id __initdata chromeos_laptop_dmi_table[] = { 313 + static int chromeos_laptop_probe(struct platform_device *pdev) 314 + { 315 + int i; 316 + int ret = 0; 317 + 318 + for (i = 0; i < MAX_I2C_PERIPHERALS; i++) { 319 + struct i2c_peripheral *i2c_dev; 320 + 321 + i2c_dev = &cros_laptop->i2c_peripherals[i]; 322 + 323 + /* No more peripherals. */ 324 + if (i2c_dev->add == NULL) 325 + break; 326 + 327 + /* Add the device. Set -EPROBE_DEFER on any failure */ 328 + if (i2c_dev->add(i2c_dev->type)) 329 + ret = -EPROBE_DEFER; 330 + } 331 + 332 + return ret; 333 + } 334 + 335 + static struct chromeos_laptop samsung_series_5_550 = { 336 + .i2c_peripherals = { 337 + /* Touchpad. */ 338 + { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, 339 + /* Light Sensor. */ 340 + { .add = setup_isl29018_als, I2C_ADAPTER_SMBUS }, 341 + }, 342 + }; 343 + 344 + static struct chromeos_laptop samsung_series_5 = { 345 + .i2c_peripherals = { 346 + /* Light Sensor. */ 347 + { .add = setup_tsl2583_als, I2C_ADAPTER_SMBUS }, 348 + }, 349 + }; 350 + 351 + static struct chromeos_laptop chromebook_pixel = { 352 + .i2c_peripherals = { 353 + /* Touch Screen. */ 354 + { .add = setup_atmel_1664s_ts, I2C_ADAPTER_PANEL }, 355 + /* Touchpad. */ 356 + { .add = setup_atmel_224s_tp, I2C_ADAPTER_VGADDC }, 357 + /* Light Sensor. */ 358 + { .add = setup_isl29018_als, I2C_ADAPTER_PANEL }, 359 + }, 360 + }; 361 + 362 + static struct chromeos_laptop acer_c7_chromebook = { 363 + .i2c_peripherals = { 364 + /* Touchpad. */ 365 + { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, 366 + }, 367 + }; 368 + 369 + static struct chromeos_laptop acer_ac700 = { 370 + .i2c_peripherals = { 371 + /* Light Sensor. */ 372 + { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS }, 373 + }, 374 + }; 375 + 376 + static struct chromeos_laptop hp_pavilion_14_chromebook = { 377 + .i2c_peripherals = { 378 + /* Touchpad. */ 379 + { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, 380 + }, 381 + }; 382 + 383 + static struct chromeos_laptop cr48 = { 384 + .i2c_peripherals = { 385 + /* Light Sensor. */ 386 + { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS }, 387 + }, 388 + }; 389 + 390 + #define _CBDD(board_) \ 391 + .callback = chromeos_laptop_dmi_matched, \ 392 + .driver_data = (void *)&board_ 393 + 394 + static struct dmi_system_id chromeos_laptop_dmi_table[] __initdata = { 320 395 { 321 - .ident = "Samsung Series 5 550 - Touchpad", 396 + .ident = "Samsung Series 5 550", 322 397 .matches = { 323 398 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"), 324 399 DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"), 325 400 }, 326 - .callback = setup_cyapa_smbus_tp, 401 + _CBDD(samsung_series_5_550), 327 402 }, 328 403 { 329 - .ident = "Chromebook Pixel - Touchscreen", 330 - .matches = { 331 - DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), 332 - DMI_MATCH(DMI_PRODUCT_NAME, "Link"), 333 - }, 334 - .callback = setup_atmel_1664s_ts, 335 - }, 336 - { 337 - .ident = "Chromebook Pixel - Touchpad", 338 - .matches = { 339 - DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), 340 - DMI_MATCH(DMI_PRODUCT_NAME, "Link"), 341 - }, 342 - .callback = setup_atmel_224s_tp, 343 - }, 344 - { 345 - .ident = "Samsung Series 5 550 - Light Sensor", 346 - .matches = { 347 - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"), 348 - DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"), 349 - }, 350 - .callback = setup_isl29018_als, 351 - }, 352 - { 353 - .ident = "Chromebook Pixel - Light Sensor", 354 - .matches = { 355 - DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), 356 - DMI_MATCH(DMI_PRODUCT_NAME, "Link"), 357 - }, 358 - .callback = setup_isl29023_als, 359 - }, 360 - { 361 - .ident = "Acer C7 Chromebook - Touchpad", 362 - .matches = { 363 - DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"), 364 - }, 365 - .callback = setup_cyapa_smbus_tp, 366 - }, 367 - { 368 - .ident = "HP Pavilion 14 Chromebook - Touchpad", 369 - .matches = { 370 - DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"), 371 - }, 372 - .callback = setup_cyapa_smbus_tp, 373 - }, 374 - { 375 - .ident = "Samsung Series 5 - Light Sensor", 404 + .ident = "Samsung Series 5", 376 405 .matches = { 377 406 DMI_MATCH(DMI_PRODUCT_NAME, "Alex"), 378 407 }, 379 - .callback = setup_tsl2583_als, 408 + _CBDD(samsung_series_5), 380 409 }, 381 410 { 382 - .ident = "Cr-48 - Light Sensor", 411 + .ident = "Chromebook Pixel", 383 412 .matches = { 384 - DMI_MATCH(DMI_PRODUCT_NAME, "Mario"), 413 + DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), 414 + DMI_MATCH(DMI_PRODUCT_NAME, "Link"), 385 415 }, 386 - .callback = setup_tsl2563_als, 416 + _CBDD(chromebook_pixel), 387 417 }, 388 418 { 389 - .ident = "Acer AC700 - Light Sensor", 419 + .ident = "Acer C7 Chromebook", 420 + .matches = { 421 + DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"), 422 + }, 423 + _CBDD(acer_c7_chromebook), 424 + }, 425 + { 426 + .ident = "Acer AC700", 390 427 .matches = { 391 428 DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"), 392 429 }, 393 - .callback = setup_tsl2563_als, 430 + _CBDD(acer_ac700), 431 + }, 432 + { 433 + .ident = "HP Pavilion 14 Chromebook", 434 + .matches = { 435 + DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"), 436 + }, 437 + _CBDD(hp_pavilion_14_chromebook), 438 + }, 439 + { 440 + .ident = "Cr-48", 441 + .matches = { 442 + DMI_MATCH(DMI_PRODUCT_NAME, "Mario"), 443 + }, 444 + _CBDD(cr48), 394 445 }, 395 446 { } 396 447 }; 397 448 MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table); 398 449 450 + static struct platform_device *cros_platform_device; 451 + 452 + static struct platform_driver cros_platform_driver = { 453 + .driver = { 454 + .name = "chromeos_laptop", 455 + .owner = THIS_MODULE, 456 + }, 457 + .probe = chromeos_laptop_probe, 458 + }; 459 + 399 460 static int __init chromeos_laptop_init(void) 400 461 { 462 + int ret; 401 463 if (!dmi_check_system(chromeos_laptop_dmi_table)) { 402 464 pr_debug("%s unsupported system.\n", __func__); 403 465 return -ENODEV; 404 466 } 467 + 468 + ret = platform_driver_register(&cros_platform_driver); 469 + if (ret) 470 + return ret; 471 + 472 + cros_platform_device = platform_device_alloc("chromeos_laptop", -1); 473 + if (!cros_platform_device) { 474 + ret = -ENOMEM; 475 + goto fail_platform_device1; 476 + } 477 + 478 + ret = platform_device_add(cros_platform_device); 479 + if (ret) 480 + goto fail_platform_device2; 481 + 405 482 return 0; 483 + 484 + fail_platform_device2: 485 + platform_device_put(cros_platform_device); 486 + fail_platform_device1: 487 + platform_driver_unregister(&cros_platform_driver); 488 + return ret; 406 489 } 407 490 408 491 static void __exit chromeos_laptop_exit(void) ··· 511 398 i2c_unregister_device(tp); 512 399 if (ts) 513 400 i2c_unregister_device(ts); 401 + 402 + platform_device_unregister(cros_platform_device); 403 + platform_driver_unregister(&cros_platform_driver); 514 404 } 515 405 516 406 module_init(chromeos_laptop_init);
+101
drivers/platform/chrome/chromeos_pstore.c
··· 1 + /* 2 + * chromeos_pstore.c - Driver to instantiate Chromebook ramoops device 3 + * 4 + * Copyright (C) 2013 Google, Inc. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation, version 2 of the License. 9 + */ 10 + 11 + #include <linux/dmi.h> 12 + #include <linux/module.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/pstore_ram.h> 15 + 16 + static struct dmi_system_id chromeos_pstore_dmi_table[] __initdata = { 17 + { 18 + /* 19 + * Today all Chromebooks/boxes ship with GOOGLE as vendor and 20 + * coreboot as bios vendor. No other systems with this 21 + * combination are known to date. 22 + */ 23 + .matches = { 24 + DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), 25 + DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"), 26 + }, 27 + }, 28 + { 29 + /* 30 + * The first Samsung Chromebox and Chromebook Series 5 550 use 31 + * coreboot but with Samsung as the system vendor. 32 + */ 33 + .matches = { 34 + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"), 35 + DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"), 36 + }, 37 + }, 38 + { 39 + /* x86-alex, the first Samsung Chromebook. */ 40 + .matches = { 41 + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 42 + DMI_MATCH(DMI_PRODUCT_NAME, "Alex"), 43 + }, 44 + }, 45 + { 46 + /* x86-mario, the Cr-48 pilot device from Google. */ 47 + .matches = { 48 + DMI_MATCH(DMI_SYS_VENDOR, "IEC"), 49 + DMI_MATCH(DMI_PRODUCT_NAME, "Mario"), 50 + }, 51 + }, 52 + { 53 + /* x86-zgb, the first Acer Chromebook. */ 54 + .matches = { 55 + DMI_MATCH(DMI_SYS_VENDOR, "ACER"), 56 + DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"), 57 + }, 58 + }, 59 + { } 60 + }; 61 + MODULE_DEVICE_TABLE(dmi, chromeos_pstore_dmi_table); 62 + 63 + /* 64 + * On x86 chromebooks/boxes, the firmware will keep the legacy VGA memory 65 + * range untouched across reboots, so we use that to store our pstore 66 + * contents for panic logs, etc. 67 + */ 68 + static struct ramoops_platform_data chromeos_ramoops_data = { 69 + .mem_size = 0x100000, 70 + .mem_address = 0xf00000, 71 + .record_size = 0x20000, 72 + .console_size = 0x20000, 73 + .ftrace_size = 0x20000, 74 + .dump_oops = 1, 75 + }; 76 + 77 + static struct platform_device chromeos_ramoops = { 78 + .name = "ramoops", 79 + .dev = { 80 + .platform_data = &chromeos_ramoops_data, 81 + }, 82 + }; 83 + 84 + static int __init chromeos_pstore_init(void) 85 + { 86 + if (dmi_check_system(chromeos_pstore_dmi_table)) 87 + return platform_device_register(&chromeos_ramoops); 88 + 89 + return -ENODEV; 90 + } 91 + 92 + static void __exit chromeos_pstore_exit(void) 93 + { 94 + platform_device_unregister(&chromeos_ramoops); 95 + } 96 + 97 + module_init(chromeos_pstore_init); 98 + module_exit(chromeos_pstore_exit); 99 + 100 + MODULE_DESCRIPTION("Chrome OS pstore module"); 101 + MODULE_LICENSE("GPL");