#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <fcntl.h> #include <signal.h> #include <linux/moto_accy.h> #include <linux/power_ic.h> #include <linux/ezxusbd.h> #include <linux/apm_bios.h> // battery voltage enum { VOLTAGE_MIN, VOLTAGE_405 = VOLTAGE_MIN, VOLTAGE_410, VOLTAGE_415, VOLTAGE_420, VOLTAGE_425, VOLTAGE_430, VOLTAGE_380, VOLTAGE_450, VOLTAGE_MAX = VOLTAGE_450 }; // charger current enum { CURRENT_MIN, CURRENT_0 = CURRENT_MIN, CURRENT_100, CURRENT_200, CURRENT_300, CURRENT_400, CURRENT_500, CURRENT_600, CURRENT_700, CURRENT_800, CURRENT_900, CURRENT_1000, CURRENT_1100, CURRENT_1200, CURRENT_1300, CURRENT_1800, CURRENT_MAX }; // control fds int apm,usb,accy,power; // TODO: config bool usb_charge = false; bool charging; // motorola 2.4 kernel charge current and voltage setting int set_charge_current(int current) { return ioctl(power,POWER_IC_IOCTL_CHARGER_SET_CHARGE_CURRENT,current); } int set_charge_voltage(int voltage) { return ioctl(power,POWER_IC_IOCTL_CHARGER_SET_CHARGE_VOLTAGE,voltage); } int battery() { POWER_IC_ATOD_REQUEST_BATT_AND_CURR_T info; info.timing = 0; ioctl (power,POWER_IC_IOCTL_ATOD_BATT_AND_CURR,&info); return info.batt_result; } void charge_alarm(int sig); void charger(int current, int voltage) { int ret; ret = set_charge_current(current); printf("current set: %d, ret: %d\n",current,ret); set_charge_voltage(voltage); printf("voltage set: %d, ret: %d\n",voltage,ret); if (current) { int flag = open("/tmp/charging", O_CREAT); close(flag); alarm(30); signal(SIGALRM, charge_alarm); charging = true; } else { unlink("/tmp/charging"); charging = false; } } // usb mode switching void usb_mode(int mode) { ioctl(usb,MOTUSBD_IOCTL_SET_USBMODE,&mode); } void plug_cable(int type) { switch (type) { case MOTO_ACCY_TYPE_CHARGER_MID: printf("charger attached\n"); charger(CURRENT_1300,VOLTAGE_425); break; case MOTO_ACCY_TYPE_CABLE_USB: printf("usb cable attached\n"); if (usb_charge) charger(CURRENT_200,VOLTAGE_425); usb_mode(USB_STATUS_NET); break; case MOTO_ACCY_TYPE_HEADSET_MONO: case MOTO_ACCY_TYPE_HEADSET_STEREO: case MOTO_ACCY_TYPE_HEADSET_EMU_MONO: case MOTO_ACCY_TYPE_HEADSET_EMU_STEREO: printf("headset attached %d\n",type); break; default: printf("attached cable %d\n",type); } } void unplug_cable(int type) { switch (type) { case MOTO_ACCY_TYPE_CHARGER_MID: printf("charger detached\n"); charger(CURRENT_0,VOLTAGE_MIN); break; case MOTO_ACCY_TYPE_CABLE_USB: printf("usb cable detached\n"); if (usb_charge) charger(CURRENT_0,VOLTAGE_MIN); usb_mode(0); break; case MOTO_ACCY_TYPE_HEADSET_MONO: case MOTO_ACCY_TYPE_HEADSET_STEREO: case MOTO_ACCY_TYPE_HEADSET_EMU_MONO: case MOTO_ACCY_TYPE_HEADSET_EMU_STEREO: printf("headset detached %d\n",type); break; default: printf("detached cable %d\n",type); } } void charge_alarm(int sig) { int b = battery(); printf("d: %d %d\n", charging, b ); if ( charging && ( b > 709 ) ) { charger(0,0); } else if ( charging && ( b > 700 ) ) { alarm(10); printf("no-no\n"); } else { printf("no..\n"); alarm(30); } } void battery_update(int sig) { printf("hauuuu...\n"); int fd = open("/tmp/battery",O_CREAT | O_RDWR ); char b[4]; sprintf(b,"%d",battery() ); write(fd,&b,4); close(fd); } int main(int argc, char *argv[]) { //if ( fork() ) // return; int pid = open("/var/run/motod.pid",O_CREAT | O_RDWR | O_TRUNC); char cpid[11]; int n = sprintf(cpid,"%d",(int)getpid() ); write(pid,&cpid,n); close(pid); //freopen("/var/log/motod", "w", stdout); fd_set devs, devs_back; usb = open("/dev/motusbd", O_RDWR); apm = open("/dev/apm_bios", O_RDWR); accy = open("/dev/accy", O_RDWR); power = open("/dev/power_ic", O_RDWR); if (usb < 0) { printf("cant open usb\n"); return 1; } if (apm < 0) { printf("cant open apm\n"); return 1; } if (accy < 0) { printf("cant open accy\n"); return 1; } if (power < 0){ printf("cant open power\n"); return 1; } battery_update(0); signal(SIGUSR1,battery_update); FD_ZERO(&devs); //FD_SET(usb, &devs); FD_SET(apm, &devs); FD_SET(accy, &devs); FD_SET(power,&devs); unsigned short event[40]; memset(event,0,sizeof(event)); apm_event_t *apm_event; devs_back = devs; n = ioctl(apm, APM_IOC_STARTPMU, NULL); printf("APM_IOC_STARTPMU %d\n", n); n = ioctl(apm, APM_IOC_SET_SPROF_WIN, 1); printf("APM_IOC_SET_SPROF_WIN %d\n",n); while (1) { devs = devs_back; select(FD_SETSIZE,&devs,NULL,NULL,NULL); if(FD_ISSET(apm,&devs) ) { read(apm,apm_event,40); switch(apm_event->type) { case APM_EVENT_DEVICE: printf("apm device kind:%x info:%x\n", apm_event->kind, apm_event->info ); break; case APM_EVENT_PROFILER: switch(apm_event->kind) { case EVENT_PROF_IDLE: printf("cpu idle\n"); break; case EVENT_PROF_PERF: printf("performance!?+\n"); break; case EVENT_PROF_SLEEP: printf("a wanna sleep!\n"); break; default: printf("profiler %x:%x\n",apm_event->kind,apm_event->info); } break; default: printf("apm event: %x:%x:%x\n", event[0],event[1],event[2]); } } /* if(FD_ISSET(usb,&devs) ) { read(usb,&event,40); printf("usb event: %d\n", event[0]); }*/ if(FD_ISSET(accy,&devs) ) { read(accy,&event,40); if(event[1]) plug_cable(event[0]); else unplug_cable(event[0]); } if(FD_ISSET(power,&devs) ) { read(power,&event,40); printf("power event: %d\n", event[0]); } } }