0001
0002
0003
0004
0005
0006 #include <linux/types.h>
0007 #include <linux/module.h>
0008 #include <linux/init.h>
0009 #include <linux/linkage.h>
0010 #include <linux/kernel.h>
0011 #include <linux/device.h>
0012 #include <linux/pnp.h>
0013 #include <linux/mm.h>
0014 #include <linux/smp.h>
0015 #include <linux/kmod.h>
0016 #include <linux/completion.h>
0017 #include <linux/spinlock.h>
0018
0019 #include <asm/page.h>
0020 #include <asm/desc.h>
0021 #include <asm/byteorder.h>
0022
0023 #include "pnpbios.h"
0024
0025 __visible struct {
0026 u16 offset;
0027 u16 segment;
0028 } pnp_bios_callpoint;
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041 asmlinkage __visible void pnp_bios_callfunc(void);
0042
0043 __asm__(".text \n"
0044 __ALIGN_STR "\n"
0045 ".globl pnp_bios_callfunc\n"
0046 "pnp_bios_callfunc:\n"
0047 " pushl %edx \n"
0048 " pushl %ecx \n"
0049 " pushl %ebx \n"
0050 " pushl %eax \n"
0051 " lcallw *pnp_bios_callpoint\n"
0052 " addl $16, %esp \n"
0053 " lret \n"
0054 ".previous \n");
0055
0056 #define Q2_SET_SEL(cpu, selname, address, size) \
0057 do { \
0058 struct desc_struct *gdt = get_cpu_gdt_rw((cpu)); \
0059 set_desc_base(&gdt[(selname) >> 3], (u32)(address)); \
0060 set_desc_limit(&gdt[(selname) >> 3], (size) - 1); \
0061 } while(0)
0062
0063 static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092,
0064 (unsigned long)__va(0x400UL), PAGE_SIZE - 0x400 - 1);
0065
0066
0067
0068
0069
0070
0071 __visible u32 pnp_bios_fault_esp;
0072 __visible u32 pnp_bios_fault_eip;
0073 __visible u32 pnp_bios_is_utter_crap = 0;
0074
0075 static DEFINE_SPINLOCK(pnp_bios_lock);
0076
0077
0078
0079
0080
0081 static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
0082 u16 arg4, u16 arg5, u16 arg6, u16 arg7,
0083 void *ts1_base, u32 ts1_size,
0084 void *ts2_base, u32 ts2_size)
0085 {
0086 unsigned long flags;
0087 u16 status;
0088 struct desc_struct save_desc_40;
0089 int cpu;
0090
0091
0092
0093
0094
0095 if (pnp_bios_is_utter_crap)
0096 return PNP_FUNCTION_NOT_SUPPORTED;
0097
0098 cpu = get_cpu();
0099 save_desc_40 = get_cpu_gdt_rw(cpu)[0x40 / 8];
0100 get_cpu_gdt_rw(cpu)[0x40 / 8] = bad_bios_desc;
0101
0102
0103 spin_lock_irqsave(&pnp_bios_lock, flags);
0104
0105
0106 if (ts1_size)
0107 Q2_SET_SEL(smp_processor_id(), PNP_TS1, ts1_base, ts1_size);
0108 if (ts2_size)
0109 Q2_SET_SEL(smp_processor_id(), PNP_TS2, ts2_base, ts2_size);
0110
0111 __asm__ __volatile__("pushl %%ebp\n\t"
0112 "pushl %%edi\n\t"
0113 "pushl %%esi\n\t"
0114 "pushl %%ds\n\t"
0115 "pushl %%es\n\t"
0116 "pushl %%fs\n\t"
0117 "pushl %%gs\n\t"
0118 "pushfl\n\t"
0119 "movl %%esp, pnp_bios_fault_esp\n\t"
0120 "movl $1f, pnp_bios_fault_eip\n\t"
0121 "lcall %5,%6\n\t"
0122 "1:popfl\n\t"
0123 "popl %%gs\n\t"
0124 "popl %%fs\n\t"
0125 "popl %%es\n\t"
0126 "popl %%ds\n\t"
0127 "popl %%esi\n\t"
0128 "popl %%edi\n\t"
0129 "popl %%ebp\n\t":"=a"(status)
0130 :"0"((func) | (((u32) arg1) << 16)),
0131 "b"((arg2) | (((u32) arg3) << 16)),
0132 "c"((arg4) | (((u32) arg5) << 16)),
0133 "d"((arg6) | (((u32) arg7) << 16)),
0134 "i"(PNP_CS32), "i"(0)
0135 :"memory");
0136 spin_unlock_irqrestore(&pnp_bios_lock, flags);
0137
0138 get_cpu_gdt_rw(cpu)[0x40 / 8] = save_desc_40;
0139 put_cpu();
0140
0141
0142 if (pnp_bios_is_utter_crap) {
0143 printk(KERN_ERR
0144 "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue\n");
0145 printk(KERN_ERR
0146 "PnPBIOS: You may need to reboot with the \"pnpbios=off\" option to operate stably\n");
0147 printk(KERN_ERR
0148 "PnPBIOS: Check with your vendor for an updated BIOS\n");
0149 }
0150
0151 return status;
0152 }
0153
0154 void pnpbios_print_status(const char *module, u16 status)
0155 {
0156 switch (status) {
0157 case PNP_SUCCESS:
0158 printk(KERN_ERR "PnPBIOS: %s: function successful\n", module);
0159 break;
0160 case PNP_NOT_SET_STATICALLY:
0161 printk(KERN_ERR "PnPBIOS: %s: unable to set static resources\n",
0162 module);
0163 break;
0164 case PNP_UNKNOWN_FUNCTION:
0165 printk(KERN_ERR "PnPBIOS: %s: invalid function number passed\n",
0166 module);
0167 break;
0168 case PNP_FUNCTION_NOT_SUPPORTED:
0169 printk(KERN_ERR
0170 "PnPBIOS: %s: function not supported on this system\n",
0171 module);
0172 break;
0173 case PNP_INVALID_HANDLE:
0174 printk(KERN_ERR "PnPBIOS: %s: invalid handle\n", module);
0175 break;
0176 case PNP_BAD_PARAMETER:
0177 printk(KERN_ERR "PnPBIOS: %s: invalid parameters were passed\n",
0178 module);
0179 break;
0180 case PNP_SET_FAILED:
0181 printk(KERN_ERR "PnPBIOS: %s: unable to set resources\n",
0182 module);
0183 break;
0184 case PNP_EVENTS_NOT_PENDING:
0185 printk(KERN_ERR "PnPBIOS: %s: no events are pending\n", module);
0186 break;
0187 case PNP_SYSTEM_NOT_DOCKED:
0188 printk(KERN_ERR "PnPBIOS: %s: the system is not docked\n",
0189 module);
0190 break;
0191 case PNP_NO_ISA_PNP_CARDS:
0192 printk(KERN_ERR
0193 "PnPBIOS: %s: no isapnp cards are installed on this system\n",
0194 module);
0195 break;
0196 case PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES:
0197 printk(KERN_ERR
0198 "PnPBIOS: %s: cannot determine the capabilities of the docking station\n",
0199 module);
0200 break;
0201 case PNP_CONFIG_CHANGE_FAILED_NO_BATTERY:
0202 printk(KERN_ERR
0203 "PnPBIOS: %s: unable to undock, the system does not have a battery\n",
0204 module);
0205 break;
0206 case PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT:
0207 printk(KERN_ERR
0208 "PnPBIOS: %s: could not dock due to resource conflicts\n",
0209 module);
0210 break;
0211 case PNP_BUFFER_TOO_SMALL:
0212 printk(KERN_ERR "PnPBIOS: %s: the buffer passed is too small\n",
0213 module);
0214 break;
0215 case PNP_USE_ESCD_SUPPORT:
0216 printk(KERN_ERR "PnPBIOS: %s: use ESCD instead\n", module);
0217 break;
0218 case PNP_MESSAGE_NOT_SUPPORTED:
0219 printk(KERN_ERR "PnPBIOS: %s: the message is unsupported\n",
0220 module);
0221 break;
0222 case PNP_HARDWARE_ERROR:
0223 printk(KERN_ERR "PnPBIOS: %s: a hardware failure has occurred\n",
0224 module);
0225 break;
0226 default:
0227 printk(KERN_ERR "PnPBIOS: %s: unexpected status 0x%x\n", module,
0228 status);
0229 break;
0230 }
0231 }
0232
0233
0234
0235
0236
0237 #define PNP_GET_NUM_SYS_DEV_NODES 0x00
0238 #define PNP_GET_SYS_DEV_NODE 0x01
0239 #define PNP_SET_SYS_DEV_NODE 0x02
0240 #define PNP_GET_EVENT 0x03
0241 #define PNP_SEND_MESSAGE 0x04
0242 #define PNP_GET_DOCKING_STATION_INFORMATION 0x05
0243 #define PNP_SET_STATIC_ALLOCED_RES_INFO 0x09
0244 #define PNP_GET_STATIC_ALLOCED_RES_INFO 0x0a
0245 #define PNP_GET_APM_ID_TABLE 0x0b
0246 #define PNP_GET_PNP_ISA_CONFIG_STRUC 0x40
0247 #define PNP_GET_ESCD_INFO 0x41
0248 #define PNP_READ_ESCD 0x42
0249 #define PNP_WRITE_ESCD 0x43
0250
0251
0252
0253
0254 static int __pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
0255 {
0256 u16 status;
0257
0258 if (!pnp_bios_present())
0259 return PNP_FUNCTION_NOT_SUPPORTED;
0260 status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2,
0261 PNP_TS1, PNP_DS, 0, 0, data,
0262 sizeof(struct pnp_dev_node_info), NULL, 0);
0263 data->no_nodes &= 0xff;
0264 return status;
0265 }
0266
0267 int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
0268 {
0269 int status = __pnp_bios_dev_node_info(data);
0270
0271 if (status)
0272 pnpbios_print_status("dev_node_info", status);
0273 return status;
0274 }
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290 static int __pnp_bios_get_dev_node(u8 *nodenum, char boot,
0291 struct pnp_bios_node *data)
0292 {
0293 u16 status;
0294 u16 tmp_nodenum;
0295
0296 if (!pnp_bios_present())
0297 return PNP_FUNCTION_NOT_SUPPORTED;
0298 if (!boot && pnpbios_dont_use_current_config)
0299 return PNP_FUNCTION_NOT_SUPPORTED;
0300 tmp_nodenum = *nodenum;
0301 status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2,
0302 boot ? 2 : 1, PNP_DS, 0, &tmp_nodenum,
0303 sizeof(tmp_nodenum), data, 65536);
0304 *nodenum = tmp_nodenum;
0305 return status;
0306 }
0307
0308 int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
0309 {
0310 int status;
0311
0312 status = __pnp_bios_get_dev_node(nodenum, boot, data);
0313 if (status)
0314 pnpbios_print_status("get_dev_node", status);
0315 return status;
0316 }
0317
0318
0319
0320
0321
0322
0323
0324 static int __pnp_bios_set_dev_node(u8 nodenum, char boot,
0325 struct pnp_bios_node *data)
0326 {
0327 u16 status;
0328
0329 if (!pnp_bios_present())
0330 return PNP_FUNCTION_NOT_SUPPORTED;
0331 if (!boot && pnpbios_dont_use_current_config)
0332 return PNP_FUNCTION_NOT_SUPPORTED;
0333 status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1,
0334 boot ? 2 : 1, PNP_DS, 0, 0, data, 65536, NULL,
0335 0);
0336 return status;
0337 }
0338
0339 int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
0340 {
0341 int status;
0342
0343 status = __pnp_bios_set_dev_node(nodenum, boot, data);
0344 if (status) {
0345 pnpbios_print_status("set_dev_node", status);
0346 return status;
0347 }
0348 if (!boot) {
0349 status = pnp_bios_get_dev_node(&nodenum, boot, data);
0350 if (status)
0351 return status;
0352 }
0353 return status;
0354 }
0355
0356
0357
0358
0359 int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
0360 {
0361 u16 status;
0362
0363 if (!pnp_bios_present())
0364 return PNP_FUNCTION_NOT_SUPPORTED;
0365 status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1,
0366 PNP_DS, 0, 0, 0, 0, data,
0367 sizeof(struct pnp_docking_station_info), NULL,
0368 0);
0369 return status;
0370 }
0371
0372
0373
0374
0375
0376 static int __pnp_bios_get_stat_res(char *info)
0377 {
0378 u16 status;
0379
0380 if (!pnp_bios_present())
0381 return PNP_FUNCTION_NOT_SUPPORTED;
0382 status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1,
0383 PNP_DS, 0, 0, 0, 0, info, 65536, NULL, 0);
0384 return status;
0385 }
0386
0387 int pnp_bios_get_stat_res(char *info)
0388 {
0389 int status;
0390
0391 status = __pnp_bios_get_stat_res(info);
0392 if (status)
0393 pnpbios_print_status("get_stat_res", status);
0394 return status;
0395 }
0396
0397
0398
0399
0400 static int __pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
0401 {
0402 u16 status;
0403
0404 if (!pnp_bios_present())
0405 return PNP_FUNCTION_NOT_SUPPORTED;
0406 status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS,
0407 0, 0, 0, 0, data,
0408 sizeof(struct pnp_isa_config_struc), NULL, 0);
0409 return status;
0410 }
0411
0412 int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
0413 {
0414 int status;
0415
0416 status = __pnp_bios_isapnp_config(data);
0417 if (status)
0418 pnpbios_print_status("isapnp_config", status);
0419 return status;
0420 }
0421
0422
0423
0424
0425 static int __pnp_bios_escd_info(struct escd_info_struc *data)
0426 {
0427 u16 status;
0428
0429 if (!pnp_bios_present())
0430 return ESCD_FUNCTION_NOT_SUPPORTED;
0431 status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4,
0432 PNP_TS1, PNP_DS, data,
0433 sizeof(struct escd_info_struc), NULL, 0);
0434 return status;
0435 }
0436
0437 int pnp_bios_escd_info(struct escd_info_struc *data)
0438 {
0439 int status;
0440
0441 status = __pnp_bios_escd_info(data);
0442 if (status)
0443 pnpbios_print_status("escd_info", status);
0444 return status;
0445 }
0446
0447
0448
0449
0450
0451 static int __pnp_bios_read_escd(char *data, u32 nvram_base)
0452 {
0453 u16 status;
0454
0455 if (!pnp_bios_present())
0456 return ESCD_FUNCTION_NOT_SUPPORTED;
0457 status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0,
0458 0, data, 65536, __va(nvram_base), 65536);
0459 return status;
0460 }
0461
0462 int pnp_bios_read_escd(char *data, u32 nvram_base)
0463 {
0464 int status;
0465
0466 status = __pnp_bios_read_escd(data, nvram_base);
0467 if (status)
0468 pnpbios_print_status("read_escd", status);
0469 return status;
0470 }
0471
0472 void pnpbios_calls_init(union pnp_bios_install_struct *header)
0473 {
0474 int i;
0475
0476 pnp_bios_callpoint.offset = header->fields.pm16offset;
0477 pnp_bios_callpoint.segment = PNP_CS16;
0478
0479 for_each_possible_cpu(i) {
0480 struct desc_struct *gdt = get_cpu_gdt_rw(i);
0481 if (!gdt)
0482 continue;
0483 set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_CS32],
0484 (unsigned long)&pnp_bios_callfunc);
0485 set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_CS16],
0486 (unsigned long)__va(header->fields.pm16cseg));
0487 set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_DS],
0488 (unsigned long)__va(header->fields.pm16dseg));
0489 }
0490 }