📄 via-pmu.c
字号:
struct adb_request req; out_8(&via[B], via[B] | TREQ); /* negate TREQ */ out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask); timeout = 100000; while (!req.complete) { if (--timeout < 0) { printk(KERN_ERR "init_pmu: no response from PMU\n"); return 0; } udelay(10); pmu_poll(); } /* ack all pending interrupts */ timeout = 100000; interrupt_data[0][0] = 1; while (interrupt_data[0][0] || pmu_state != idle) { if (--timeout < 0) { printk(KERN_ERR "init_pmu: timed out acking intrs\n"); return 0; } if (pmu_state == idle) adb_int_pending = 1; via_pmu_interrupt(0, NULL); udelay(10); } /* Tell PMU we are ready. */ if (pmu_kind == PMU_KEYLARGO_BASED) { pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); while (!req.complete) pmu_poll(); } /* Read PMU version */ pmu_request(&req, NULL, 1, PMU_GET_VERSION); pmu_wait_complete(&req); if (req.reply_len > 0) pmu_version = req.reply[0]; /* Read server mode setting */ if (pmu_kind == PMU_KEYLARGO_BASED) { pmu_request(&req, NULL, 2, PMU_POWER_EVENTS, PMU_PWR_GET_POWERUP_EVENTS); pmu_wait_complete(&req); if (req.reply_len == 2) { if (req.reply[1] & PMU_PWR_WAKEUP_AC_INSERT) option_server_mode = 1; printk(KERN_INFO "via-pmu: Server Mode is %s\n", option_server_mode ? "enabled" : "disabled"); } } return 1;}intpmu_get_model(void){ return pmu_kind;}static void pmu_set_server_mode(int server_mode){ struct adb_request req; if (pmu_kind != PMU_KEYLARGO_BASED) return; option_server_mode = server_mode; pmu_request(&req, NULL, 2, PMU_POWER_EVENTS, PMU_PWR_GET_POWERUP_EVENTS); pmu_wait_complete(&req); if (req.reply_len < 2) return; if (server_mode) pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_POWERUP_EVENTS, req.reply[0], PMU_PWR_WAKEUP_AC_INSERT); else pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_POWERUP_EVENTS, req.reply[0], PMU_PWR_WAKEUP_AC_INSERT); pmu_wait_complete(&req);}/* This new version of the code for 2400/3400/3500 powerbooks * is inspired from the implementation in gkrellm-pmu */static voiddone_battery_state_ohare(struct adb_request* req){ /* format: * [0] : flags * 0x01 : AC indicator * 0x02 : charging * 0x04 : battery exist * 0x08 : * 0x10 : * 0x20 : full charged * 0x40 : pcharge reset * 0x80 : battery exist * * [1][2] : battery voltage * [3] : CPU temperature * [4] : battery temperature * [5] : current * [6][7] : pcharge * --tkoba */ unsigned int bat_flags = PMU_BATT_TYPE_HOOPER; long pcharge, charge, vb, vmax, lmax; long vmax_charging, vmax_charged; long amperage, voltage, time, max; int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_MODEL, 0); if (req->reply[0] & 0x01) pmu_power_flags |= PMU_PWR_AC_PRESENT; else pmu_power_flags &= ~PMU_PWR_AC_PRESENT; if (mb == PMAC_TYPE_COMET) { vmax_charged = 189; vmax_charging = 213; lmax = 6500; } else { vmax_charged = 330; vmax_charging = 330; lmax = 6500; } vmax = vmax_charged; /* If battery installed */ if (req->reply[0] & 0x04) { bat_flags |= PMU_BATT_PRESENT; if (req->reply[0] & 0x02) bat_flags |= PMU_BATT_CHARGING; vb = (req->reply[1] << 8) | req->reply[2]; voltage = (vb * 265 + 72665) / 10; amperage = req->reply[5]; if ((req->reply[0] & 0x01) == 0) { if (amperage > 200) vb += ((amperage - 200) * 15)/100; } else if (req->reply[0] & 0x02) { vb = (vb * 97) / 100; vmax = vmax_charging; } charge = (100 * vb) / vmax; if (req->reply[0] & 0x40) { pcharge = (req->reply[6] << 8) + req->reply[7]; if (pcharge > lmax) pcharge = lmax; pcharge *= 100; pcharge = 100 - pcharge / lmax; if (pcharge < charge) charge = pcharge; } if (amperage > 0) time = (charge * 16440) / amperage; else time = 0; max = 100; amperage = -amperage; } else charge = max = amperage = voltage = time = 0; pmu_batteries[pmu_cur_battery].flags = bat_flags; pmu_batteries[pmu_cur_battery].charge = charge; pmu_batteries[pmu_cur_battery].max_charge = max; pmu_batteries[pmu_cur_battery].amperage = amperage; pmu_batteries[pmu_cur_battery].voltage = voltage; pmu_batteries[pmu_cur_battery].time_remaining = time; clear_bit(0, &async_req_locks);}static voiddone_battery_state_smart(struct adb_request* req){ /* format: * [0] : format of this structure (known: 3,4,5) * [1] : flags * * format 3 & 4: * * [2] : charge * [3] : max charge * [4] : current * [5] : voltage * * format 5: * * [2][3] : charge * [4][5] : max charge * [6][7] : current * [8][9] : voltage */ unsigned int bat_flags = PMU_BATT_TYPE_SMART; int amperage; unsigned int capa, max, voltage; if (req->reply[1] & 0x01) pmu_power_flags |= PMU_PWR_AC_PRESENT; else pmu_power_flags &= ~PMU_PWR_AC_PRESENT; capa = max = amperage = voltage = 0; if (req->reply[1] & 0x04) { bat_flags |= PMU_BATT_PRESENT; switch(req->reply[0]) { case 3: case 4: capa = req->reply[2]; max = req->reply[3]; amperage = *((signed char *)&req->reply[4]); voltage = req->reply[5]; break; case 5: capa = (req->reply[2] << 8) | req->reply[3]; max = (req->reply[4] << 8) | req->reply[5]; amperage = *((signed short *)&req->reply[6]); voltage = (req->reply[8] << 8) | req->reply[9]; break; default: printk(KERN_WARNING "pmu.c : unrecognized battery info, len: %d, %02x %02x %02x %02x\n", req->reply_len, req->reply[0], req->reply[1], req->reply[2], req->reply[3]); break; } } if ((req->reply[1] & 0x01) && (amperage > 0)) bat_flags |= PMU_BATT_CHARGING; pmu_batteries[pmu_cur_battery].flags = bat_flags; pmu_batteries[pmu_cur_battery].charge = capa; pmu_batteries[pmu_cur_battery].max_charge = max; pmu_batteries[pmu_cur_battery].amperage = amperage; pmu_batteries[pmu_cur_battery].voltage = voltage; if (amperage) { if ((req->reply[1] & 0x01) && (amperage > 0)) pmu_batteries[pmu_cur_battery].time_remaining = ((max-capa) * 3600) / amperage; else pmu_batteries[pmu_cur_battery].time_remaining = (capa * 3600) / (-amperage); } else pmu_batteries[pmu_cur_battery].time_remaining = 0; pmu_cur_battery = (pmu_cur_battery + 1) % pmu_battery_count; clear_bit(0, &async_req_locks);}static voidquery_battery_state(void){ if (test_and_set_bit(0, &async_req_locks)) return; if (pmu_kind == PMU_OHARE_BASED) pmu_request(&batt_req, done_battery_state_ohare, 1, PMU_BATTERY_STATE); else pmu_request(&batt_req, done_battery_state_smart, 2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1);}static intproc_get_info(char *page, char **start, off_t off, int count, int *eof, void *data){ char* p = page; p += sprintf(p, "PMU driver version : %d\n", PMU_DRIVER_VERSION); p += sprintf(p, "PMU firmware version : %02x\n", pmu_version); p += sprintf(p, "AC Power : %d\n", ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0) || pmu_battery_count == 0); p += sprintf(p, "Battery count : %d\n", pmu_battery_count); return p - page;}static intproc_get_irqstats(char *page, char **start, off_t off, int count, int *eof, void *data){ int i; char* p = page; static const char *irq_names[] = { "Total CB1 triggered events", "Total GPIO1 triggered events", "PC-Card eject button", "Sound/Brightness button", "ADB message", "Battery state change", "Environment interrupt", "Tick timer", "Ghost interrupt (zero len)", "Empty interrupt (empty mask)", "Max irqs in a row" }; for (i=0; i<11; i++) { p += sprintf(p, " %2u: %10u (%s)\n", i, pmu_irq_stats[i], irq_names[i]); } return p - page;}static intproc_get_batt(char *page, char **start, off_t off, int count, int *eof, void *data){ long batnum = (long)data; char *p = page; p += sprintf(p, "\n"); p += sprintf(p, "flags : %08x\n", pmu_batteries[batnum].flags); p += sprintf(p, "charge : %d\n", pmu_batteries[batnum].charge); p += sprintf(p, "max_charge : %d\n", pmu_batteries[batnum].max_charge); p += sprintf(p, "current : %d\n", pmu_batteries[batnum].amperage); p += sprintf(p, "voltage : %d\n", pmu_batteries[batnum].voltage); p += sprintf(p, "time rem. : %d\n", pmu_batteries[batnum].time_remaining); return p - page;}static intproc_read_options(char *page, char **start, off_t off, int count, int *eof, void *data){ char *p = page;#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32) if (pmu_kind == PMU_KEYLARGO_BASED && pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup);#endif if (pmu_kind == PMU_KEYLARGO_BASED) p += sprintf(p, "server_mode=%d\n", option_server_mode); return p - page;} static intproc_write_options(struct file *file, const char __user *buffer, unsigned long count, void *data){ char tmp[33]; char *label, *val; unsigned long fcount = count; if (!count) return -EINVAL; if (count > 32) count = 32; if (copy_from_user(tmp, buffer, count)) return -EFAULT; tmp[count] = 0; label = tmp; while(*label == ' ') label++; val = label; while(*val && (*val != '=')) { if (*val == ' ') *val = 0; val++; } if ((*val) == 0) return -EINVAL; *(val++) = 0; while(*val == ' ') val++;#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32) if (pmu_kind == PMU_KEYLARGO_BASED && pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) if (!strcmp(label, "lid_wakeup")) option_lid_wakeup = ((*val) == '1');#endif if (pmu_kind == PMU_KEYLARGO_BASED && !strcmp(label, "server_mode")) { int new_value; new_value = ((*val) == '1'); if (new_value != option_server_mode) pmu_set_server_mode(new_value); } return fcount;}#ifdef CONFIG_ADB/* Send an ADB command */static intpmu_send_request(struct adb_request *req, int sync){ int i, ret; if ((vias == NULL) || (!pmu_fully_inited)) { req->complete = 1; return -ENXIO; } ret = -EINVAL; switch (req->data[0]) { case PMU_PACKET: for (i = 0; i < req->nbytes - 1; ++i) req->data[i] = req->data[i+1]; --req->nbytes; if (pmu_data_len[req->data[0]][1] != 0) { req->reply[0] = ADB_RET_OK; req->reply_len = 1; } else req->reply_len = 0; ret = pmu_queue_request(req); break; case CUDA_PACKET: switch (req->data[1]) { case CUDA_GET_TIME: if (req->nbytes != 2) break; req->data[0] = PMU_READ_RTC; req->nbytes = 1; req->reply_len = 3; req->reply[0] = CUDA_PACKET; req->reply[1] = 0; req->reply[2] = CUDA_GET_TIME; ret = pmu_queue_request(req); break; case CUDA_SET_TIME: if (req->nbytes != 6) break; req->data[0] = PMU_SET_RTC; req->nbytes = 5; for (i = 1; i <= 4; ++i) req->data[i] = req->data[i+1]; req->reply_len = 3; req->reply[0] = CUDA_PACKET; req->reply[1] = 0; req->reply[2] = CUDA_SET_TIME; ret = pmu_queue_request(req); break; } break; case ADB_PACKET: if (!pmu_has_adb) return -ENXIO; for (i = req->nbytes - 1; i > 1; --i) req->data[i+2] = req->data[i]; req->data[3] = req->nbytes - 2; req->data[2] = pmu_adb_flags; /*req->data[1] = req->data[1];*/ req->data[0] = PMU_ADB_CMD; req->nbytes += 2; req->reply_expected = 1; req->reply_len = 0; ret = pmu_queue_request(req); break; } if (ret) { req->complete = 1; return ret; } if (sync) while (!req->complete) pmu_poll(); return 0;}/* Enable/disable autopolling */static intpmu_adb_autopoll(int devs){ struct adb_request req; if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb) return -ENXIO; if (devs) { adb_dev_map = devs; pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86, adb_dev_map >> 8, adb_dev_map); pmu_adb_flags = 2; } else { pmu_request(&req, NULL, 1, PMU_ADB_POLL_OFF); pmu_adb_flags = 0; } while (!req.complete) pmu_poll(); return 0;}/* Reset the ADB bus */static intpmu_adb_reset_bus(void){ struct adb_request req; int save_autopoll = adb_dev_map; if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb) return -ENXIO; /* anyone got a better idea?? */ pmu_adb_autopoll(0); req.nbytes = 5; req.done = NULL; req.data[0] = PMU_ADB_CMD; req.data[1] = 0; req.data[2] = ADB_BUSRESET; req.data[3] = 0; req.data[4] = 0; req.reply_len = 0; req.reply_expected = 1; if (pmu_queue_request(&req) != 0) { printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n"); return -EIO; } pmu_wait_complete(&req); if (save_autopoll != 0) pmu_adb_autopoll(save_autopoll); return 0;}#endif /* CONFIG_ADB */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -