1*658d439bSTaku Izumi /* 2*658d439bSTaku Izumi * FUJITSU Extended Socket Network Device driver 3*658d439bSTaku Izumi * Copyright (c) 2015 FUJITSU LIMITED 4*658d439bSTaku Izumi * 5*658d439bSTaku Izumi * This program is free software; you can redistribute it and/or modify it 6*658d439bSTaku Izumi * under the terms and conditions of the GNU General Public License, 7*658d439bSTaku Izumi * version 2, as published by the Free Software Foundation. 8*658d439bSTaku Izumi * 9*658d439bSTaku Izumi * This program is distributed in the hope it will be useful, but WITHOUT 10*658d439bSTaku Izumi * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11*658d439bSTaku Izumi * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12*658d439bSTaku Izumi * more details. 13*658d439bSTaku Izumi * 14*658d439bSTaku Izumi * You should have received a copy of the GNU General Public License along with 15*658d439bSTaku Izumi * this program; if not, see <http://www.gnu.org/licenses/>. 16*658d439bSTaku Izumi * 17*658d439bSTaku Izumi * The full GNU General Public License is included in this distribution in 18*658d439bSTaku Izumi * the file called "COPYING". 19*658d439bSTaku Izumi * 20*658d439bSTaku Izumi */ 21*658d439bSTaku Izumi 22*658d439bSTaku Izumi #include <linux/module.h> 23*658d439bSTaku Izumi #include <linux/types.h> 24*658d439bSTaku Izumi #include <linux/nls.h> 25*658d439bSTaku Izumi #include <linux/platform_device.h> 26*658d439bSTaku Izumi 27*658d439bSTaku Izumi #include "fjes.h" 28*658d439bSTaku Izumi 29*658d439bSTaku Izumi #define MAJ 1 30*658d439bSTaku Izumi #define MIN 0 31*658d439bSTaku Izumi #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) 32*658d439bSTaku Izumi #define DRV_NAME "fjes" 33*658d439bSTaku Izumi char fjes_driver_name[] = DRV_NAME; 34*658d439bSTaku Izumi char fjes_driver_version[] = DRV_VERSION; 35*658d439bSTaku Izumi static const char fjes_driver_string[] = 36*658d439bSTaku Izumi "FUJITSU Extended Socket Network Device Driver"; 37*658d439bSTaku Izumi static const char fjes_copyright[] = 38*658d439bSTaku Izumi "Copyright (c) 2015 FUJITSU LIMITED"; 39*658d439bSTaku Izumi 40*658d439bSTaku Izumi MODULE_AUTHOR("Taku Izumi <izumi.taku@jp.fujitsu.com>"); 41*658d439bSTaku Izumi MODULE_DESCRIPTION("FUJITSU Extended Socket Network Device Driver"); 42*658d439bSTaku Izumi MODULE_LICENSE("GPL"); 43*658d439bSTaku Izumi MODULE_VERSION(DRV_VERSION); 44*658d439bSTaku Izumi 45*658d439bSTaku Izumi static int fjes_acpi_add(struct acpi_device *); 46*658d439bSTaku Izumi static int fjes_acpi_remove(struct acpi_device *); 47*658d439bSTaku Izumi static acpi_status fjes_get_acpi_resource(struct acpi_resource *, void*); 48*658d439bSTaku Izumi 49*658d439bSTaku Izumi static int fjes_probe(struct platform_device *); 50*658d439bSTaku Izumi static int fjes_remove(struct platform_device *); 51*658d439bSTaku Izumi 52*658d439bSTaku Izumi static const struct acpi_device_id fjes_acpi_ids[] = { 53*658d439bSTaku Izumi {"PNP0C02", 0}, 54*658d439bSTaku Izumi {"", 0}, 55*658d439bSTaku Izumi }; 56*658d439bSTaku Izumi MODULE_DEVICE_TABLE(acpi, fjes_acpi_ids); 57*658d439bSTaku Izumi 58*658d439bSTaku Izumi static struct acpi_driver fjes_acpi_driver = { 59*658d439bSTaku Izumi .name = DRV_NAME, 60*658d439bSTaku Izumi .class = DRV_NAME, 61*658d439bSTaku Izumi .owner = THIS_MODULE, 62*658d439bSTaku Izumi .ids = fjes_acpi_ids, 63*658d439bSTaku Izumi .ops = { 64*658d439bSTaku Izumi .add = fjes_acpi_add, 65*658d439bSTaku Izumi .remove = fjes_acpi_remove, 66*658d439bSTaku Izumi }, 67*658d439bSTaku Izumi }; 68*658d439bSTaku Izumi 69*658d439bSTaku Izumi static struct platform_driver fjes_driver = { 70*658d439bSTaku Izumi .driver = { 71*658d439bSTaku Izumi .name = DRV_NAME, 72*658d439bSTaku Izumi .owner = THIS_MODULE, 73*658d439bSTaku Izumi }, 74*658d439bSTaku Izumi .probe = fjes_probe, 75*658d439bSTaku Izumi .remove = fjes_remove, 76*658d439bSTaku Izumi }; 77*658d439bSTaku Izumi 78*658d439bSTaku Izumi static struct resource fjes_resource[] = { 79*658d439bSTaku Izumi { 80*658d439bSTaku Izumi .flags = IORESOURCE_MEM, 81*658d439bSTaku Izumi .start = 0, 82*658d439bSTaku Izumi .end = 0, 83*658d439bSTaku Izumi }, 84*658d439bSTaku Izumi { 85*658d439bSTaku Izumi .flags = IORESOURCE_IRQ, 86*658d439bSTaku Izumi .start = 0, 87*658d439bSTaku Izumi .end = 0, 88*658d439bSTaku Izumi }, 89*658d439bSTaku Izumi }; 90*658d439bSTaku Izumi 91*658d439bSTaku Izumi static int fjes_acpi_add(struct acpi_device *device) 92*658d439bSTaku Izumi { 93*658d439bSTaku Izumi struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; 94*658d439bSTaku Izumi char str_buf[sizeof(FJES_ACPI_SYMBOL) + 1]; 95*658d439bSTaku Izumi struct platform_device *plat_dev; 96*658d439bSTaku Izumi union acpi_object *str; 97*658d439bSTaku Izumi acpi_status status; 98*658d439bSTaku Izumi int result; 99*658d439bSTaku Izumi 100*658d439bSTaku Izumi status = acpi_evaluate_object(device->handle, "_STR", NULL, &buffer); 101*658d439bSTaku Izumi if (ACPI_FAILURE(status)) 102*658d439bSTaku Izumi return -ENODEV; 103*658d439bSTaku Izumi 104*658d439bSTaku Izumi str = buffer.pointer; 105*658d439bSTaku Izumi result = utf16s_to_utf8s((wchar_t *)str->string.pointer, 106*658d439bSTaku Izumi str->string.length, UTF16_LITTLE_ENDIAN, 107*658d439bSTaku Izumi str_buf, sizeof(str_buf) - 1); 108*658d439bSTaku Izumi str_buf[result] = 0; 109*658d439bSTaku Izumi 110*658d439bSTaku Izumi if (strncmp(FJES_ACPI_SYMBOL, str_buf, strlen(FJES_ACPI_SYMBOL)) != 0) { 111*658d439bSTaku Izumi kfree(buffer.pointer); 112*658d439bSTaku Izumi return -ENODEV; 113*658d439bSTaku Izumi } 114*658d439bSTaku Izumi kfree(buffer.pointer); 115*658d439bSTaku Izumi 116*658d439bSTaku Izumi status = acpi_walk_resources(device->handle, METHOD_NAME__CRS, 117*658d439bSTaku Izumi fjes_get_acpi_resource, fjes_resource); 118*658d439bSTaku Izumi if (ACPI_FAILURE(status)) 119*658d439bSTaku Izumi return -ENODEV; 120*658d439bSTaku Izumi 121*658d439bSTaku Izumi /* create platform_device */ 122*658d439bSTaku Izumi plat_dev = platform_device_register_simple(DRV_NAME, 0, fjes_resource, 123*658d439bSTaku Izumi ARRAY_SIZE(fjes_resource)); 124*658d439bSTaku Izumi device->driver_data = plat_dev; 125*658d439bSTaku Izumi 126*658d439bSTaku Izumi return 0; 127*658d439bSTaku Izumi } 128*658d439bSTaku Izumi 129*658d439bSTaku Izumi static int fjes_acpi_remove(struct acpi_device *device) 130*658d439bSTaku Izumi { 131*658d439bSTaku Izumi struct platform_device *plat_dev; 132*658d439bSTaku Izumi 133*658d439bSTaku Izumi plat_dev = (struct platform_device *)acpi_driver_data(device); 134*658d439bSTaku Izumi platform_device_unregister(plat_dev); 135*658d439bSTaku Izumi 136*658d439bSTaku Izumi return 0; 137*658d439bSTaku Izumi } 138*658d439bSTaku Izumi 139*658d439bSTaku Izumi static acpi_status 140*658d439bSTaku Izumi fjes_get_acpi_resource(struct acpi_resource *acpi_res, void *data) 141*658d439bSTaku Izumi { 142*658d439bSTaku Izumi struct acpi_resource_address32 *addr; 143*658d439bSTaku Izumi struct acpi_resource_irq *irq; 144*658d439bSTaku Izumi struct resource *res = data; 145*658d439bSTaku Izumi 146*658d439bSTaku Izumi switch (acpi_res->type) { 147*658d439bSTaku Izumi case ACPI_RESOURCE_TYPE_ADDRESS32: 148*658d439bSTaku Izumi addr = &acpi_res->data.address32; 149*658d439bSTaku Izumi res[0].start = addr->address.minimum; 150*658d439bSTaku Izumi res[0].end = addr->address.minimum + 151*658d439bSTaku Izumi addr->address.address_length - 1; 152*658d439bSTaku Izumi break; 153*658d439bSTaku Izumi 154*658d439bSTaku Izumi case ACPI_RESOURCE_TYPE_IRQ: 155*658d439bSTaku Izumi irq = &acpi_res->data.irq; 156*658d439bSTaku Izumi if (irq->interrupt_count != 1) 157*658d439bSTaku Izumi return AE_ERROR; 158*658d439bSTaku Izumi res[1].start = irq->interrupts[0]; 159*658d439bSTaku Izumi res[1].end = irq->interrupts[0]; 160*658d439bSTaku Izumi break; 161*658d439bSTaku Izumi 162*658d439bSTaku Izumi default: 163*658d439bSTaku Izumi break; 164*658d439bSTaku Izumi } 165*658d439bSTaku Izumi 166*658d439bSTaku Izumi return AE_OK; 167*658d439bSTaku Izumi } 168*658d439bSTaku Izumi 169*658d439bSTaku Izumi /* fjes_probe - Device Initialization Routine */ 170*658d439bSTaku Izumi static int fjes_probe(struct platform_device *plat_dev) 171*658d439bSTaku Izumi { 172*658d439bSTaku Izumi return 0; 173*658d439bSTaku Izumi } 174*658d439bSTaku Izumi 175*658d439bSTaku Izumi /* fjes_remove - Device Removal Routine */ 176*658d439bSTaku Izumi static int fjes_remove(struct platform_device *plat_dev) 177*658d439bSTaku Izumi { 178*658d439bSTaku Izumi return 0; 179*658d439bSTaku Izumi } 180*658d439bSTaku Izumi 181*658d439bSTaku Izumi /* fjes_init_module - Driver Registration Routine */ 182*658d439bSTaku Izumi static int __init fjes_init_module(void) 183*658d439bSTaku Izumi { 184*658d439bSTaku Izumi int result; 185*658d439bSTaku Izumi 186*658d439bSTaku Izumi pr_info("%s - version %s - %s\n", 187*658d439bSTaku Izumi fjes_driver_string, fjes_driver_version, fjes_copyright); 188*658d439bSTaku Izumi 189*658d439bSTaku Izumi result = platform_driver_register(&fjes_driver); 190*658d439bSTaku Izumi if (result < 0) 191*658d439bSTaku Izumi return result; 192*658d439bSTaku Izumi 193*658d439bSTaku Izumi result = acpi_bus_register_driver(&fjes_acpi_driver); 194*658d439bSTaku Izumi if (result < 0) 195*658d439bSTaku Izumi goto fail_acpi_driver; 196*658d439bSTaku Izumi 197*658d439bSTaku Izumi return 0; 198*658d439bSTaku Izumi 199*658d439bSTaku Izumi fail_acpi_driver: 200*658d439bSTaku Izumi platform_driver_unregister(&fjes_driver); 201*658d439bSTaku Izumi return result; 202*658d439bSTaku Izumi } 203*658d439bSTaku Izumi 204*658d439bSTaku Izumi module_init(fjes_init_module); 205*658d439bSTaku Izumi 206*658d439bSTaku Izumi /* fjes_exit_module - Driver Exit Cleanup Routine */ 207*658d439bSTaku Izumi static void __exit fjes_exit_module(void) 208*658d439bSTaku Izumi { 209*658d439bSTaku Izumi acpi_bus_unregister_driver(&fjes_acpi_driver); 210*658d439bSTaku Izumi platform_driver_unregister(&fjes_driver); 211*658d439bSTaku Izumi } 212*658d439bSTaku Izumi 213*658d439bSTaku Izumi module_exit(fjes_exit_module); 214