📄 via-pmu.c
字号:
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, 0, 0); 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); while (!req.complete) pmu_poll(); if (req.reply_len > 0) pmu_version = req.reply[0]; return 1;}intpmu_get_model(void){ return pmu_kind;}#ifdef CONFIG_PMAC_PBOOK/* * WARNING ! This code probably needs some debugging... -- BenH. */static void __pmacdone_battery_state_ohare(struct adb_request* req){ unsigned int bat_flags = 0; int current = 0; unsigned int capa, max, voltage, time; int lrange[] = { 0, 275, 850, 1680, 2325, 2765, 3160, 3500, 3830, 4115, 4360, 4585, 4795, 4990, 5170, 5340, 5510, 5710, 5930, 6150, 6370, 6500 }; if (req->reply[0] & 0x01) pmu_power_flags |= PMU_PWR_AC_PRESENT; else pmu_power_flags &= ~PMU_PWR_AC_PRESENT; if (req->reply[0] & 0x04) { int vb, i, j, charge, pcharge; bat_flags |= PMU_BATT_PRESENT; vb = (req->reply[1] << 8) | req->reply[2]; voltage = ((vb * 2650) + 726650)/100; current = *((signed char *)&req->reply[5]); if ((req->reply[0] & 0x01) == 0 && (current > 200)) vb += (current - 200) * 15; else if (req->reply[0] & 0x02) vb = (vb - 10) * 100; i = (33000 - vb) / 10; j = i - (i % 100); if (j <= 0) charge = 0; else if (j >= 21) charge = 650000; else charge = (lrange[j + 1] - lrange[j]) * (i - j) + (lrange[j] * 100); charge = (1000 - charge / 650) / 10; if (req->reply[0] & 0x40) { pcharge = (req->reply[6] << 8) + req->reply[7]; if (pcharge > 6500) pcharge = 6500; pcharge *= 100; pcharge = (1000 - pcharge / 650) / 10; if (pcharge < charge) charge = pcharge; } capa = charge; max = 100; time = (charge * 274) / current; current = -current; } else capa = max = current = voltage = time = 0; if ((req->reply[0] & 0x02) && (current > 0)) bat_flags |= PMU_BATT_CHARGING; if (req->reply[0] & 0x04) /* CHECK THIS ONE */ bat_flags |= PMU_BATT_PRESENT; 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].current = current; pmu_batteries[pmu_cur_battery].voltage = voltage; pmu_batteries[pmu_cur_battery].time_remaining = time;}static void __pmacdone_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 = 0; int current; 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; 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]; current = *((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]; current = *((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; } } else capa = max = current = voltage = 0; if ((req->reply[1] & 0x01) && (current > 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].current = current; pmu_batteries[pmu_cur_battery].voltage = voltage; if (current) { if ((req->reply[1] & 0x01) && (current > 0)) pmu_batteries[pmu_cur_battery].time_remaining = ((max-capa) * 3600) / current; else pmu_batteries[pmu_cur_battery].time_remaining = (capa * 3600) / (-current); } else pmu_batteries[pmu_cur_battery].time_remaining = 0; pmu_cur_battery = (pmu_cur_battery + 1) % pmu_battery_count;}static void __pmacquery_battery_state(void){ if (!batt_req.complete) 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);}#endif /* CONFIG_PMAC_PBOOK */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);#ifdef CONFIG_PMAC_PBOOK p += sprintf(p, "AC Power : %d\n", ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0)); p += sprintf(p, "Battery count : %d\n", pmu_battery_count);#endif /* CONFIG_PMAC_PBOOK */ return p - page;}#ifdef CONFIG_PMAC_PBOOKstatic intproc_get_batt(char *page, char **start, off_t off, int count, int *eof, void *data){ int batnum = (int)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].current); 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;}#endif /* CONFIG_PMAC_PBOOK */static intproc_read_options(char *page, char **start, off_t off, int count, int *eof, void *data){ char *p = page;#ifdef CONFIG_PMAC_PBOOK if (pmu_kind == PMU_KEYLARGO_BASED && can_sleep) p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup);#endif /* CONFIG_PMAC_PBOOK */ return p - page;} static intproc_write_options(struct file *file, const char *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++;#ifdef CONFIG_PMAC_PBOOK if (pmu_kind == PMU_KEYLARGO_BASED && can_sleep) if (!strcmp(label, "lid_wakeup")) option_lid_wakeup = ((*val) == '1');#endif /* CONFIG_PMAC_PBOOK */ return fcount;}#ifdef CONFIG_ADB/* Send an ADB command */static int __openfirmwarepmu_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 int __openfirmwarepmu_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 int __openfirmwarepmu_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; } while (!req.complete) pmu_poll(); if (save_autopoll != 0) pmu_adb_autopoll(save_autopoll); return 0;}#endif /* CONFIG_ADB *//* Construct and send a pmu request */int __openfirmwarepmu_request(struct adb_request *req, void (*done)(struct adb_request *), int nbytes, ...){ va_list list; int i; if (vias == NULL) return -ENXIO; if (nbytes < 0 || nbytes > 32) { printk(KERN_ERR "pmu_request: bad nbytes (%d)\n", nbytes); req->complete = 1; return -EINVAL; } req->nbytes = nbytes; req->done = done; va_start(list, nbytes); for (i = 0; i < nbytes; ++i) req->data[i] = va_arg(list, int); va_end(list); req->reply_len = 0; req->reply_expected = 0; return pmu_queue_request(req);}int __openfirmwarepmu_queue_request(struct adb_request *req){ unsigned long flags; int nsend; if (via == NULL) { req->complete = 1; return -ENXIO; } if (req->nbytes <= 0) { req->complete = 1; return 0; } nsend = pmu_data_len[req->data[0]][0]; if (nsend >= 0 && req->nbytes != nsend + 1) { req->complete = 1; return -EINVAL; } req->next = 0; req->sent = 0; req->complete = 0; spin_lock_irqsave(&pmu_lock, flags); if (current_req != 0) { last_req->next = req; last_req = req; } else { current_req = req; last_req = req; if (pmu_state == idle) pmu_start(); } spin_unlock_irqrestore(&pmu_lock, flags); return 0;}static void __openfirmwarewait_for_ack(void){ /* Sightly increased the delay, I had one occurence of the message * reported */ int timeout = 4000; while ((in_8(&via[B]) & TACK) == 0) { if (--timeout < 0) { printk(KERN_ERR "PMU not responding (!ack)\n"); return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -