// SPDX-License-Identifier: GPL-2.0 /* * * Copyright (C) 2016-2022 Samsung, Inc. * Author: Dongrak Shin * */ /* usb notify layer v3.7 */ #define pr_fmt(fmt) "usb_notify: " fmt #include #include #include #include #include #include #include #include #include #include #include #include /* clock.h should be included since kernel 4.14 */ #include #include #define USBLOG_MAX_BUF_SIZE (1 << 6) /* 64 */ #define USBLOG_MAX_BUF2_SIZE (1 << 7) /* 128 */ #define USBLOG_MAX_BUF3_SIZE (1 << 8) /* 256 */ #define USBLOG_MAX_BUF4_SIZE (1 << 9) /* 512 */ #define USBLOG_MAX_STRING_SIZE (1 << 5) /* 32 */ #define USBLOG_CMP_INDEX 3 #define USBLOG_MAX_STORE_PORT (1 << 6) /* 64 */ #define USBLOG_CCIC_BUFFER_SIZE USBLOG_MAX_BUF4_SIZE #define USBLOG_MODE_BUFFER_SIZE USBLOG_MAX_BUF_SIZE #define USBLOG_STATE_BUFFER_SIZE USBLOG_MAX_BUF3_SIZE #define USBLOG_EVENT_BUFFER_SIZE USBLOG_MAX_BUF_SIZE #define USBLOG_PORT_BUFFER_SIZE USBLOG_MAX_BUF2_SIZE #define USBLOG_PCM_BUFFER_SIZE USBLOG_MAX_BUF_SIZE #define USBLOG_EXTRA_BUFFER_SIZE USBLOG_MAX_BUF2_SIZE #define USBLOG_INDEX 0xABCDABCD #define USBLOG_CC1 0xffffffff00000000 #define USBLOG_CC2 0x00000000ffffffff struct usblog_rtc_time { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; }; struct ccic_buf { unsigned long long ts_nsec; int cc_type; uint64_t noti; }; struct mode_buf { unsigned long long ts_nsec; char usbmode_str[USBLOG_MAX_STRING_SIZE]; }; struct state_buf { unsigned long long ts_nsec; int usbstate; }; struct event_buf { unsigned long long ts_nsec; unsigned long event; int enable; }; struct port_buf { unsigned long long ts_nsec; int type; uint16_t param1; uint16_t param2; uint16_t count; }; struct port_count { uint16_t vid; uint16_t pid; uint16_t count; }; struct pcm_buf { struct usblog_rtc_time rt; unsigned long long ts_nsec; int type; int enable; }; struct extra_buf { unsigned long long ts_nsec; int event; }; struct usblog_buf { unsigned long long ccic_count; unsigned long long mode_count; unsigned long long state_count; unsigned long long event_count; unsigned long long port_count; unsigned long long extra_count; unsigned long ccic_index; unsigned long mode_index; unsigned long state_index; unsigned long event_index; unsigned long port_index; unsigned long extra_index; struct ccic_buf ccic_buffer[USBLOG_CCIC_BUFFER_SIZE]; struct mode_buf mode_buffer[USBLOG_MODE_BUFFER_SIZE]; struct state_buf state_buffer[USBLOG_STATE_BUFFER_SIZE]; struct event_buf event_buffer[USBLOG_EVENT_BUFFER_SIZE]; struct port_buf port_buffer[USBLOG_PORT_BUFFER_SIZE]; struct port_count store_port_cnt[USBLOG_MAX_STORE_PORT]; struct extra_buf extra_buffer[USBLOG_EXTRA_BUFFER_SIZE]; }; struct usblog_vm_buf { unsigned long long pcm_count; unsigned long pcm_index; struct pcm_buf pcm_buffer[USBLOG_PCM_BUFFER_SIZE]; }; struct ccic_version { unsigned char hw_version[4]; unsigned char sw_main[3]; unsigned char sw_boot; }; struct usblog_root_str { unsigned long usblog_index; struct usblog_buf *usblog_buffer; struct usblog_vm_buf *usblog_vm_buffer; struct ccic_version ccic_ver; struct ccic_version ccic_bin_ver; spinlock_t usblog_lock; int init; }; struct ccic_type { uint64_t src:4; uint64_t dest:4; uint64_t id:8; uint64_t sub1:16; uint64_t sub2:16; uint64_t sub3:16; }; static struct usblog_root_str usblog_root; static const char *usbstate_string(enum usblog_state usbstate) { switch (usbstate) { case NOTIFY_CONFIGURED: return "CONFIGURED"; case NOTIFY_CONNECTED: return "CONNECTED"; case NOTIFY_DISCONNECTED: return "DISCONNECTED"; case NOTIFY_RESET: return "RESET"; case NOTIFY_RESET_FULL: return "RESET : FULL"; case NOTIFY_RESET_HIGH: return "RESET: HIGH"; case NOTIFY_RESET_SUPER: return "RESET : SUPER"; case NOTIFY_PULLUP: return "VBUS_PULLUP (EN OR DIS)"; case NOTIFY_PULLUP_ENABLE: return "VBUS_PULLUP_EN"; case NOTIFY_PULLUP_EN_SUCCESS: return "VBUS_PULLUP_EN : S"; case NOTIFY_PULLUP_EN_FAIL: return "VBUS_PULLUP_EN : F"; case NOTIFY_PULLUP_DISABLE: return "VBUS_PULLUP_DIS"; case NOTIFY_PULLUP_DIS_SUCCESS: return "VBUS_PULLUP_DIS : S"; case NOTIFY_PULLUP_DIS_FAIL: return "VBUS_PULLUP_DIS : F"; case NOTIFY_VBUS_SESSION: return "VBUS_SESSION (EN OR DIS)"; case NOTIFY_VBUS_SESSION_ENABLE: return "VBUS_SESSION_EN"; case NOTIFY_VBUS_EN_SUCCESS: return "VBUS_SESSION_EN : S"; case NOTIFY_VBUS_EN_FAIL: return "VBUS_SESSION_EN : F"; case NOTIFY_VBUS_SESSION_DISABLE: return "VBUS_SESSIOIN_DIS"; case NOTIFY_VBUS_DIS_SUCCESS: return "VBUS_SESSION_DIS : S"; case NOTIFY_VBUS_DIS_FAIL: return "VBUS_SESSION_DIS : F"; case NOTIFY_ACCSTART: return "ACCSTART"; case NOTIFY_HIGH: return "HIGH SPEED"; case NOTIFY_SUPER: return "SUPER SPEED"; case NOTIFY_GET_DES: return "GET_DES"; case NOTIFY_SET_CON: return "SET_CON"; case NOTIFY_CONNDONE_SSP: return "CONNDONE SSP"; case NOTIFY_CONNDONE_SS: return "CONNDONE SS"; case NOTIFY_CONNDONE_HS: return "CONNDONE HS"; case NOTIFY_CONNDONE_FS: return "CONNDONE FS"; case NOTIFY_CONNDONE_LS: return "CONNDONE LS"; default: return "UNDEFINED"; } } static const char *usbstatus_string(enum usblog_status usbstatus) { switch (usbstatus) { case NOTIFY_DETACH: return "DETACH"; case NOTIFY_ATTACH_DFP: return "ATTACH_DFP"; case NOTIFY_ATTACH_UFP: return "ATTACH_UFP"; case NOTIFY_ATTACH_DRP: return "ATTACH_DRP"; default: return "UNDEFINED"; } } static const char *ccic_dev_string(enum ccic_device dev) { switch (dev) { case NOTIFY_DEV_INITIAL: return "INITIAL"; case NOTIFY_DEV_USB: return "USB"; case NOTIFY_DEV_BATTERY: return "BATTERY"; case NOTIFY_DEV_PDIC: return "PDIC"; case NOTIFY_DEV_MUIC: return "MUIC"; case NOTIFY_DEV_CCIC: return "CCIC"; case NOTIFY_DEV_MANAGER: return "MANAGER"; case NOTIFY_DEV_DP: return "DP"; case NOTIFY_DEV_USB_DP: return "USB_DP"; case NOTIFY_DEV_SUB_BATTERY: return "BATTERY2"; case NOTIFY_DEV_SECOND_MUIC: return "MUIC2"; case NOTIFY_DEV_DEDICATED_MUIC: return "DEDICATED MUIC"; case NOTIFY_DEV_ALL: return "DEV ALL"; default: return "UNDEFINED"; } } static const char *ccic_id_string(enum ccic_id id) { switch (id) { case NOTIFY_ID_INITIAL: return "ID_INITIAL"; case NOTIFY_ID_ATTACH: return "ID_CONNECT"; case NOTIFY_ID_RID: return "ID_RID"; case NOTIFY_ID_USB: return "ID_USB"; case NOTIFY_ID_POWER_STATUS: return "ID_POWER_STATUS"; case NOTIFY_ID_WATER: return "ID_WATER"; case NOTIFY_ID_VCONN: return "ID_VCONN"; case NOTIFY_ID_OTG: return "ID_OTG"; case NOTIFY_ID_TA: return "ID_TA"; case NOTIFY_ID_DP_CONNECT: return "ID_DP_CONNECT"; case NOTIFY_ID_DP_HPD: return "ID_DP_HPD"; case NOTIFY_ID_DP_LINK_CONF: return "ID_DP_LINK_CONF"; case NOTIFY_ID_USB_DP: return "ID_USB_DP"; case NOTIFY_ID_ROLE_SWAP: return "ID_ROLE_SWAP"; case NOTIFY_ID_FAC: return "ID_FAC"; case NOTIFY_ID_CC_PIN_STATUS: return "ID_PIN_STATUS"; case NOTIFY_ID_WATER_CABLE: return "ID_WATER_CABLE"; case NOTIFY_ID_POFF_WATER: return "ID_POWEROFF_WATER"; case NOTIFY_ID_DEVICE_INFO: return "ID_DEVICE_INFO"; case NOTIFY_ID_SVID_INFO: return "ID_SVID_INFO"; case NOTIFY_ID_CLEAR_INFO: return "ID_CLEAR_INFO"; default: return "UNDEFINED"; } } static const char *ccic_rid_string(enum ccic_rid rid) { switch (rid) { case NOTIFY_RID_UNDEFINED: return "RID_UNDEFINED"; #if defined(CONFIG_USB_CCIC_NOTIFIER_USING_QC) case NOTIFY_RID_GND: return "RID_GND"; case NOTIFY_RID_056K: return "RID_056K"; #else case NOTIFY_RID_000K: return "RID_000K"; case NOTIFY_RID_001K: return "RID_001K"; #endif case NOTIFY_RID_255K: return "RID_255K"; case NOTIFY_RID_301K: return "RID_301K"; case NOTIFY_RID_523K: return "RID_523K"; case NOTIFY_RID_619K: return "RID_619K"; case NOTIFY_RID_OPEN: return "RID_OPEN"; default: return "UNDEFINED"; } } static const char *ccic_con_string(enum ccic_con con) { switch (con) { case NOTIFY_CON_DETACH: return "DETACHED"; case NOTIFY_CON_ATTACH: return "ATTACHED"; default: return "UNDEFINED"; } } static const char *ccic_rprd_string(enum ccic_rprd rprd) { switch (rprd) { case NOTIFY_RD: return "RD"; case NOTIFY_RP: return "RP"; default: return "UNDEFINED"; } } static const char *ccic_rpstatus_string(enum ccic_rpstatus rprd) { switch (rprd) { case NOTIFY_RP_NONE: return "NONE"; case NOTIFY_RP_56K: return "RP_56K"; case NOTIFY_RP_22K: return "RP_22K"; case NOTIFY_RP_10K: return "RP_10K"; case NOTIFY_RP_ABNORMAL: return "RP_ABNORMAL"; default: return "UNDEFINED"; } } static const char *ccic_hpd_string(enum ccic_hpd hpd) { switch (hpd) { case NOTIFY_HPD_LOW: return "LOW"; case NOTIFY_HPD_HIGH: return "HIGH"; case NOTIFY_HPD_IRQ: return "IRQ"; default: return "UNDEFINED"; } } static const char *ccic_pin_string(enum ccic_pin_assignment pin) { switch (pin) { case NOTIFY_DP_PIN_UNKNOWN: return "UNKNOWN"; case NOTIFY_DP_PIN_A: return "DP_PIN_A"; case NOTIFY_DP_PIN_B: return "DP_PIN_B"; case NOTIFY_DP_PIN_C: return "DP_PIN_C"; case NOTIFY_DP_PIN_D: return "DP_PIN_D"; case NOTIFY_DP_PIN_E: return "DP_PIN_E"; case NOTIFY_DP_PIN_F: return "DP_PIN_F"; default: return "UNKNOWN"; } } static const char *ccic_alternatemode_string(uint64_t id) { if ((id & ALTERNATE_MODE_READY) && (id & ALTERNATE_MODE_START)) return "READY & START"; else if ((id & ALTERNATE_MODE_READY) && (id & ALTERNATE_MODE_STOP)) return "READY & STOP"; else if (id & ALTERNATE_MODE_READY) return "MODE READY"; else if (id & ALTERNATE_MODE_START) return "START"; else if (id & ALTERNATE_MODE_STOP) return "STOP"; else if (id & ALTERNATE_MODE_RESET) return "RESET"; else return "UNDEFINED"; } static const char *ccic_voltage_string(uint8_t cc) { switch (cc) { case NOTIFY_CC_VOLT_OPEN: return "open"; case NOTIFY_CC_VOLT_RA: return "ra"; case NOTIFY_CC_VOLT_RD: return "rd"; case NOTIFY_CC_VOLT_SNK_DFT: return "rp 56k"; case NOTIFY_CC_VOLT_SNK_1_5: return "rp 22k"; case NOTIFY_CC_VOLT_SNK_3_0: return "rp 10k"; case NOTIFY_CC_DRP_TOGGLING: return "cc toggle"; default: return "undefined"; } } static const char *ccic_pinstatus_string(enum ccic_pin_status pinstatus) { switch (pinstatus) { case NOTIFY_PIN_NOTERMINATION: return "NO TERMINATION"; case NOTIFY_PIN_CC1_ACTIVE: return "CC1_ACTIVE"; case NOTIFY_PIN_CC2_ACTIVE: return "CC2_ACTIVE"; case NOTIFY_PIN_AUDIO_ACCESSORY: return "AUDIO_ACCESSORY"; default: return "ETC"; } } static const char *extra_string(enum extra event) { switch (event) { case NOTIFY_EXTRA_USBKILLER: return "USB_KILLER"; case NOTIFY_EXTRA_HARDRESET_SENT: return "PDIC HARDRESET_SENT"; case NOTIFY_EXTRA_HARDRESET_RECEIVED: return "PDIC HARDRESET_RECEIVED"; case NOTIFY_EXTRA_SYSERROR_BOOT_WDT: return "PDIC WDT RESET"; case NOTIFY_EXTRA_SYSMSG_BOOT_POR: return "PDIC POR RESET"; case NOTIFY_EXTRA_SYSMSG_CC_SHORT: return "CC VBUS SHORT"; case NOTIFY_EXTRA_SYSMSG_SBU_GND_SHORT: return "SBU GND SHORT"; case NOTIFY_EXTRA_SYSMSG_SBU_VBUS_SHORT: return "SBU VBUS SHORT"; case NOTIFY_EXTRA_UVDM_TIMEOUT: return "UVDM TIMEOUT"; case NOTIFY_EXTRA_CCOPEN_REQ_SET: return "CC OPEN SET"; case NOTIFY_EXTRA_CCOPEN_REQ_CLEAR: return "CC OPEN CLEAR"; case NOTIFY_EXTRA_USB_ANALOGAUDIO: return "USB ANALOG AUDIO"; case NOTIFY_EXTRA_USBHOST_OVERCURRENT: return "USB HOST OVERCURRENT"; case NOTIFY_EXTRA_ROOTHUB_SUSPEND_FAIL: return "ROOTHUB SUSPEND FAIL"; case NOTIFY_EXTRA_PORT_SUSPEND_FAIL: return "PORT SUSPEND FAIL"; case NOTIFY_EXTRA_PORT_SUSPEND_WAKEUP_FAIL: return "PORT REMOTE WAKEUP FAIL"; case NOTIFY_EXTRA_PORT_SUSPEND_LTM_FAIL: return "PORT LTM FAIL"; case NOTIFY_EXTRA_VIB_FW_LOAD_SUCCESS: return "VIBRATOR FIRMWARE LOAD SUCCESS"; default: return "ETC"; } } static const char * const tcpm_states[] = { NOTIFY_FOREACH_STATE(NOTIFY_GENERATE_STRING) }; static void usblog_get_rt(struct usblog_rtc_time *rt) { struct rtc_time tm; struct timespec64 ts64; ktime_get_real_ts64(&ts64); rtc_time64_to_tm(ts64.tv_sec - (sys_tz.tz_minuteswest * 60), &tm); rt->tm_mon = tm.tm_mon + 1; rt->tm_mday = tm.tm_mday; rt->tm_hour = tm.tm_hour; rt->tm_min = tm.tm_min; rt->tm_sec = tm.tm_sec; } static void print_ccic_event(struct seq_file *m, unsigned long long ts, unsigned long rem_nsec, int cc_type, uint64_t *noti) { struct ccic_type type = *(struct ccic_type *)noti; uint8_t cc1 = 0, cc2 = 0; int cable = type.sub3; switch (cc_type) { case NOTIFY_FUNCSTATE: seq_printf(m, "[%5lu.%06lu] function state = %llu\n", (unsigned long)ts, rem_nsec / 1000, *noti); break; case NOTIFY_TCPMSTATE: if (*noti >= ARRAY_SIZE(tcpm_states)) { seq_printf(m, "[%5lu.%06lu] tcpm state = %llu\n", (unsigned long)ts, rem_nsec / 1000, *noti); } else { seq_printf(m, "[%5lu.%06lu] tcpm state = %s(%llu)\n", (unsigned long)ts, rem_nsec / 1000, tcpm_states[*noti], *noti); } break; case NOTIFY_CCSTATE: cc1 = (*noti & USBLOG_CC1) >> 32; cc2 = (*noti & USBLOG_CC2); seq_printf(m, "[%5lu.%06lu] cc1=%s cc2=%s\n", (unsigned long)ts, rem_nsec / 1000, ccic_voltage_string(cc1), ccic_voltage_string(cc2)); break; case NOTIFY_ALTERNATEMODE: seq_printf(m, "[%5lu.%06lu] ccic alternate mode is %s 0x%04llx\n", (unsigned long)ts, rem_nsec / 1000, ccic_alternatemode_string(*noti), *noti); break; case NOTIFY_CCIC_EVENT: if (type.id == NOTIFY_ID_ATTACH) { if (type.src == NOTIFY_DEV_MUIC || type.src == NOTIFY_DEV_SECOND_MUIC || type.src == NOTIFY_DEV_DEDICATED_MUIC) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s rprd=%s cable=%d %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_rprd_string(type.sub2), cable, ccic_con_string(type.sub1)); else seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s rprd=%s rp status=%s %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_rprd_string(type.sub2), ccic_rpstatus_string(type.sub3), ccic_con_string(type.sub1)); } else if (type.id == NOTIFY_ID_RID) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s rid=%s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_rid_string(type.sub1)); else if (type.id == NOTIFY_ID_USB) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s status=%s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), usbstatus_string(type.sub2)); else if (type.id == NOTIFY_ID_POWER_STATUS) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_con_string(type.sub1)); else if (type.id == NOTIFY_ID_WATER) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s %s detected\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub1 ? "WATER":"DRY"); else if (type.id == NOTIFY_ID_VCONN) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest)); else if (type.id == NOTIFY_ID_OTG) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub2 ? "Enable":"Disable"); else if (type.id == NOTIFY_ID_TA) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_con_string(type.sub1)); else if (type.id == NOTIFY_ID_DP_CONNECT) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s 0x%04x/0x%04x %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub2, type.sub3, ccic_con_string(type.sub1)); else if (type.id == NOTIFY_ID_DP_HPD) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s hpd=%s irq=%s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_hpd_string(type.sub1), type.sub2 ? "VALID":"NONE"); else if (type.id == NOTIFY_ID_DP_LINK_CONF) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s PIN-assign=%s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_pin_string(type.sub1)); else if (type.id == NOTIFY_ID_USB_DP) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s CON=%d HS=%d\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub1, type.sub2); else if (type.id == NOTIFY_ID_ROLE_SWAP) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s sub1=%d sub2=%d\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub1, type.sub2); else if (type.id == NOTIFY_ID_FAC) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s ErrState=%d\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub1); else if (type.id == NOTIFY_ID_CC_PIN_STATUS) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s pinstatus=%s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_pinstatus_string(type.sub1)); else if (type.id == NOTIFY_ID_WATER_CABLE) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_con_string(type.sub1)); else if (type.id == NOTIFY_ID_POFF_WATER) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s POWEROFF %s detected\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub1 ? "WATER":"DRY"); else if (type.id == NOTIFY_ID_DEVICE_INFO) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s vid=%04x pid=%04x bcd=%04x\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub1, type.sub2, type.sub3); else if (type.id == NOTIFY_ID_SVID_INFO) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s svid=%04x\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub1); else if (type.id == NOTIFY_ID_CLEAR_INFO) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s clear %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), (type.sub1 == NOTIFY_ID_DEVICE_INFO) ? "DEVICE INFO" : "SVID INFO"); else seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s rprd=%s %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_rprd_string(type.sub2), ccic_con_string(type.sub1)); break; case NOTIFY_MANAGER: if (type.id == NOTIFY_ID_ATTACH) { if (type.src == NOTIFY_DEV_MUIC || type.src == NOTIFY_DEV_SECOND_MUIC || type.src == NOTIFY_DEV_DEDICATED_MUIC) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s rprd=%s cable=%d %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_rprd_string(type.sub2), cable, ccic_con_string(type.sub1)); else seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s rprd=%s rp status=%s %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_rprd_string(type.sub2), ccic_rpstatus_string(type.sub3), ccic_con_string(type.sub1)); } else if (type.id == NOTIFY_ID_RID) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s rid=%s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_rid_string(type.sub1)); else if (type.id == NOTIFY_ID_USB) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s status=%s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), usbstatus_string(type.sub2)); else if (type.id == NOTIFY_ID_POWER_STATUS) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_con_string(type.sub1)); else if (type.id == NOTIFY_ID_WATER) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s %s detected\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub1 ? "WATER":"DRY"); else if (type.id == NOTIFY_ID_VCONN) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest)); else if (type.id == NOTIFY_ID_OTG) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub2 ? "Enable":"Disable"); else if (type.id == NOTIFY_ID_TA) seq_printf(m, "[%5lu.%06lu] ccic notify: id=%s src=%s dest=%s %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_con_string(type.sub1)); else if (type.id == NOTIFY_ID_DP_CONNECT) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s 0x%04x/0x%04x %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub2, type.sub3, ccic_con_string(type.sub1)); else if (type.id == NOTIFY_ID_DP_HPD) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s hpd=%s irq=%s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_hpd_string(type.sub1), type.sub2 ? "VALID":"NONE"); else if (type.id == NOTIFY_ID_DP_LINK_CONF) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s PIN-assign=%s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_pin_string(type.sub1)); else if (type.id == NOTIFY_ID_USB_DP) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s CON=%d HS=%d\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub1, type.sub2); else if (type.id == NOTIFY_ID_ROLE_SWAP) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s sub1=%d sub2=%d\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub1, type.sub2); else if (type.id == NOTIFY_ID_FAC) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s ErrState=%d\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub1); else if (type.id == NOTIFY_ID_CC_PIN_STATUS) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s pinstatus=%s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_pinstatus_string(type.sub1)); else if (type.id == NOTIFY_ID_WATER_CABLE) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_con_string(type.sub1)); else if (type.id == NOTIFY_ID_DEVICE_INFO) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s vid=%04x pid=%04x bcd=%04x\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub1, type.sub2, type.sub3); else if (type.id == NOTIFY_ID_SVID_INFO) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s svid=%04x\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), type.sub1); else if (type.id == NOTIFY_ID_CLEAR_INFO) seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s clear %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), (type.sub1 == NOTIFY_ID_DEVICE_INFO) ? "DEVICE INFO" : "SVID INFO"); else seq_printf(m, "[%5lu.%06lu] manager notify: id=%s src=%s dest=%s rprd=%s %s\n", (unsigned long)ts, rem_nsec / 1000, ccic_id_string(type.id), ccic_dev_string(type.src), ccic_dev_string(type.dest), ccic_rprd_string(type.sub2), ccic_con_string(type.sub1)); break; default: seq_printf(m, "[%5lu.%06lu] undefined event\n", (unsigned long)ts, rem_nsec / 1000); break; } } static void print_port_string(struct seq_file *m, unsigned long long ts, unsigned long rem_nsec, int type, uint16_t param1, uint16_t param2, uint16_t cnt) { switch (type) { case NOTIFY_PORT_CONNECT: seq_printf(m, "[%5lu.%06lu] port connect - VID:0x%04x PID:0x%04x cnt:%d\n", (unsigned long)ts, rem_nsec / 1000, param1, param2, cnt); break; case NOTIFY_PORT_DISCONNECT: seq_printf(m, "[%5lu.%06lu] port disconnect - VID:0x%04x PID:0x%04x\n", (unsigned long)ts, rem_nsec / 1000, param1, param2); break; case NOTIFY_PORT_CLASS: seq_printf(m, "[%5lu.%06lu] device class %d, interface class %d\n", (unsigned long)ts, rem_nsec / 1000, param1, param2); break; case NOTIFY_PORT_CLASS_BLOCK: seq_printf(m, "[%5lu.%06lu] block device class %d, interface class %d\n", (unsigned long)ts, rem_nsec / 1000, param1, param2); break; default: seq_printf(m, "[%5lu.%06lu] undefined event\n", (unsigned long)ts, rem_nsec / 1000); break; } } static uint16_t set_port_count(uint16_t vid, uint16_t pid) { int i; uint16_t ret = 0; struct port_count *temp_port; for (i = 0; i < USBLOG_MAX_STORE_PORT; i++) { temp_port = &usblog_root.usblog_buffer->store_port_cnt[i]; if ((temp_port->vid == vid) && temp_port->pid == pid) { temp_port->count++; ret = temp_port->count; break; } if (!temp_port->vid && !temp_port->pid) { temp_port->vid = vid; temp_port->pid = pid; temp_port->count++; ret = temp_port->count; break; } } if (i == USBLOG_MAX_STORE_PORT) pr_err("%s store port overflow\n", __func__); return ret; } static void print_pcm_string(struct seq_file *m, struct usblog_rtc_time *rt, unsigned long long ts, unsigned long rem_nsec, int type, int enable) { switch (type) { case NOTIFY_PCM_PLAYBACK: seq_printf(m, "[%02d-%02d %02d:%02d:%02d][%5lu.%06lu] USB PCM PLAYBACK %s\n", rt->tm_mon, rt->tm_mday, rt->tm_hour, rt->tm_min, rt->tm_sec, (unsigned long)ts, rem_nsec / 1000, enable ? "OPEN" : "CLOSE"); break; case NOTIFY_PCM_CAPTURE: seq_printf(m, "[%02d-%02d %02d:%02d:%02d][%5lu.%06lu] USB PCM CAPTURE %s\n", rt->tm_mon, rt->tm_mday, rt->tm_hour, rt->tm_min, rt->tm_sec, (unsigned long)ts, rem_nsec / 1000, enable ? "OPEN" : "CLOSE"); break; default: seq_printf(m, "[%02d-%02d %02d:%02d:%02d][%5lu.%06lu] undefined event\n", rt->tm_mon, rt->tm_mday, rt->tm_hour, rt->tm_min, rt->tm_sec, (unsigned long)ts, rem_nsec / 1000); break; } } static int usblog_proc_show(struct seq_file *m, void *v) { struct usblog_buf *temp_usblog_buffer; struct usblog_vm_buf *temp_usblog_vm_buffer; struct usblog_rtc_time rt; unsigned long long ts; unsigned long rem_nsec; unsigned long i; temp_usblog_buffer = usblog_root.usblog_buffer; temp_usblog_vm_buffer = usblog_root.usblog_vm_buffer; if (!temp_usblog_buffer || !temp_usblog_vm_buffer) goto err; usblog_get_rt(&rt); ts = local_clock(); rem_nsec = do_div(ts, 1000000000); seq_printf(m, "time sync: [%02d-%02d %02d:%02d:%02d][%5lu.%06lu]\n", rt.tm_mon, rt.tm_mday, rt.tm_hour, rt.tm_min, rt.tm_sec, (unsigned long)ts, rem_nsec / 1000); seq_printf(m, "usblog CC IC version:\n"); seq_printf(m, "hw version =%2x %2x %2x %2x\n", usblog_root.ccic_ver.hw_version[3], usblog_root.ccic_ver.hw_version[2], usblog_root.ccic_ver.hw_version[1], usblog_root.ccic_ver.hw_version[0]); seq_printf(m, "sw version =%2x %2x %2x %2x\n", usblog_root.ccic_ver.sw_main[2], usblog_root.ccic_ver.sw_main[1], usblog_root.ccic_ver.sw_main[0], usblog_root.ccic_ver.sw_boot); seq_printf(m, "bin version =%2x %2x %2x %2x\n", usblog_root.ccic_bin_ver.sw_main[2], usblog_root.ccic_bin_ver.sw_main[1], usblog_root.ccic_bin_ver.sw_main[0], usblog_root.ccic_bin_ver.sw_boot); seq_printf(m, "\n\n"); seq_printf(m, "usblog CCIC EVENT: count=%llu maxline=%d\n", temp_usblog_buffer->ccic_count, USBLOG_CCIC_BUFFER_SIZE); if (temp_usblog_buffer->ccic_count >= USBLOG_CCIC_BUFFER_SIZE) { for (i = temp_usblog_buffer->ccic_index; i < USBLOG_CCIC_BUFFER_SIZE; i++) { ts = temp_usblog_buffer->ccic_buffer[i].ts_nsec; rem_nsec = do_div(ts, 1000000000); print_ccic_event(m, ts, rem_nsec, temp_usblog_buffer->ccic_buffer[i].cc_type, &temp_usblog_buffer->ccic_buffer[i].noti); } } for (i = 0; i < temp_usblog_buffer->ccic_index; i++) { ts = temp_usblog_buffer->ccic_buffer[i].ts_nsec; rem_nsec = do_div(ts, 1000000000); print_ccic_event(m, ts, rem_nsec, temp_usblog_buffer->ccic_buffer[i].cc_type, &temp_usblog_buffer->ccic_buffer[i].noti); } seq_printf(m, "\n\n"); seq_printf(m, "usblog USB_MODE: count=%llu maxline=%d\n", temp_usblog_buffer->mode_count, USBLOG_MODE_BUFFER_SIZE); if (temp_usblog_buffer->mode_count >= USBLOG_MODE_BUFFER_SIZE) { for (i = temp_usblog_buffer->mode_index; i < USBLOG_MODE_BUFFER_SIZE; i++) { ts = temp_usblog_buffer->mode_buffer[i].ts_nsec; rem_nsec = do_div(ts, 1000000000); seq_printf(m, "[%5lu.%06lu] %s\n", (unsigned long)ts, rem_nsec / 1000, temp_usblog_buffer->mode_buffer[i].usbmode_str); } } for (i = 0; i < temp_usblog_buffer->mode_index; i++) { ts = temp_usblog_buffer->mode_buffer[i].ts_nsec; rem_nsec = do_div(ts, 1000000000); seq_printf(m, "[%5lu.%06lu] %s\n", (unsigned long)ts, rem_nsec / 1000, temp_usblog_buffer->mode_buffer[i].usbmode_str); } seq_printf(m, "\n\n"); seq_printf(m, "usblog USB STATE: count=%llu maxline=%d\n", temp_usblog_buffer->state_count, USBLOG_STATE_BUFFER_SIZE); if (temp_usblog_buffer->state_count >= USBLOG_STATE_BUFFER_SIZE) { for (i = temp_usblog_buffer->state_index; i < USBLOG_STATE_BUFFER_SIZE; i++) { ts = temp_usblog_buffer->state_buffer[i].ts_nsec; rem_nsec = do_div(ts, 1000000000); seq_printf(m, "[%5lu.%06lu] %s\n", (unsigned long)ts, rem_nsec / 1000, usbstate_string(temp_usblog_buffer ->state_buffer[i].usbstate)); } } for (i = 0; i < temp_usblog_buffer->state_index; i++) { ts = temp_usblog_buffer->state_buffer[i].ts_nsec; rem_nsec = do_div(ts, 1000000000); seq_printf(m, "[%5lu.%06lu] %s\n", (unsigned long)ts, rem_nsec / 1000, usbstate_string(temp_usblog_buffer->state_buffer[i].usbstate)); } seq_printf(m, "\n\n"); seq_printf(m, "usblog USB EVENT: count=%llu maxline=%d\n", temp_usblog_buffer->event_count, USBLOG_EVENT_BUFFER_SIZE); if (temp_usblog_buffer->event_count >= USBLOG_EVENT_BUFFER_SIZE) { for (i = temp_usblog_buffer->event_index; i < USBLOG_EVENT_BUFFER_SIZE; i++) { ts = temp_usblog_buffer->event_buffer[i].ts_nsec; rem_nsec = do_div(ts, 1000000000); seq_printf(m, "[%5lu.%06lu] %s %s\n", (unsigned long)ts, rem_nsec / 1000, event_string(temp_usblog_buffer->event_buffer[i].event), status_string(temp_usblog_buffer ->event_buffer[i].enable)); } } for (i = 0; i < temp_usblog_buffer->event_index; i++) { ts = temp_usblog_buffer->event_buffer[i].ts_nsec; rem_nsec = do_div(ts, 1000000000); seq_printf(m, "[%5lu.%06lu] %s %s\n", (unsigned long)ts, rem_nsec / 1000, event_string(temp_usblog_buffer->event_buffer[i].event), status_string(temp_usblog_buffer->event_buffer[i].enable)); } seq_printf(m, "\n\n"); seq_printf(m, "usblog PORT: count=%llu maxline=%d\n", temp_usblog_buffer->port_count, USBLOG_PORT_BUFFER_SIZE); if (temp_usblog_buffer->port_count >= USBLOG_PORT_BUFFER_SIZE) { for (i = temp_usblog_buffer->port_index; i < USBLOG_PORT_BUFFER_SIZE; i++) { ts = temp_usblog_buffer->port_buffer[i].ts_nsec; rem_nsec = do_div(ts, 1000000000); print_port_string(m, ts, rem_nsec, temp_usblog_buffer->port_buffer[i].type, temp_usblog_buffer->port_buffer[i].param1, temp_usblog_buffer->port_buffer[i].param2, temp_usblog_buffer->port_buffer[i].count); } } for (i = 0; i < temp_usblog_buffer->port_index; i++) { ts = temp_usblog_buffer->port_buffer[i].ts_nsec; rem_nsec = do_div(ts, 1000000000); print_port_string(m, ts, rem_nsec, temp_usblog_buffer->port_buffer[i].type, temp_usblog_buffer->port_buffer[i].param1, temp_usblog_buffer->port_buffer[i].param2, temp_usblog_buffer->port_buffer[i].count); } seq_printf(m, "\n\n"); seq_printf(m, "usblog PCM: count=%llu maxline=%d\n", temp_usblog_vm_buffer->pcm_count, USBLOG_PCM_BUFFER_SIZE); if (temp_usblog_vm_buffer->pcm_count >= USBLOG_PCM_BUFFER_SIZE) { for (i = temp_usblog_vm_buffer->pcm_index; i < USBLOG_PCM_BUFFER_SIZE; i++) { ts = temp_usblog_vm_buffer->pcm_buffer[i].ts_nsec; rem_nsec = do_div(ts, 1000000000); print_pcm_string(m, &temp_usblog_vm_buffer->pcm_buffer[i].rt, ts, rem_nsec, temp_usblog_vm_buffer->pcm_buffer[i].type, temp_usblog_vm_buffer->pcm_buffer[i].enable); } } for (i = 0; i < temp_usblog_vm_buffer->pcm_index; i++) { ts = temp_usblog_vm_buffer->pcm_buffer[i].ts_nsec; rem_nsec = do_div(ts, 1000000000); print_pcm_string(m, &temp_usblog_vm_buffer->pcm_buffer[i].rt, ts, rem_nsec, temp_usblog_vm_buffer->pcm_buffer[i].type, temp_usblog_vm_buffer->pcm_buffer[i].enable); } seq_printf(m, "\n\n"); seq_printf(m, "usblog EXTRA: count=%llu maxline=%d\n", temp_usblog_buffer->extra_count, USBLOG_EXTRA_BUFFER_SIZE); if (temp_usblog_buffer->extra_count >= USBLOG_EXTRA_BUFFER_SIZE) { for (i = temp_usblog_buffer->extra_index; i < USBLOG_EXTRA_BUFFER_SIZE; i++) { ts = temp_usblog_buffer->extra_buffer[i].ts_nsec; rem_nsec = do_div(ts, 1000000000); seq_printf(m, "[%5lu.%06lu] %s\n", (unsigned long)ts, rem_nsec / 1000, extra_string(temp_usblog_buffer ->extra_buffer[i].event)); } } for (i = 0; i < temp_usblog_buffer->extra_index; i++) { ts = temp_usblog_buffer->extra_buffer[i].ts_nsec; rem_nsec = do_div(ts, 1000000000); seq_printf(m, "[%5lu.%06lu] %s\n", (unsigned long)ts, rem_nsec / 1000, extra_string(temp_usblog_buffer->extra_buffer[i].event)); } err: return 0; } static int usblog_proc_open(struct inode *inode, struct file *file) { return single_open(file, usblog_proc_show, NULL); } static const struct file_operations usblog_proc_fops = { .open = usblog_proc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; void ccic_store_usblog_notify(int type, uint64_t *param1) { struct ccic_buf *ccic_buffer; unsigned long long *target_count; unsigned long *target_index; target_count = &usblog_root.usblog_buffer->ccic_count; target_index = &usblog_root.usblog_buffer->ccic_index; ccic_buffer = &usblog_root.usblog_buffer->ccic_buffer[*target_index]; if (ccic_buffer == NULL) { pr_err("%s target_buffer error\n", __func__); goto err; } ccic_buffer->ts_nsec = local_clock(); ccic_buffer->cc_type = type; ccic_buffer->noti = *param1; *target_index = (*target_index+1)%USBLOG_CCIC_BUFFER_SIZE; (*target_count)++; err: return; } void mode_store_usblog_notify(int type, char *param1) { struct mode_buf *md_buffer; unsigned long long *target_count; unsigned long *target_index; char buf[256], buf2[4]; char *b, *name; int param_len; target_count = &usblog_root.usblog_buffer->mode_count; target_index = &usblog_root.usblog_buffer->mode_index; md_buffer = &usblog_root.usblog_buffer->mode_buffer[*target_index]; if (md_buffer == NULL) { pr_err("%s target_buffer error\n", __func__); goto err; } md_buffer->ts_nsec = local_clock(); strlcpy(buf, param1, sizeof(buf)); b = strim(buf); if (type == NOTIFY_USBMODE_EXTRA) { param_len = strlen(b); if (param_len >= USBLOG_MAX_STRING_SIZE) param_len = USBLOG_MAX_STRING_SIZE-1; strncpy(md_buffer->usbmode_str, b, sizeof(md_buffer->usbmode_str)-1); } else if (type == NOTIFY_USBMODE) { if (b) { name = strsep(&b, ","); strlcpy(buf2, name, sizeof(buf2)); strncpy(md_buffer->usbmode_str, buf2, sizeof(md_buffer->usbmode_str)-1); } while (b) { name = strsep(&b, ","); if (!name) continue; if (USBLOG_MAX_STRING_SIZE - strlen(md_buffer->usbmode_str) < 5) { strncpy(md_buffer->usbmode_str, "overflow", sizeof(md_buffer->usbmode_str)-1); b = NULL; } else { strncat(md_buffer->usbmode_str, ",", 1); strncat(md_buffer->usbmode_str, name, 3); } } } *target_index = (*target_index+1)%USBLOG_MODE_BUFFER_SIZE; (*target_count)++; err: return; } void state_store_usblog_notify(int type, char *param1) { struct state_buf *st_buffer; unsigned long long *target_count; unsigned long *target_index; char buf[256], index, index2, index3; char *b, *name; int usbstate = 0; target_count = &usblog_root.usblog_buffer->state_count; target_index = &usblog_root.usblog_buffer->state_index; st_buffer = &usblog_root.usblog_buffer->state_buffer[*target_index]; if (st_buffer == NULL) { pr_err("%s target_buffer error\n", __func__); goto err; } st_buffer->ts_nsec = local_clock(); strlcpy(buf, param1, sizeof(buf)); b = strim(buf); name = strsep(&b, "="); index = *(b+USBLOG_CMP_INDEX); switch (index) { case 'F': /* CONFIGURED */ usbstate = NOTIFY_CONFIGURED; break; case 'N': /* CONNECTED */ usbstate = NOTIFY_CONNECTED; break; case 'C': /* DISCONNECTED */ usbstate = NOTIFY_DISCONNECTED; break; case 'E': /* RESET */ name = strsep(&b, ":"); if (b) { index2 = *b; switch (index2) { case 'F': /* FULL SPEED */ usbstate = NOTIFY_RESET_FULL; break; case 'H': /* HIGH SPEED */ usbstate = NOTIFY_RESET_HIGH; break; case 'S': /* SUPER SPEED */ usbstate = NOTIFY_RESET_SUPER; break; default: usbstate = NOTIFY_RESET; break; } } else usbstate = NOTIFY_RESET; break; case 'L': /* GADGET PULL UP/DN */ name = strsep(&b, ":"); if (b) { index2 = *b; name = strsep(&b, ":"); if (b) index3 = *b; else /* X means none */ index3 = 'X'; } else /* X means none */ index2 = 'X'; switch (index2) { case 'E': /* VBUS SESSION ENABLE */ if (index3 == 'S') usbstate = NOTIFY_PULLUP_EN_SUCCESS; else if (index3 == 'F') usbstate = NOTIFY_PULLUP_EN_FAIL; else usbstate = NOTIFY_PULLUP_ENABLE; break; case 'D': /* VBUS SESSION DISABLE */ if (index3 == 'S') usbstate = NOTIFY_PULLUP_DIS_SUCCESS; else if (index3 == 'F') usbstate = NOTIFY_PULLUP_DIS_FAIL; else usbstate = NOTIFY_PULLUP_DISABLE; break; default: usbstate = NOTIFY_PULLUP; break; } break; case 'R': /* ACCESSORY START */ usbstate = NOTIFY_ACCSTART; break; case 'S': /* GADGET_VBUS EN/DN*/ name = strsep(&b, ":"); if (b) { index2 = *b; name = strsep(&b, ":"); if (b) index3 = *b; else /* X means none */ index3 = 'X'; } else /* X means none */ index2 = 'X'; switch (index2) { case 'E': /* VBUS SESSION ENABLE */ if (index3 == 'S') usbstate = NOTIFY_VBUS_EN_SUCCESS; else if (index3 == 'F') usbstate = NOTIFY_VBUS_EN_FAIL; else usbstate = NOTIFY_VBUS_SESSION_ENABLE; break; case 'D': /* VBUS SESSION DISABLE */ if (index3 == 'S') usbstate = NOTIFY_VBUS_DIS_SUCCESS; else if (index3 == 'F') usbstate = NOTIFY_VBUS_DIS_FAIL; else usbstate = NOTIFY_VBUS_SESSION_DISABLE; break; default: usbstate = NOTIFY_VBUS_SESSION; break; } break; case 'D': /* SUPER SPEED */ usbstate = NOTIFY_SUPER; break; case 'H': /*HIGH SPEED */ usbstate = NOTIFY_HIGH; break; case 'M': /* USB ENUMERATION */ name = strsep(&b, ":"); if (b) { index2 = *b; name = strsep(&b, ":"); if (b) index3 = *b; else /* X means none */ index3 = 'X'; } else /* X means none */ index2 = 'X'; switch (index2) { case 'C': /* CONNDONE */ if (index3 == 'P') /* SUPERSPEED_PLUS */ usbstate = NOTIFY_CONNDONE_SSP; else if (index3 == 'S') /* SUPERSPEED */ usbstate = NOTIFY_CONNDONE_SS; else if (index3 == 'H') /* HIGHSPEED */ usbstate = NOTIFY_CONNDONE_HS; else if (index3 == 'F') /* FULLSPEED */ usbstate = NOTIFY_CONNDONE_FS; else if (index3 == 'L') /* LOWSPEED */ usbstate = NOTIFY_CONNDONE_LS; break; case 'G': /* GET */ if (index3 == 'D') /* GET_DES */ usbstate = NOTIFY_GET_DES; break; case 'S': /* SET */ if (index3 == 'C') /* SET_CON */ usbstate = NOTIFY_SET_CON; break; default: break; } break; default: pr_err("%s state param error. state=%s\n", __func__, param1); goto err; } st_buffer->usbstate = usbstate; *target_index = (*target_index+1)%USBLOG_STATE_BUFFER_SIZE; (*target_count)++; err: return; } void event_store_usblog_notify(int type, unsigned long *param1, int *param2) { struct event_buf *ev_buffer; unsigned long long *target_count; unsigned long *target_index; target_count = &usblog_root.usblog_buffer->event_count; target_index = &usblog_root.usblog_buffer->event_index; ev_buffer = &usblog_root.usblog_buffer->event_buffer[*target_index]; if (ev_buffer == NULL) { pr_err("%s target_buffer error\n", __func__); goto err; } ev_buffer->ts_nsec = local_clock(); ev_buffer->event = *param1; ev_buffer->enable = *param2; *target_index = (*target_index+1)%USBLOG_EVENT_BUFFER_SIZE; (*target_count)++; err: return; } void port_store_usblog_notify(int type, void *param1, void *param2) { struct port_buf *pt_buffer; unsigned long long *target_count; unsigned long *target_index; target_count = &usblog_root.usblog_buffer->port_count; target_index = &usblog_root.usblog_buffer->port_index; pt_buffer = &usblog_root.usblog_buffer->port_buffer[*target_index]; if (pt_buffer == NULL) { pr_err("%s target_buffer error\n", __func__); goto err; } pt_buffer->ts_nsec = local_clock(); pt_buffer->type = type; if (type == NOTIFY_PORT_CONNECT) { pt_buffer->param1 = le16_to_cpu(*(__le16 *)(param1)); pt_buffer->param2 = le16_to_cpu(*(__le16 *)(param2)); pt_buffer->count = set_port_count(pt_buffer->param1, pt_buffer->param2); } else if (type == NOTIFY_PORT_DISCONNECT) { pt_buffer->param1 = le16_to_cpu(*(__le16 *)(param1)); pt_buffer->param2 = le16_to_cpu(*(__le16 *)(param2)); } else { pt_buffer->param1 = (uint16_t)(*(__u8 *)(param1)); pt_buffer->param2 = (uint16_t)(*(__u8 *)(param2)); } *target_index = (*target_index+1)%USBLOG_PORT_BUFFER_SIZE; (*target_count)++; err: return; } void pcm_store_usblog_notify(int type, int *param1) { struct pcm_buf *pcm_buffer; unsigned long long *target_count; unsigned long *target_index; target_count = &usblog_root.usblog_vm_buffer->pcm_count; target_index = &usblog_root.usblog_vm_buffer->pcm_index; pcm_buffer = &usblog_root.usblog_vm_buffer->pcm_buffer[*target_index]; if (pcm_buffer == NULL) { pr_err("%s target_buffer error\n", __func__); goto err; } usblog_get_rt(&pcm_buffer->rt); pcm_buffer->ts_nsec = local_clock(); pcm_buffer->type = type; pcm_buffer->enable = *param1; *target_index = (*target_index+1)%USBLOG_PCM_BUFFER_SIZE; (*target_count)++; err: return; } void extra_store_usblog_notify(int type, int *param1) { struct extra_buf *ex_buffer; unsigned long long *target_count; unsigned long *target_index; target_count = &usblog_root.usblog_buffer->extra_count; target_index = &usblog_root.usblog_buffer->extra_index; ex_buffer = &usblog_root.usblog_buffer->extra_buffer[*target_index]; if (ex_buffer == NULL) { pr_err("%s target_buffer error\n", __func__); goto err; } ex_buffer->ts_nsec = local_clock(); ex_buffer->event = *param1; *target_index = (*target_index+1)%USBLOG_EXTRA_BUFFER_SIZE; (*target_count)++; err: return; } void store_usblog_notify(int type, void *param1, void *param2) { unsigned long flags = 0; uint64_t temp = 0; if (!usblog_root.init) register_usblog_proc(); spin_lock_irqsave(&usblog_root.usblog_lock, flags); if (!usblog_root.usblog_buffer) { pr_err("%s usblog_buffer is null\n", __func__); spin_unlock_irqrestore(&usblog_root.usblog_lock, flags); return; } if (!usblog_root.usblog_vm_buffer) { pr_err("%s usblog_vm_buffer is null\n", __func__); spin_unlock_irqrestore(&usblog_root.usblog_lock, flags); return; } if (type == NOTIFY_FUNCSTATE || type == NOTIFY_TCPMSTATE || type == NOTIFY_ALTERNATEMODE) { temp = *(int *)param1; ccic_store_usblog_notify(type, &temp); } else if (type == NOTIFY_CCSTATE || type == NOTIFY_CCIC_EVENT || type == NOTIFY_MANAGER) ccic_store_usblog_notify(type, (uint64_t *)param1); else if (type == NOTIFY_EVENT) event_store_usblog_notify(type, (unsigned long *)param1, (int *)param2); else if (type == NOTIFY_USBMODE || type == NOTIFY_USBMODE_EXTRA) mode_store_usblog_notify(type, (char *)param1); else if (type == NOTIFY_USBSTATE) state_store_usblog_notify(type, (char *)param1); else if (type == NOTIFY_PORT_CONNECT || type == NOTIFY_PORT_DISCONNECT || type == NOTIFY_PORT_CLASS || type == NOTIFY_PORT_CLASS_BLOCK) port_store_usblog_notify(type, param1, param2); else if (type == NOTIFY_PCM_PLAYBACK || type == NOTIFY_PCM_CAPTURE) pcm_store_usblog_notify(type, (int *)param1); else if (type == NOTIFY_EXTRA) extra_store_usblog_notify(type, (int *)param1); else pr_err("%s type error %d\n", __func__, type); spin_unlock_irqrestore(&usblog_root.usblog_lock, flags); } EXPORT_SYMBOL(store_usblog_notify); void store_ccic_version(unsigned char *hw, unsigned char *sw_main, unsigned char *sw_boot) { if (!hw || !sw_main || !sw_boot) { pr_err("%s null buffer\n", __func__); return; } memcpy(&usblog_root.ccic_ver.hw_version, hw, 4); memcpy(&usblog_root.ccic_ver.sw_main, sw_main, 3); memcpy(&usblog_root.ccic_ver.sw_boot, sw_boot, 1); } EXPORT_SYMBOL(store_ccic_version); void store_ccic_bin_version(const unsigned char *sw_main, const unsigned char *sw_boot) { if (!sw_main || !sw_boot) { pr_err("%s null buffer\n", __func__); return; } memcpy(&usblog_root.ccic_bin_ver.sw_main, sw_main, 3); memcpy(&usblog_root.ccic_bin_ver.sw_boot, sw_boot, 1); } EXPORT_SYMBOL(store_ccic_bin_version); unsigned long long show_ccic_version(void) { unsigned long long ret = 0; memcpy(&ret, &usblog_root.ccic_ver, sizeof(unsigned long long)); return ret; } EXPORT_SYMBOL(show_ccic_version); int register_usblog_proc(void) { int ret = 0; struct otg_notify *o_notify = get_otg_notify(); if (usblog_root.init) { pr_err("%s already registered\n", __func__); if (o_notify != NULL) goto err; } spin_lock_init(&usblog_root.usblog_lock); usblog_root.usblog_index = USBLOG_INDEX; usblog_root.init = 1; proc_create("usblog", 0444, NULL, &usblog_proc_fops); usblog_root.usblog_buffer = kzalloc(sizeof(struct usblog_buf), GFP_KERNEL); if (!usblog_root.usblog_buffer) { ret = -ENOMEM; goto err; } usblog_root.usblog_vm_buffer = vzalloc(sizeof(struct usblog_vm_buf)); if (!usblog_root.usblog_vm_buffer) { ret = -ENOMEM; goto err1; } pr_info("%s size=%zu\n", __func__, sizeof(struct usblog_buf)); return ret; err1: kfree(usblog_root.usblog_buffer); usblog_root.usblog_buffer = NULL; err: pr_err("%s error\n", __func__); return ret; } EXPORT_SYMBOL(register_usblog_proc); void unregister_usblog_proc(void) { vfree(usblog_root.usblog_vm_buffer); usblog_root.usblog_vm_buffer = NULL; kfree(usblog_root.usblog_buffer); usblog_root.usblog_buffer = NULL; remove_proc_entry("usblog", NULL); usblog_root.init = 0; } EXPORT_SYMBOL(unregister_usblog_proc);