#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/kobject.h>
#include <linux/delay.h>
/* For build single module using (Ex: ONL platform) */
#include <linux/module.h>
#include "io_expander.h"
#include "transceiver.h"


/* ========== Register EEPROM address mapping ==========
 */
struct eeprom_map_s eeprom_map_sfp = {
    .addr_br           =0x50,  .page_br           =-1,  .offset_br           =12,   .length_br           =1,
    .addr_cdr          =-1,    .page_cdr          =-1,  .offset_cdr          =-1,   .length_cdr          =-1,
    .addr_comp_rev     =0x50,  .page_comp_rev     =-1,  .offset_comp_rev     =94,   .length_comp_rev     =1,
    .addr_connector    =0x50,  .page_connector    =-1,  .offset_connector    =2,    .length_connector    =1,
    .addr_diag_type    =0x50,  .page_diag_type    =-1,  .offset_diag_type    =92 ,  .length_diag_type    =1,
    .addr_extbr        =-1,    .page_extbr        =-1,  .offset_extbr        =-1,   .length_extbr        =-1,
    .addr_ext_id       =0x50,  .page_ext_id       =-1,  .offset_ext_id       =1,    .length_ext_id       =1,
    .addr_id           =0x50,  .page_id           =-1,  .offset_id           =0,    .length_id           =1,
    .addr_len_sm       =0x50,  .page_len_sm       =-1,  .offset_len_sm       =15,   .length_len_sm       =1,
    .addr_len_smf      =0x50,  .page_len_smf      =-1,  .offset_len_smf      =14,   .length_len_smf      =1,
    .addr_len_om1      =0x50,  .page_len_om1      =-1,  .offset_len_om1      =17,   .length_len_om1      =1,
    .addr_len_om2      =0x50,  .page_len_om2      =-1,  .offset_len_om2      =16,   .length_len_om2      =1,
    .addr_len_om3      =0x50,  .page_len_om3      =-1,  .offset_len_om3      =19,   .length_len_om3      =1,
    .addr_len_om4      =0x50,  .page_len_om4      =-1,  .offset_len_om4      =18,   .length_len_om4      =1,
    .addr_option       =0x50,  .page_option       =-1,  .offset_option       =64,   .length_option       =2,
    .addr_rate_id      =0x50,  .page_rate_id      =-1,  .offset_rate_id      =13,   .length_rate_id      =1,
    .addr_rx_am        =-1,    .page_rx_am        =-1,  .offset_rx_am        =-1,   .length_rx_am        =-1,
    .addr_rx_em        =0x51,  .page_rx_em        =-1,  .offset_rx_em        =115,  .length_rx_em        =1,
    .addr_rx_los       =-1,    .page_rx_los       =-1,  .offset_rx_los       =-1,   .length_rx_los       =-1,
    .addr_rx_power     =0x51,  .page_rx_power     =-1,  .offset_rx_power     =104,  .length_rx_power     =2,
    .addr_soft_rs0     =0x51,  .page_soft_rs0     =-1,  .offset_soft_rs0     =110,  .length_soft_rs0     =1,
    .addr_soft_rs1     =0x51,  .page_soft_rs1     =-1,  .offset_soft_rs1     =118,  .length_soft_rs0     =1,
    .addr_temp         =0x51,  .page_temp         =-1,  .offset_temp         =96,   .length_temp         =2,
    .addr_trancomp     =0x50,  .page_trancomp     =-1,  .offset_trancomp     =3,    .length_trancomp     =8,
    .addr_trancomp_ext =0x50,  .page_trancomp_ext =-1,  .offset_trancomp_ext =36,   .length_trancomp_ext =1,
    .addr_tx_bias      =0x51,  .page_tx_bias      =-1,  .offset_tx_bias      =100,  .length_tx_bias      =2,
    .addr_tx_disable   =-1,    .page_tx_disable   =-1,  .offset_tx_disable   =-1,   .length_tx_disable   =-1,
    .addr_tx_eq        =0x51,  .page_tx_eq        =-1,  .offset_tx_eq        =114,  .length_tx_eq        =1,
    .addr_tx_fault     =-1,    .page_tx_fault     =-1,  .offset_tx_fault     =-1,   .length_tx_fault     =-1,
    .addr_tx_power     =0x51,  .page_tx_power     =-1,  .offset_tx_power     =102,  .length_tx_power     =2,
    .addr_vendor_name  =0x50,  .page_vendor_name  =-1,  .offset_vendor_name  =20,   .length_vendor_name  =16,
    .addr_vendor_pn    =0x50,  .page_vendor_pn    =-1,  .offset_vendor_pn    =40,   .length_vendor_pn    =16,
    .addr_vendor_rev   =0x50,  .page_vendor_rev   =-1,  .offset_vendor_rev   =56,   .length_vendor_rev   =4,
    .addr_vendor_sn    =0x50,  .page_vendor_sn    =-1,  .offset_vendor_sn    =68,   .length_vendor_sn    =16,
    .addr_voltage      =0x51,  .page_voltage      =-1,  .offset_voltage      =98,   .length_voltage      =2,
    .addr_wavelength   =0x50,  .page_wavelength   =-1,  .offset_wavelength   =60,   .length_wavelength   =2,
};

struct eeprom_map_s eeprom_map_qsfp = {
    .addr_br           =0x50,  .page_br           =0,   .offset_br           =140,  .length_br           =1,
    .addr_cdr          =-1,    .page_cdr          =-1,  .offset_cdr          =-1,   .length_cdr          =-1,
    .addr_comp_rev     =0x50,  .page_comp_rev     =-1,  .offset_comp_rev     =1,    .length_comp_rev     =1,
    .addr_connector    =0x50,  .page_connector    =0,   .offset_connector    =130,  .length_connector    =1,
    .addr_diag_type    =0x50,  .page_diag_type    =0,   .offset_diag_type    =220,  .length_diag_type    =1,
    .addr_extbr        =0x50,  .page_extbr        =0,   .offset_extbr        =222,  .length_extbr        =1,
    .addr_ext_id       =0x50,  .page_ext_id       =0,   .offset_ext_id       =129,  .length_ext_id       =1,
    .addr_id           =0x50,  .page_id           =0,   .offset_id           =128,  .length_id           =1,
    .addr_len_sm       =-1,    .page_len_sm       =-1,  .offset_len_sm       =-1,   .length_len_sm       =-1,
    .addr_len_smf      =0x50,  .page_len_smf      =0,   .offset_len_smf      =142,  .length_len_smf      =1,
    .addr_len_om1      =0x50,  .page_len_om1      =0,   .offset_len_om1      =145,  .length_len_om1      =1,
    .addr_len_om2      =0x50,  .page_len_om2      =0,   .offset_len_om2      =144,  .length_len_om2      =1,
    .addr_len_om3      =0x50,  .page_len_om3      =0,   .offset_len_om3      =143,  .length_len_om3      =1,
    .addr_len_om4      =0x50,  .page_len_om4      =0,   .offset_len_om4      =146,  .length_len_om4      =1,
    .addr_option       =0x50,  .page_option       =0,   .offset_option       =193,  .length_option       =3,
    .addr_rate_id      =-1,    .page_rate_id      =-1,  .offset_rate_id      =-1,   .length_rate_id      =-1,
    .addr_rx_am        =-1,    .page_rx_am        =-1,  .offset_rx_am        =-1,   .length_rx_am        =-1,
    .addr_rx_em        =-1,    .page_rx_em        =-1,  .offset_rx_em        =-1,   .length_rx_em        =-1,
    .addr_rx_los       =0x50,  .page_rx_los       =-1,  .offset_rx_los       =3,    .length_rx_los       =1,
    .addr_rx_power     =0x50,  .page_rx_power     =-1,  .offset_rx_power     =34,   .length_rx_power     =8,
    .addr_soft_rs0     =-1,    .page_soft_rs0     =-1,  .offset_soft_rs0     =-1,   .length_soft_rs0     =-1,
    .addr_soft_rs1     =-1,    .page_soft_rs1     =-1,  .offset_soft_rs1     =-1,   .length_soft_rs0     =-1,
    .addr_temp         =0x50,  .page_temp         =-1,  .offset_temp         =22,   .length_temp         =2,
    .addr_trancomp     =0x50,  .page_trancomp     =0,   .offset_trancomp     =131,  .length_trancomp     =8,
    .addr_trancomp_ext =0x50,  .page_trancomp_ext =0,   .offset_trancomp_ext =192,  .length_trancomp_ext =1,
    .addr_tx_bias      =0x50,  .page_tx_bias      =-1,  .offset_tx_bias      =42,   .length_tx_bias      =8,
    .addr_tx_disable   =0x50,  .page_tx_disable   =-1,  .offset_tx_disable   =86,   .length_tx_disable   =1,
    .addr_tx_eq        =-1,    .page_tx_eq        =-1,  .offset_tx_eq        =-1,   .length_tx_eq        =-1,
    .addr_tx_fault     =0x50,  .page_tx_fault     =-1,  .offset_tx_fault     =4,    .length_tx_fault     =1,
    .addr_tx_power     =0x50,  .page_tx_power     =-1,  .offset_tx_power     =50,   .length_tx_power     =8,
    .addr_vendor_name  =0x50,  .page_vendor_name  =0,   .offset_vendor_name  =148,  .length_vendor_name  =16,
    .addr_vendor_pn    =0x50,  .page_vendor_pn    =0,   .offset_vendor_pn    =168,  .length_vendor_pn    =16,
    .addr_vendor_rev   =0x50,  .page_vendor_rev   =0,   .offset_vendor_rev   =184,  .length_vendor_rev   =2,
    .addr_vendor_sn    =0x50,  .page_vendor_sn    =0,   .offset_vendor_sn    =196,  .length_vendor_sn    =16,
    .addr_voltage      =0x50,  .page_voltage      =-1,  .offset_voltage      =26,   .length_voltage      =2,
    .addr_wavelength   =0x50,  .page_wavelength   =0,   .offset_wavelength   =186,  .length_wavelength   =2,
};

struct eeprom_map_s eeprom_map_qsfp28 = {
    .addr_br           =0x50,  .page_br           =0,   .offset_br           =140,  .length_br           =1,
    .addr_cdr          =0x50,  .page_cdr          =-1,  .offset_cdr          =98,   .length_cdr          =1,
    .addr_comp_rev     =0x50,  .page_comp_rev     =-1,  .offset_comp_rev     =1,    .length_comp_rev     =1,
    .addr_connector    =0x50,  .page_connector    =0,   .offset_connector    =130,  .length_connector    =1,
    .addr_diag_type    =0x50,  .page_diag_type    =0,   .offset_diag_type    =220,  .length_diag_type    =1,
    .addr_extbr        =0x50,  .page_extbr        =0,   .offset_extbr        =222,  .length_extbr        =1,
    .addr_ext_id       =0x50,  .page_ext_id       =0,   .offset_ext_id       =129,  .length_ext_id       =1,
    .addr_id           =0x50,  .page_id           =0,   .offset_id           =128,  .length_id           =1,
    .addr_len_sm       =-1,    .page_len_sm       =-1,  .offset_len_sm       =-1,   .length_len_sm       =-1,
    .addr_len_smf      =0x50,  .page_len_smf      =0,   .offset_len_smf      =142,  .length_len_smf      =1,
    .addr_len_om1      =0x50,  .page_len_om1      =0,   .offset_len_om1      =145,  .length_len_om1      =1,
    .addr_len_om2      =0x50,  .page_len_om2      =0,   .offset_len_om2      =144,  .length_len_om2      =1,
    .addr_len_om3      =0x50,  .page_len_om3      =0,   .offset_len_om3      =143,  .length_len_om3      =1,
    .addr_len_om4      =0x50,  .page_len_om4      =0,   .offset_len_om4      =146,  .length_len_om4      =1,
    .addr_option       =0x50,  .page_option       =0,   .offset_option       =193,  .length_option       =3,
    .addr_rate_id      =-1,    .page_rate_id      =-1,  .offset_rate_id      =-1,   .length_rate_id      =-1,
    .addr_rx_am        =0x50,  .page_rx_am        =3,   .offset_rx_am        =238,  .length_rx_am        =2,
    .addr_rx_em        =0x50,  .page_rx_em        =3,   .offset_rx_em        =236,  .length_rx_em        =2,
    .addr_rx_los       =0x50,  .page_rx_los       =-1,  .offset_rx_los       =3,    .length_rx_los       =1,
    .addr_rx_power     =0x50,  .page_rx_power     =-1,  .offset_rx_power     =34,   .length_rx_power     =8,
    .addr_soft_rs0     =-1,    .page_soft_rs0     =-1,  .offset_soft_rs0     =-1,   .length_soft_rs0     =-1,
    .addr_soft_rs1     =-1,    .page_soft_rs1     =-1,  .offset_soft_rs1     =-1,   .length_soft_rs0     =-1,
    .addr_temp         =0x50,  .page_temp         =-1,  .offset_temp         =22,   .length_temp         =2,
    .addr_trancomp     =0x50,  .page_trancomp     =0,   .offset_trancomp     =131,  .length_trancomp     =8,
    .addr_trancomp_ext =0x50,  .page_trancomp_ext =0,   .offset_trancomp_ext =192,  .length_trancomp_ext =1,
    .addr_tx_bias      =0x50,  .page_tx_bias      =-1,  .offset_tx_bias      =42,   .length_tx_bias      =8,
    .addr_tx_disable   =0x50,  .page_tx_disable   =-1,  .offset_tx_disable   =86,   .length_tx_disable   =1,
    .addr_tx_eq        =0x50,  .page_tx_eq        =3,   .offset_tx_eq        =234,  .length_tx_eq        =2,
    .addr_tx_fault     =0x50,  .page_tx_fault     =-1,  .offset_tx_fault     =4,    .length_tx_fault     =1,
    .addr_tx_power     =0x50,  .page_tx_power     =-1,  .offset_tx_power     =50,   .length_tx_power     =8,
    .addr_vendor_name  =0x50,  .page_vendor_name  =0,   .offset_vendor_name  =148,  .length_vendor_name  =16,
    .addr_vendor_pn    =0x50,  .page_vendor_pn    =0,   .offset_vendor_pn    =168,  .length_vendor_pn    =16,
    .addr_vendor_rev   =0x50,  .page_vendor_rev   =0,   .offset_vendor_rev   =184,  .length_vendor_rev   =2,
    .addr_vendor_sn    =0x50,  .page_vendor_sn    =0,   .offset_vendor_sn    =196,  .length_vendor_sn    =16,
    .addr_voltage      =0x50,  .page_voltage      =-1,  .offset_voltage      =26,   .length_voltage      =2,
    .addr_wavelength   =0x50,  .page_wavelength   =0,   .offset_wavelength   =186,  .length_wavelength   =2,
};


/* ========== Utility Functions ==========
 */
static int
get_bit(uint8_t origin_byte, int bit_shift) {
    return (int)((origin_byte >> bit_shift) & 0x1);
}

static int
transform_word_to_int(uint8_t hight_byte,
                      uint8_t low_byte) {
    return ((((int)hight_byte) << 8) + (int)low_byte);
}

void
alarm_msg_2_user(struct transvr_obj_s *self,
                 char *emsg) {

    SWPS_ERR("%s on %s.\n", emsg, self->swp_name);
}
EXPORT_SYMBOL(alarm_msg_2_user);

/* ========== Private functions ==========
 */
static int
_reload_transvr_obj(struct transvr_obj_s *self,int new_type);

static int
reload_transvr_obj(struct transvr_obj_s *self,int new_type);

static int
_is_transvr_support_ctle(struct transvr_obj_s *self);

static int
_transvr_init_handler(struct transvr_obj_s *self);

int
_transvr_clean_handler(struct transvr_obj_s *self);

int
_sfp_detect_class_by_1g_ethernet(struct transvr_obj_s* self);


void
lock_transvr_obj(struct transvr_obj_s *self) {

    mutex_lock(&self->lock);
    self->curr_page = VAL_TRANSVR_PAGE_FREE;
}
EXPORT_SYMBOL(lock_transvr_obj);


void
unlock_transvr_obj(struct transvr_obj_s *self) {

    self->curr_page = VAL_TRANSVR_PAGE_FREE;
    mutex_unlock(&self->lock);
}
EXPORT_SYMBOL(unlock_transvr_obj);


static int
_check_by_mode(struct transvr_obj_s *self,
               int  (*attr_update_func)(struct transvr_obj_s *self, int show_err),
               char *caller_name){

    int return_val = ERR_TRANSVR_UNEXCPT;

    switch (self->mode){
        case TRANSVR_MODE_POLLING:
            switch (self->state){
                case STATE_TRANSVR_CONNECTED:
                    goto ok_check_by_mode_1;
                case STATE_TRANSVR_NEW:
                case STATE_TRANSVR_INIT:
                    return ERR_TRANSVR_UNINIT;
                case STATE_TRANSVR_DISCONNECTED:
                    return ERR_TRANSVR_UNPLUGGED;
                case STATE_TRANSVR_UNEXCEPTED:
                    return ERR_TRANSVR_ABNORMAL;
                case STATE_TRANSVR_ISOLATED:
                    return ERR_TRNASVR_BE_ISOLATED;
                default:
                    goto err_check_by_mode_1;
            }
            goto ok_check_by_mode_1;

        case TRANSVR_MODE_DIRECT:
            return_val = self->fsm_4_direct(self, caller_name);
            if (return_val < 0){
                return return_val;
            }
            goto ok_check_by_mode_1;

        default:
            goto err_check_by_mode_1;
    }
    goto ok_check_by_mode_1;

ok_check_by_mode_1:
    return attr_update_func(self, 0);

err_check_by_mode_1:
    SWPS_INFO("_check_by_mode: mode:%d state:%d\n", self->mode, self->state);
    return ERR_TRANSVR_UNEXCPT;
}


static void
_transvr_clean_retry(struct transvr_obj_s *self) {
    self->retry = 0;
}


static int
_transvr_handle_retry(struct transvr_obj_s *self, int retry) {
    /* Return: 0: keep retry
     *        -1: stop retry
     */
    if (self->retry == 0) {
        self->retry = retry;
    }
    self->retry -= 1;
    if (self->retry <= 0) {
        _transvr_clean_retry(self);
        return -1;
    }
    return 0;
}


static int
_common_setup_page(struct transvr_obj_s *self,
                   int addr,
                   int page,
                   int offset,
                   int len,
                   int show_e) {
    /* return:
     *    0 : OK
     *   -1 : EEPROM settings incorrect
     *   -2 : I2C R/W failure
     *   -3 : Undefined case
     */
    int retval = DEBUG_TRANSVR_INT_VAL;
    char *emsg = DEBUG_TRANSVR_STR_VAL;

    /* Check */
    if ((addr < 0) || (offset < 0) || (len < 0)) {
        emsg   = "EEPROM settings incorrect";
        retval = -1;
        goto err_common_setup_page;
    }
    /* Case1: continue access */
    if ((self->i2c_client_p->addr == addr) &&
        (self->curr_page == page)) {
        return 0;
    }
    self->i2c_client_p->addr = addr;
    /* Case2: select lower page */
    if (page == -1) {
        self->curr_page = page;
        return 0;
    }
    /* Case3: select upper page */
    if (page >= 0) {
        goto upper_common_setup_page;
    }
    /* Unexpected case */
    show_e = 1;
    emsg   = "Unexpected case";
    retval = -3;
    goto err_common_setup_page;

upper_common_setup_page:
    if (i2c_smbus_write_byte_data(self->i2c_client_p,
                                  VAL_TRANSVR_PAGE_SELECT_OFFSET,
                                  page) < 0) {
        emsg   = "I2C R/W failure";
        retval = -2;
        goto err_common_setup_page;
    }
    self->curr_page = page;
    mdelay(VAL_TRANSVR_PAGE_SELECT_DELAY);
    return 0;

err_common_setup_page:
    if (show_e) {
        SWPS_INFO("%s: %s", __func__, emsg);
        SWPS_INFO("%s: <addr>:0x%02x <page>:%d <offs>:%d <len>:%d\n",
                __func__, addr, page, offset, len);
    }
    return retval;
}

/*
static int
_common_setup_password(struct transvr_obj_s *self,
                       int addr,
                       int page,
                       int offs,
                       uint8_t pwd[4],
                       int show_e) {
    int   i    = 0;
    int   err  = DEBUG_TRANSVR_INT_VAL;
    char *emsg = DEBUG_TRANSVR_STR_VAL;

    err = _common_setup_page(self, addr, page, offs, 4, show_e);
    if (err < 0){
        emsg = "setup EEPROM page fail";
        goto err_common_setup_password;
    }
    for (i=0; i<4; i++) {
        err = i2c_smbus_write_byte_data(self->i2c_client_p,
                                        (offs + i),
                                        pwd[i]);
        if (err < 0){
            emsg = "I2C R/W fail!";
            goto err_common_setup_password;
        }
    }
    return 0;

err_common_setup_password:
    if (show_e) {
        SWPS_INFO("%s: %s <err>:%d\n", __func__, emsg,  err);
    }
    return ERR_TRANSVR_UPDATE_FAIL;
}
*/

static int
_common_update_uint8_attr(struct transvr_obj_s *self,
                          int addr,
                          int page,
                          int offset,
                          int len,
                          uint8_t *buf,
                          char *caller,
                          int show_e){

    int   i;
    int   err  = DEBUG_TRANSVR_INT_VAL;
    char *emsg = DEBUG_TRANSVR_STR_VAL;

    err = _common_setup_page(self, addr, page, offset, len, show_e);
    if (err < 0){
        emsg = "setup EEPROM page fail";
        goto err_common_update_uint8_attr;
    }
    for (i=0; i<len; i++) {
        err = i2c_smbus_read_byte_data(self->i2c_client_p, (offset + i));
        if (err < 0){
            emsg = "I2C R/W fail!";
            goto err_common_update_uint8_attr;
        }
        buf[i] = err;
    }
    return 0;

err_common_update_uint8_attr:
    if (show_e) {
        SWPS_INFO("%s: %s <caller>:%s <err>:%d\n",
                  __func__, emsg, caller, err);
    }
    buf[0] = DEBUG_TRANSVR_HEX_VAL;
    return ERR_TRANSVR_UPDATE_FAIL;
}


static int
_common_update_int_attr(struct transvr_obj_s *self,
                        int addr,
                        int page,
                        int offset,
                        int len,
                        int *buf,
                        char *caller,
                        int show_e){

    int   i;
    int   err  = DEBUG_TRANSVR_INT_VAL;
    char *emsg = DEBUG_TRANSVR_STR_VAL;

    err = _common_setup_page(self, addr, page, offset, len, show_e);
    if (err < 0){
        emsg = "setup EEPROM page fail";
        goto err_common_update_int_attr;
    }
    for (i=0; i<len; i++) {
        err = i2c_smbus_read_byte_data(self->i2c_client_p, (offset + i));
        if (err < 0){
            emsg = "I2C R/W fail!";
            goto err_common_update_int_attr;
        }
        buf[i] = (int)err;
    }
    return 0;

err_common_update_int_attr:
    if (show_e) {
        SWPS_INFO("%s: %s <caller>:%s <err>:%d\n",
                  __func__, emsg, caller, err);
    }
    buf[0] = DEBUG_TRANSVR_INT_VAL;
    return ERR_TRANSVR_UPDATE_FAIL;
}


static int
_common_update_string_attr(struct transvr_obj_s *self,
                           int addr,
                           int page,
                           int offset,
                           int len,
                           char buf[],
                           char *caller,
                           int show_e){

    int   i;
    int   err  = DEBUG_TRANSVR_INT_VAL;
    char *emsg = DEBUG_TRANSVR_STR_VAL;

    err = _common_setup_page(self, addr, page, offset, len, show_e);
    if (err < 0){
        emsg = "setup EEPROM page fail";
        goto err_common_update_string_attr;
    }
    for (i=0; i<len; i++) {
        err = i2c_smbus_read_byte_data(self->i2c_client_p, (offset + i));
        if (err < 0){
            emsg = "I2C R/W fail!";
            goto err_common_update_string_attr;
        }
        buf[i] = (char)err;
    }
    return 0;

err_common_update_string_attr:
    if (show_e) {
        SWPS_INFO("%s: %s <caller>:%s <err>:%d\n",
                  __func__, emsg, caller, err);
    }
    buf[0] = 'e';
    return ERR_TRANSVR_UPDATE_FAIL;
}


static int
_common_set_uint8_attr(struct transvr_obj_s *self,
                       int addr,
                       int page,
                       int offset,
                       uint8_t update,
                       uint8_t *buf,
                       char *caller,
                       int show_e){
    int   len  = 1;
    int   err  = DEBUG_TRANSVR_INT_VAL;
    char *emsg = DEBUG_TRANSVR_STR_VAL;

    if ((*buf) == update){
        return 0;
    }
    err = _common_setup_page(self, addr, page, offset, len, show_e);
    if (err < 0){
        emsg = "setup EEPROM page fail";
        goto err_common_set_uint8_attr_1;
    }
    err = i2c_smbus_write_byte_data(self->i2c_client_p,
                                    offset,
                                    update);
    if (err < 0){
        emsg = "I2C R/W fail!";
        goto err_common_set_uint8_attr_1;
    }
    (*buf) = update;
    return 0;

err_common_set_uint8_attr_1:
    if (show_e) {
        SWPS_INFO("%s: %s <caller>:%s <err>:%d\n",
                  __func__, emsg, caller, err);
    }
    return ERR_TRANSVR_UPDATE_FAIL;
}


static int
_common_set_uint8_array(struct transvr_obj_s *self,
                       int addr,
                       int page,
                       int offs,
                       int len,
                       uint8_t update[],
                       uint8_t buf[],
                       char *caller,
                       int show_e){
    int   i    = 0;
    int   err  = DEBUG_TRANSVR_INT_VAL;
    char *emsg = DEBUG_TRANSVR_STR_VAL;

    err = _common_setup_page(self, addr, page, offs, len, show_e);
    if (err < 0){
        emsg = "setup EEPROM page fail";
        goto err_common_set_uint8_attr_1;
    }
    for (i=0; i<len; i++) {
        if (buf[i] == update[i]){
            continue;
        }
        err = i2c_smbus_write_byte_data(self->i2c_client_p,
                                        (offs + i),
                                        update[i]);
        if (err < 0){
            emsg = "I2C R/W fail!";
            goto err_common_set_uint8_attr_1;
        }
        buf[i] = update[i];
    }
    return 0;

err_common_set_uint8_attr_1:
    if (show_e) {
        SWPS_INFO("%s: %s <caller>:%s <err>:%d <i>:%d\n",
                  __func__, emsg, caller, err, i);
    }
    return ERR_TRANSVR_UPDATE_FAIL;
}


static int
_common_update_attr_id(struct transvr_obj_s *self,
                       int show_err){
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_id,
                                     self->eeprom_map_p->page_id,
                                     self->eeprom_map_p->offset_id,
                                     self->eeprom_map_p->length_id,
                                     &(self->id),
                                     "_common_update_attr_id",
                                     show_err);
}


static int
_common_update_attr_extended_id(struct transvr_obj_s *self,
                                int show_err){
    return  _common_update_uint8_attr(self,
                                      self->eeprom_map_p->addr_ext_id,
                                      self->eeprom_map_p->page_ext_id,
                                      self->eeprom_map_p->offset_ext_id,
                                      self->eeprom_map_p->length_ext_id,
                                      &(self->ext_id),
                                      "_common_update_attr_extended_id",
                                      show_err);
}


static int
_common_update_attr_connector(struct transvr_obj_s *self,
                              int show_err){
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_connector,
                                     self->eeprom_map_p->page_connector,
                                     self->eeprom_map_p->offset_connector,
                                     self->eeprom_map_p->length_connector,
                                     &(self->connector),
                                     "_common_update_attr_connector",
                                     show_err);
}


static int
_common_update_attr_transvr_comp(struct transvr_obj_s *self,
                                 int show_err){
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_trancomp,
                                     self->eeprom_map_p->page_trancomp,
                                     self->eeprom_map_p->offset_trancomp,
                                     self->eeprom_map_p->length_trancomp,
                                     self->transvr_comp,
                                     "_common_update_attr_transvr_comp",
                                     show_err);
}


static int
_common_update_attr_transvr_comp_ext(struct transvr_obj_s *self,
                                     int show_err){
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_trancomp_ext,
                                     self->eeprom_map_p->page_trancomp_ext,
                                     self->eeprom_map_p->offset_trancomp_ext,
                                     self->eeprom_map_p->length_trancomp_ext,
                                     &(self->transvr_comp_ext),
                                     "_common_update_attr_transvr_comp_ext",
                                     show_err);
}


static int
_common_update_attr_vendor_name(struct transvr_obj_s *self,
                                int show_err){
    return _common_update_string_attr(self,
                                      self->eeprom_map_p->addr_vendor_name,
                                      self->eeprom_map_p->page_vendor_name,
                                      self->eeprom_map_p->offset_vendor_name,
                                      self->eeprom_map_p->length_vendor_name,
                                      self->vendor_name,
                                      "_common_update_attr_vendor_name",
                                      show_err);
}


static int
_common_update_attr_vendor_pn(struct transvr_obj_s *self,
                              int show_err){
    return _common_update_string_attr(self,
                                      self->eeprom_map_p->addr_vendor_pn,
                                      self->eeprom_map_p->page_vendor_pn,
                                      self->eeprom_map_p->offset_vendor_pn,
                                      self->eeprom_map_p->length_vendor_pn,
                                      self->vendor_pn,
                                      "_common_update_attr_vendor_pn",
                                      show_err);
}


static int
_common_update_attr_vendor_rev(struct transvr_obj_s *self,
                               int show_err){
    return _common_update_string_attr(self,
                                      self->eeprom_map_p->addr_vendor_rev,
                                      self->eeprom_map_p->page_vendor_rev,
                                      self->eeprom_map_p->offset_vendor_rev,
                                      self->eeprom_map_p->length_vendor_rev,
                                      self->vendor_rev,
                                      "_common_update_attr_vendor_rev",
                                      show_err);
}


static int
_common_update_attr_vendor_sn(struct transvr_obj_s *self,
                              int show_err){
    return _common_update_string_attr(self,
                                      self->eeprom_map_p->addr_vendor_sn,
                                      self->eeprom_map_p->page_vendor_sn,
                                      self->eeprom_map_p->offset_vendor_sn,
                                      self->eeprom_map_p->length_vendor_sn,
                                      self->vendor_sn,
                                      "_common_update_attr_vendor_sn",
                                      show_err);
}


static int
_common_update_attr_br(struct transvr_obj_s *self,
                       int show_err){
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_br,
                                     self->eeprom_map_p->page_br,
                                     self->eeprom_map_p->offset_br,
                                     self->eeprom_map_p->length_br,
                                     &(self->br),
                                     "_common_update_attr_br",
                                     show_err);
}


static int
_common_update_attr_len_smf(struct transvr_obj_s *self,
                            int show_err){
    return _common_update_int_attr(self,
                                   self->eeprom_map_p->addr_len_smf,
                                   self->eeprom_map_p->page_len_smf,
                                   self->eeprom_map_p->offset_len_smf,
                                   self->eeprom_map_p->length_len_smf,
                                   &(self->len_smf),
                                   "_common_update_attr_len_smf",
                                   show_err);
}


static int
_common_update_attr_len_om1(struct transvr_obj_s *self,
                            int show_err){
    return _common_update_int_attr(self,
                                   self->eeprom_map_p->addr_len_om1,
                                   self->eeprom_map_p->page_len_om1,
                                   self->eeprom_map_p->offset_len_om1,
                                   self->eeprom_map_p->length_len_om1,
                                   &(self->len_om1),
                                   "_common_update_attr_len_om1",
                                   show_err);
}

static int
_common_update_attr_len_om2(struct transvr_obj_s *self,
                            int show_err){
    return _common_update_int_attr(self,
                                   self->eeprom_map_p->addr_len_om2,
                                   self->eeprom_map_p->page_len_om2,
                                   self->eeprom_map_p->offset_len_om2,
                                   self->eeprom_map_p->length_len_om2,
                                   &(self->len_om2),
                                   "_common_update_attr_len_om2",
                                   show_err);
}

static int
_common_update_attr_len_om3(struct transvr_obj_s *self,
                            int show_err){
    return _common_update_int_attr(self,
                                   self->eeprom_map_p->addr_len_om3,
                                   self->eeprom_map_p->page_len_om3,
                                   self->eeprom_map_p->offset_len_om3,
                                   self->eeprom_map_p->length_len_om3,
                                   &(self->len_om3),
                                   "_common_update_attr_len_om3",
                                   show_err);
}


static int
_common_update_attr_len_om4(struct transvr_obj_s *self,
                            int show_err){
    return _common_update_int_attr(self,
                                   self->eeprom_map_p->addr_len_om4,
                                   self->eeprom_map_p->page_len_om4,
                                   self->eeprom_map_p->offset_len_om4,
                                   self->eeprom_map_p->length_len_om4,
                                   &(self->len_om4),
                                   "_common_update_attr_len_om4",
                                   show_err);
}


static int
_common_update_attr_option(struct transvr_obj_s *self,
                           int show_err){
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_option,
                                     self->eeprom_map_p->page_option,
                                     self->eeprom_map_p->offset_option,
                                     self->eeprom_map_p->length_option,
                                     self->option,
                                     "_common_update_attr_option",
                                     show_err);
}


static int
_common_update_attr_comp_rev(struct transvr_obj_s *self,
                             int show_err){
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_comp_rev,
                                     self->eeprom_map_p->page_comp_rev,
                                     self->eeprom_map_p->offset_comp_rev,
                                     self->eeprom_map_p->length_comp_rev,
                                     &(self->comp_rev),
                                     "_common_update_attr_comp_rev",
                                     show_err);
}


static int
_common_update_attr_diag_type(struct transvr_obj_s *self,
                              int show_err){
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_diag_type,
                                     self->eeprom_map_p->page_diag_type,
                                     self->eeprom_map_p->offset_diag_type,
                                     self->eeprom_map_p->length_diag_type,
                                     &(self->diag_type),
                                     "_common_update_attr_diag_type",
                                     show_err);
}


static int
_common_update_attr_wavelength(struct transvr_obj_s *self,
                               int show_err){
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_wavelength,
                                     self->eeprom_map_p->page_wavelength,
                                     self->eeprom_map_p->offset_wavelength,
                                     self->eeprom_map_p->length_wavelength,
                                     self->wavelength,
                                     "_common_update_attr_wavelength",
                                     show_err);
}


int
_common_get_option_value(struct transvr_obj_s *self,
                         int offset,
                         int bit_shift) {
    /* SFP:
     *  - option[0] = A0h / 64
     *  - option[1] = A0h / 65
     * QSFP:
     *  - option[0] = 00h / 193
     *  - option[1] = 00h / 194
     *  - option[2] = 00h / 195
     */
    return (self->option[offset] & (1 << bit_shift));
}


static int
_sfp_update_attr_len_sm(struct transvr_obj_s *self,
                        int show_err){
    return _common_update_int_attr(self,
                                   self->eeprom_map_p->addr_len_sm,
                                   self->eeprom_map_p->page_len_sm,
                                   self->eeprom_map_p->offset_len_sm,
                                   self->eeprom_map_p->length_len_sm,
                                   &(self->len_sm),
                                   "_common_update_attr_len_sm",
                                   show_err);
}


static int
_sfp_update_attr_rate_id(struct transvr_obj_s *self,
                         int show_err){
    return _common_update_int_attr(self,
                                   self->eeprom_map_p->addr_rate_id,
                                   self->eeprom_map_p->page_rate_id,
                                   self->eeprom_map_p->offset_rate_id,
                                   self->eeprom_map_p->length_rate_id,
                                   &(self->rate_id),
                                   "_sfp_update_attr_rate_id",
                                   show_err);
}


static int
_sfp_update_attr_soft_rs0(struct transvr_obj_s *self,
                          int show_err){
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_soft_rs0,
                                     self->eeprom_map_p->page_soft_rs0,
                                     self->eeprom_map_p->offset_soft_rs0,
                                     self->eeprom_map_p->length_soft_rs0,
                                     &(self->soft_rs0),
                                     "_sfp_update_attr_soft_rs0",
                                     show_err);
}


static int
_sfp_update_attr_soft_rs1(struct transvr_obj_s *self,
                          int show_err){
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_soft_rs1,
                                     self->eeprom_map_p->page_soft_rs1,
                                     self->eeprom_map_p->offset_soft_rs1,
                                     self->eeprom_map_p->length_soft_rs1,
                                     &(self->soft_rs1),
                                     "_sfp_update_attr_soft_rs1",
                                     show_err);
}


int
_sfp_is_diag_support(struct transvr_obj_s *self){

    uint8_t bit_mask = 0xC0; /* 1100 0000 */
    uint8_t en_val   = 0x40; /* 0100 0000 */
    uint8_t checkval = (self->diag_type & bit_mask);

    if (checkval == en_val) {
        return 1;
    }
    return 0;
}


static int
_sfp_update_attr_curr_temp(struct transvr_obj_s *self,
                           int show_err){

    if (!(_sfp_is_diag_support(self))) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_temp,
                                     self->eeprom_map_p->page_temp,
                                     self->eeprom_map_p->offset_temp,
                                     self->eeprom_map_p->length_temp,
                                     self->curr_temp,
                                     "_sfp_update_attr_curr_temp",
                                     show_err);
}


static int
_sfp_update_attr_curr_voltage(struct transvr_obj_s *self,
                              int show_err){

    if (!(_sfp_is_diag_support(self))) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_voltage,
                                     self->eeprom_map_p->page_voltage,
                                     self->eeprom_map_p->offset_voltage,
                                     self->eeprom_map_p->length_voltage,
                                     self->curr_voltage,
                                     "_sfp_update_attr_curr_voltage",
                                     show_err);
}


static int
_sfp_update_attr_curr_tx_bias(struct transvr_obj_s *self,
                              int show_err){

    if (!(_sfp_is_diag_support(self))) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_tx_bias,
                                     self->eeprom_map_p->page_tx_bias,
                                     self->eeprom_map_p->offset_tx_bias,
                                     self->eeprom_map_p->length_tx_bias,
                                     self->curr_tx_bias,
                                     "_sfp_update_attr_curr_tx_bias",
                                     show_err);
}


static int
_sfp_update_attr_curr_tx_power(struct transvr_obj_s *self,
                               int show_err){

    if (!(_sfp_is_diag_support(self))) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_tx_power,
                                     self->eeprom_map_p->page_tx_power,
                                     self->eeprom_map_p->offset_tx_power,
                                     self->eeprom_map_p->length_tx_power,
                                     self->curr_tx_power,
                                     "_sfp_update_attr_curr_tx_power",
                                     show_err);
}


static int
_sfp_update_attr_curr_rx_power(struct transvr_obj_s *self,
                               int show_err){

    if (!(_sfp_is_diag_support(self))) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_rx_power,
                                     self->eeprom_map_p->page_rx_power,
                                     self->eeprom_map_p->offset_rx_power,
                                     self->eeprom_map_p->length_rx_power,
                                     self->curr_rx_power,
                                     "_sfp_update_attr_curr_rx_power",
                                     show_err);
}


static int
_sfp_update_attr_rx_em(struct transvr_obj_s *self,
                       int show_err){

    if (!_is_transvr_support_ctle(self)) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_rx_em,
                                     self->eeprom_map_p->page_rx_em,
                                     self->eeprom_map_p->offset_rx_em,
                                     self->eeprom_map_p->length_rx_em,
                                     self->rx_em,
                                     "_sfp_update_attr_rx_em",
                                     show_err);
}


static int
_sfp_update_attr_tx_eq(struct transvr_obj_s *self,
                       int show_err){

    if (!_is_transvr_support_ctle(self)) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_tx_eq,
                                     self->eeprom_map_p->page_tx_eq,
                                     self->eeprom_map_p->offset_tx_eq,
                                     self->eeprom_map_p->length_tx_eq,
                                     self->tx_eq,
                                     "_sfp_update_attr_tx_eq",
                                     show_err);
}


static int
_qsfp_update_attr_cdr(struct transvr_obj_s *self,
                      int show_err){
    if (self->type != TRANSVR_TYPE_QSFP_28){
        self->cdr = DEBUG_TRANSVR_HEX_VAL;
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_cdr,
                                     self->eeprom_map_p->page_cdr,
                                     self->eeprom_map_p->offset_cdr,
                                     self->eeprom_map_p->length_cdr,
                                     &(self->cdr),
                                     "_common_update_attr_cdr",
                                     show_err);
}


static int
_qsfg_update_attr_extbr(struct transvr_obj_s *self,
                        int show_err) {
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_extbr,
                                     self->eeprom_map_p->page_extbr,
                                     self->eeprom_map_p->offset_extbr,
                                     self->eeprom_map_p->length_extbr,
                                     &(self->extbr),
                                     "_common_update_attr_extbr",
                                     show_err);
}


static int
_qsfp_is_diag_support(struct transvr_obj_s *self,
                      int diag_type) {
    /* Input Parm: diag_type
     * => 1 : temperature
     * => 2 : voltage
     * => 3 : tx relate
     * => 4 : rx relate
     */
    uint8_t mask_b2 = 0x04; /* 0000 0100 */
    uint8_t mask_b3 = 0x08; /* 0000 1000 */

    switch (diag_type) {
        case 1: /* temperature */
        case 2: /* voltage */
            /* Direct access target, because of spec not defined */
            return 1;
        case 3:
        case 4:
            /* [Note]
             *   Due to lot of transceiver vendor defined it not rigorously and
             *   consider of general support, we seem it as supported if there
             *   are bit-2 OR bit-3 defined by transceiver vendor.
             */
            if ( ((self->diag_type & mask_b2) == mask_b2 ) ||
                 ((self->diag_type & mask_b3) == mask_b3 ) ){
                return 1;
            }
            return 0;
        default:
            SWPS_INFO("%s: undefined diag_type:%d\n",
                      __func__, diag_type);
            break;
    }
    return 0;
}


int
_qsfp_is_implement_tx_disable(struct transvr_obj_s *self) {
    /*
     * 00h / Byte-195 / Bit-4
     */
    int byte = 2;
    int bit  = 4;
    return _common_get_option_value(self, byte, bit);
}


int
_qsfp_is_implement_tx_fault(struct transvr_obj_s *self) {
    /*
     * 00h / Byte-195 / Bit-3
     */
    int byte = 2;
    int bit  = 3;
    return _common_get_option_value(self, byte, bit);
}


static int
_qsfp_update_attr_curr_temp(struct transvr_obj_s *self,
                            int show_err){
    int diag_type = 1;

    if (!(_qsfp_is_diag_support(self, diag_type))) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_temp,
                                     self->eeprom_map_p->page_temp,
                                     self->eeprom_map_p->offset_temp,
                                     self->eeprom_map_p->length_temp,
                                     self->curr_temp,
                                     "_qsfp_update_attr_curr_temp",
                                     show_err);
}


static int
_qsfp_update_attr_curr_voltage(struct transvr_obj_s *self,
                               int show_err){
    int diag_type = 2;

    if (!(_qsfp_is_diag_support(self, diag_type))) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_voltage,
                                     self->eeprom_map_p->page_voltage,
                                     self->eeprom_map_p->offset_voltage,
                                     self->eeprom_map_p->length_voltage,
                                     self->curr_voltage,
                                     "_qsfp_update_attr_curr_voltage",
                                     show_err);
}


static int
_qsfp_update_attr_curr_tx_bias(struct transvr_obj_s *self,
                               int show_err){
    int diag_type = 3;

    if (!(_qsfp_is_diag_support(self, diag_type))) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_tx_bias,
                                     self->eeprom_map_p->page_tx_bias,
                                     self->eeprom_map_p->offset_tx_bias,
                                     self->eeprom_map_p->length_tx_bias,
                                     self->curr_tx_bias,
                                     "_qsfp_update_attr_curr_tx_bias",
                                     show_err);
}


static int
_qsfp_update_attr_curr_tx_power(struct transvr_obj_s *self,
                                int show_err){
    int diag_type = 3;

    if (!(_qsfp_is_diag_support(self, diag_type))) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_tx_power,
                                     self->eeprom_map_p->page_tx_power,
                                     self->eeprom_map_p->offset_tx_power,
                                     self->eeprom_map_p->length_tx_power,
                                     self->curr_tx_power,
                                     "_qsfp_update_attr_curr_tx_power",
                                     show_err);
}


static int
_qsfp_update_attr_curr_rx_power(struct transvr_obj_s *self,
                                int show_err){
    int diag_type = 4;

    if (!(_qsfp_is_diag_support(self, diag_type))) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_rx_power,
                                     self->eeprom_map_p->page_rx_power,
                                     self->eeprom_map_p->offset_rx_power,
                                     self->eeprom_map_p->length_rx_power,
                                     self->curr_rx_power,
                                     "_qsfp_update_attr_curr_rx_power",
                                     show_err);
}


static int
_qsfp_update_attr_soft_rx_los(struct transvr_obj_s *self,
                              int show_err){

    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_rx_los,
                                     self->eeprom_map_p->page_rx_los,
                                     self->eeprom_map_p->offset_rx_los,
                                     self->eeprom_map_p->length_rx_los,
                                     &(self->rx_los),
                                     "_qsfp_update_attr_soft_rx_los",
                                     show_err);
}


static int
_qsfp_update_attr_soft_tx_disable(struct transvr_obj_s *self,
                                  int show_err){

    if (!_qsfp_is_implement_tx_disable(self)) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_tx_disable,
                                     self->eeprom_map_p->page_tx_disable,
                                     self->eeprom_map_p->offset_tx_disable,
                                     self->eeprom_map_p->length_tx_disable,
                                     &(self->tx_disable),
                                     "_qsfp_update_attr_soft_tx_disable",
                                     show_err);
}


static int
_qsfp_update_attr_soft_tx_fault(struct transvr_obj_s *self,
                                int show_err){

    if (!_qsfp_is_implement_tx_fault(self)) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_tx_fault,
                                     self->eeprom_map_p->page_tx_fault,
                                     self->eeprom_map_p->offset_tx_fault,
                                     self->eeprom_map_p->length_tx_fault,
                                     &(self->tx_fault),
                                     "_qsfp_update_attr_soft_tx_fault",
                                     show_err);
}


static int
_qsfp_update_attr_tx_eq(struct transvr_obj_s *self,
                        int show_err){

    if (!_is_transvr_support_ctle(self)) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_tx_eq,
                                     self->eeprom_map_p->page_tx_eq,
                                     self->eeprom_map_p->offset_tx_eq,
                                     self->eeprom_map_p->length_tx_eq,
                                     self->tx_eq,
                                     "_qsfp_update_attr_tx_eq",
                                     show_err);
}


static int
_qsfp_update_attr_rx_am(struct transvr_obj_s *self,
                        int show_err){

    if (!_is_transvr_support_ctle(self)) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_rx_am,
                                     self->eeprom_map_p->page_rx_am,
                                     self->eeprom_map_p->offset_rx_am,
                                     self->eeprom_map_p->length_rx_am,
                                     self->rx_am,
                                     "_qsfp_update_attr_rx_am",
                                     show_err);
}


static int
_qsfp_update_attr_rx_em(struct transvr_obj_s *self,
                        int show_err){

    if (!_is_transvr_support_ctle(self)) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return _common_update_uint8_attr(self,
                                     self->eeprom_map_p->addr_rx_em,
                                     self->eeprom_map_p->page_rx_em,
                                     self->eeprom_map_p->offset_rx_em,
                                     self->eeprom_map_p->length_rx_em,
                                     self->rx_em,
                                     "_qsfp_update_attr_rx_em",
                                     show_err);
}


int
_common_update_attr_all(struct transvr_obj_s *self,
                        int show_err){

    char *err_str = "err";

    if (_common_update_attr_id(self, show_err) < 0) {
        err_str = "_common_update_attr_id";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_extended_id(self, show_err) < 0) {
        err_str = "_common_update_attr_extended_id";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_connector(self, show_err) < 0) {
        err_str = "_common_update_attr_connector";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_transvr_comp(self, show_err) < 0) {
        err_str = "_common_update_attr_transvr_comp";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_transvr_comp_ext(self, show_err) < 0) {
        err_str = "_common_update_attr_transvr_comp_ext";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_vendor_name(self, show_err) < 0) {
        err_str = "_common_update_attr_vendor_name";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_vendor_pn(self, show_err) < 0) {
        err_str = "_common_update_attr_vendor_pn";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_vendor_rev(self, show_err) < 0) {
        err_str = "_common_update_attr_vendor_rev";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_vendor_sn(self, show_err) < 0) {
        err_str = "_common_update_attr_vendor_sn";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_br(self, show_err) < 0) {
        err_str = "_common_update_attr_br";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_len_smf(self, show_err) < 0) {
        err_str = "_common_update_attr_len_smf";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_len_om1(self, show_err) < 0) {
        err_str = "_common_update_attr_len_om1";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_len_om2(self, show_err) < 0) {
        err_str = "_common_update_attr_len_om2";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_len_om3(self, show_err) < 0) {
        err_str = "_common_update_attr_len_om3";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_len_om4(self, show_err) < 0) {
        err_str = "_common_update_attr_len_om4";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_option(self, show_err) < 0) {
        err_str = "_common_update_attr_option";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_comp_rev(self, show_err) < 0) {
        err_str = "_common_update_attr_comp_rev";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_diag_type(self, show_err) < 0) {
        err_str = "_common_update_attr_diag_type";
        goto err_common_update_attr_all;
    }
    if (_common_update_attr_wavelength(self, show_err) < 0) {
        err_str = "_common_update_attr_wavelength";
        goto err_common_update_attr_all;
    }
    return 0;

err_common_update_attr_all:
    if (show_err){
        SWPS_INFO("%s: fail at:%s <swp>:%s\n", __func__, err_str, self->swp_name);
    }
    return -1;
}


int
_sfp_update_attr_all(struct transvr_obj_s *self,
                     int show_err){

    char *err_str  = DEBUG_TRANSVR_STR_VAL;

    if (_common_update_attr_all(self, show_err) < 0){
        err_str = "_common_update_attr_all";
        goto err_sfp_update_attr_all;
    }
    if (_sfp_update_attr_len_sm(self, show_err) < 0) {
        err_str = "_sfp_update_attr_len_sm";
        goto err_sfp_update_attr_all;
    }
    if (_sfp_update_attr_rate_id(self, show_err) < 0) {
        err_str = "_sfp_update_attr_rate_id";
        goto err_sfp_update_attr_all;
    }
    if ((self->rate_id) > 0) {
        if (_sfp_update_attr_soft_rs0(self, show_err) < 0) {
            err_str = "_sfp_update_attr_soft_rs0";
            goto err_sfp_update_attr_all;
        }
        if (_sfp_update_attr_soft_rs1(self, show_err) < 0) {
            err_str = "_sfp_update_attr_soft_rs1";
            goto err_sfp_update_attr_all;
        }
    }
    return 0;

err_sfp_update_attr_all:
    if (show_err){
        SWPS_INFO("%s: fail at:%s <swp>:%s\n", __func__, err_str, self->swp_name);
    }
    return -1;
}


int
_qsfp_update_attr_all(struct transvr_obj_s *self,
                      int show_err){

    char *err_str  = DEBUG_TRANSVR_STR_VAL;

    if (_common_update_attr_all(self, show_err) < 0){
        err_str = "_common_update_attr_all";
        goto err_qsfp_update_attr_all;
    }
    if (_qsfg_update_attr_extbr(self, show_err) < 0) {
        err_str = "_qsfg_update_attr_extbr";
        goto err_qsfp_update_attr_all;
    }
    if (self->type == TRANSVR_TYPE_QSFP_28) {
        if (_qsfp_update_attr_cdr(self, 1) < 0) {
            err_str = "_qsfp_update_attr_cdr";
            goto err_qsfp_update_attr_all;
        }
    }
    return 0;

err_qsfp_update_attr_all:
    if (show_err){
        SWPS_INFO("%s: fail at:%s <swp>:%s\n", __func__, err_str, self->swp_name);
    }
    return -1;
}


/* ========== Object functions for common type ==========
 */
int
_common_count_temp(uint8_t high_byte,
                   uint8_t low_byte,
                   char *buf_p) {
    int sign = 0;
    int high = 0;
    int low  = 0;
    int lmax = 8;

    /* Count high */
    sign = get_bit(high_byte,7);
    SWP_BIT_CLEAR(high_byte, 7);
    high = (int)high_byte;
    if (sign == 1) {
        high = 0 - high;
    }
    /* Count low */
    low  = (get_bit(low_byte, 7) * 500);
    low += (get_bit(low_byte, 6) * 250);
    low += (get_bit(low_byte, 5) * 125);
    low += (get_bit(low_byte, 4) *  62);
    low  = (low / 100);
    /* Integrate High and Low */
    return snprintf(buf_p, lmax, "%d.%d\n", high, low);
}


int
_common_count_voltage(uint8_t high_byte,
                      uint8_t low_byte,
                      char *buf_p) {
    /* [Note]:
     *   Internally measured transceiver supply voltage. Represented
     *   as a 16 bit unsigned integer with the voltage defined as the
     *   full 16 bit value (0-65535) with LSB equal to 100 uVolt,
     *   yielding a total range of 0 to +6.55 Volts. Practical
     *   considerations to be defined by transceiver manufacturer will
     *   tend to limit the actual bounds of the supply voltage measurement.
     *   Accuracy is vendor specific but must be better than 3% of the
     *   manufacturer's nominal value over specified operating temperature
     *   and voltage. Note that in some transceivers, transmitter supply
     *   voltage and receiver supply voltage are isolated. In that case,
     *   only one supply is monitored. Refer to the device specification
     *   for more detail.
     */
    int total = 0;
    int lmax  = 8;
    int val_i = 0;
    int val_f = 0;
    /* unit: 100 uV (1mV=1000uV) */
    total = transform_word_to_int(high_byte, low_byte);
    val_i = ((total/10) / 1000);
    val_f = ((total/10) - (val_i*1000));
    /* Return Unit: 1 Volt */
    return snprintf(buf_p, lmax, "%d.%03d\n", val_i, val_f);
}


int
_common_count_tx_bias(uint8_t high_byte,
                      uint8_t low_byte,
                      char *buf_p) {
    /* [Note]
     *   Measured TX bias current in uA. Represented as a 16 bit unsigned
     *   integer with the current defined as the full 16 bit value (0-65535)
     *   with LSB equal to 2 uA, yielding a total range of 0 to 131 mA.
     *   Accuracy is vendor specific but must be better than 10% of the
     *   manufacturer's nominal value over specified operating temperature
     *   and voltage.
     */
    int total = 0;
    int lmax  = 8;
    int val_i = 0;
    int val_f = 0;
    /* unit: 2 uA (1mA=1000uA) */
    total = transform_word_to_int(high_byte, low_byte);
    val_i = ((total*2) / 1000);
    val_f = (((total*2) - (val_i*1000)) / 100);
    /* Return Unit: 1 mA */
    return snprintf(buf_p, lmax, "%d.%01d\n", val_i, val_f);
}


int
_common_count_tx_power(uint8_t high_byte,
                       uint8_t low_byte,
                       char *buf_p) {
    /* [Note]
     *   Measured TX output power in mW. Represented as a 16 bit unsigned
     *   integer with the power defined as the full 16 bit value (0-65535)
     *   with LSB equal to 0.1 uW, yielding a total range of 0 to 6.5535 mW
     *   (~ -40 to +8.2 dBm). Data is assumed to be based on measurement of
     *   laser monitor photodiode current. It is factory calibrated to absolute
     *   units using the most representative fiber output type. Accuracy is
     *   vendor specific but must be better than 3dB over specified temperature
     *   and voltage. Data is not valid when the transmitter is disabled.
     */
    int total = 0;
    int lmax  = 8;
    int val_i = 0;
    int val_f = 0;
    /* unit: 0.1 uW (1mW=1000uW) */
    total = transform_word_to_int(high_byte, low_byte);
    val_i = ((total/10) / 1000);
    val_f = ((total/10) - (val_i*1000));
    /* Return Unit: 1 mW */
    return snprintf(buf_p, lmax, "%d.%03d\n", val_i, val_f);
}


int
_common_count_rx_power(uint8_t high_byte,
                       uint8_t low_byte,
                       char *buf_p) {
    /* [Note]
     *   Measured RX received optical power in mW. Value can represent either
     *   average received power or OMA depending upon how bit 3 of byte 92 (A0h)
     *   is set. Represented as a 16 bit unsigned integer with the power defined
     *   as the full 16 bit value (0-65535) with LSB equal to 0.1 uW, yielding a
     *   total range of 0 to 6.5535 mW (~ -40 to +8.2 dBm). Absolute accuracy is
     *   dependent upon the exact optical wavelength. For the vendor specified
     *   wavelength, accuracy shall be better than 3dB over specified temperature
     *   and voltage.
     */
    int total = 0;
    int lmax  = 8;
    int val_i = 0;
    int val_f = 0;
    /* unit: 0.1 uW (1mW=1000uW) */
    total = transform_word_to_int(high_byte, low_byte);
    val_i = ((total/10) / 1000);
    val_f = ((total/10) - (val_i*1000));
    /* Return Unit: 1 mW */
    return snprintf(buf_p, lmax, "%d.%03d\n", val_i, val_f);
}


int
_common_count_wavelength(struct transvr_obj_s *self,
                         uint8_t high_byte,
                         uint8_t low_byte) {
    /* [Note]
     *  SFP : uint 1 um.
     *  QSFP: unit 0.05 um.
     */
    int total = 0;

    total = transform_word_to_int(high_byte, low_byte);
    switch (self->type) {
        case TRANSVR_TYPE_SFP:
            return total;

        case TRANSVR_TYPE_QSFP:
        case TRANSVR_TYPE_QSFP_PLUS:
        case TRANSVR_TYPE_QSFP_28:
            return (total/20);

        default:
            break;
    }
    return ERR_TRANSVR_UNDEFINED;
}


int
common_get_id(struct transvr_obj_s *self){

    int err_code = _check_by_mode(self,
                                  &_common_update_attr_id,
                                  "common_get_id");
    if (err_code < 0){
        return err_code;
    }
    /* Transform to INT to show error case */
    return (int)self->id;
}


int
common_get_ext_id(struct transvr_obj_s *self){

    int err_code = _check_by_mode(self,
                                  &_common_update_attr_extended_id,
                                  "common_get_ext_id");
    if (err_code < 0){
        return err_code;
    }
    /* Transform to INT to show error case */
    return (int)self->ext_id;
}


int
common_get_connector(struct transvr_obj_s *self){

    int err_code = _check_by_mode(self,
                                  &_common_update_attr_connector,
                                  "common_get_connector");
    if (err_code < 0){
        return err_code;
    }
    /* Transform to INT to show error case */
    return (int)self->connector;
}


int
common_get_vendor_name(struct transvr_obj_s *self, char *buf){

    int err = DEBUG_TRANSVR_INT_VAL;

    if (self->state == STATE_TRANSVR_CONNECTED &&
        self->mode == TRANSVR_MODE_POLLING &&
        TRANSVR_INFO_CACHE_ENABLE) {
        return snprintf(buf, LEN_TRANSVR_M_STR, "%s\n", self->vendor_name);
    }
    err = _check_by_mode(self,
                         &_common_update_attr_vendor_name,
                         "common_get_vendor_name");
    memset(buf, 0, LEN_TRANSVR_M_STR);
    if (err < 0){
        return snprintf(buf, LEN_TRANSVR_M_STR, "%d\n", err);
    }
    return snprintf(buf, LEN_TRANSVR_M_STR, "%s\n", self->vendor_name);
}


int
common_get_vendor_pn(struct transvr_obj_s *self, char *buf) {

    int err = DEBUG_TRANSVR_INT_VAL;

    if (self->state == STATE_TRANSVR_CONNECTED &&
        self->mode == TRANSVR_MODE_POLLING &&
        TRANSVR_INFO_CACHE_ENABLE) {
        return snprintf(buf, LEN_TRANSVR_M_STR, "%s\n", self->vendor_pn);
    }
    err = _check_by_mode(self,
                         &_common_update_attr_vendor_pn,
                         "common_get_vendor_pn");
    memset(buf, 0, LEN_TRANSVR_M_STR);
    if (err < 0){
        return snprintf(buf, LEN_TRANSVR_M_STR, "%d\n", err);
    }
    return snprintf(buf, LEN_TRANSVR_M_STR, "%s\n", self->vendor_pn);
}


int
common_get_vendor_rev(struct transvr_obj_s *self, char *buf) {

    int err = DEBUG_TRANSVR_INT_VAL;

    if (self->state == STATE_TRANSVR_CONNECTED &&
        self->mode == TRANSVR_MODE_POLLING &&
        TRANSVR_INFO_CACHE_ENABLE) {
        return snprintf(buf, LEN_TRANSVR_M_STR, "%s\n", self->vendor_rev);
    }
    err = _check_by_mode(self,
                         &_common_update_attr_vendor_rev,
                         "common_get_vendor_rev");
    memset(buf, 0, LEN_TRANSVR_M_STR);
    if (err < 0){
        return snprintf(buf, LEN_TRANSVR_M_STR, "%d\n", err);
    }
    return snprintf(buf, LEN_TRANSVR_M_STR, "%s\n", self->vendor_rev);
}


int
common_get_vendor_sn(struct transvr_obj_s *self, char *buf) {

    int err = DEBUG_TRANSVR_INT_VAL;

    if (self->state == STATE_TRANSVR_CONNECTED &&
        self->mode == TRANSVR_MODE_POLLING &&
        TRANSVR_INFO_CACHE_ENABLE) {
        return snprintf(buf, LEN_TRANSVR_M_STR, "%s\n", self->vendor_sn);
    }
    err = _check_by_mode(self,
                         &_common_update_attr_vendor_sn,
                         "common_get_vendor_sn");
    memset(buf, 0, LEN_TRANSVR_M_STR);
    if (err < 0){
        return snprintf(buf, LEN_TRANSVR_M_STR, "%d\n", err);
    }
    return snprintf(buf, LEN_TRANSVR_M_STR, "%s\n", self->vendor_sn);
}


int
common_get_br(struct transvr_obj_s *self){

    int err = DEBUG_TRANSVR_INT_VAL;

    if (self->state == STATE_TRANSVR_CONNECTED &&
        self->mode == TRANSVR_MODE_POLLING &&
        TRANSVR_INFO_CACHE_ENABLE) {
        return (int)self->br;
    }
    err = _check_by_mode(self,
                         &_common_update_attr_br,
                         "common_get_br");
    if (err < 0){
        return err;
    }
    /* Transform to INT to show error case */
    return (int)self->br;
}


int
common_get_len_smf(struct transvr_obj_s *self){

    int err = DEBUG_TRANSVR_INT_VAL;

    if (self->state == STATE_TRANSVR_CONNECTED &&
        self->mode == TRANSVR_MODE_POLLING &&
        TRANSVR_INFO_CACHE_ENABLE) {
        return self->len_smf;
    }
    err = _check_by_mode(self,
                         &_common_update_attr_len_smf,
                         "common_get_len_smf");
    if (err < 0){
        return err;
    }
    return self->len_smf;
}


int
common_get_len_om1(struct transvr_obj_s *self){

    int err = DEBUG_TRANSVR_INT_VAL;

    if (self->state == STATE_TRANSVR_CONNECTED &&
        self->mode == TRANSVR_MODE_POLLING &&
        TRANSVR_INFO_CACHE_ENABLE) {
        return self->len_om1;
    }
    err = _check_by_mode(self,
                         &_common_update_attr_len_om1,
                         "common_get_len_om1");
    if (err < 0){
        return err;
    }
    return self->len_om1;
}


int
common_get_len_om2(struct transvr_obj_s *self){

    int err = DEBUG_TRANSVR_INT_VAL;

    if (self->state == STATE_TRANSVR_CONNECTED &&
        self->mode == TRANSVR_MODE_POLLING &&
        TRANSVR_INFO_CACHE_ENABLE) {
        return self->len_om2;
    }

    err = _check_by_mode(self,
                         &_common_update_attr_len_om2,
                         "common_get_len_om2");
    if (err < 0){
        return err;
    }
    return self->len_om2;
}


int
common_get_len_om3(struct transvr_obj_s *self){

    int err = DEBUG_TRANSVR_INT_VAL;

    if (self->state == STATE_TRANSVR_CONNECTED &&
        self->mode == TRANSVR_MODE_POLLING &&
        TRANSVR_INFO_CACHE_ENABLE) {
        return self->len_om3;
    }

    err = _check_by_mode(self,
                         &_common_update_attr_len_om3,
                         "common_get_len_om3");
    if (err < 0){
        return err;
    }
    return self->len_om3;
}


int
common_get_len_om4(struct transvr_obj_s *self){

    int err = DEBUG_TRANSVR_INT_VAL;

    if (self->state == STATE_TRANSVR_CONNECTED &&
        self->mode == TRANSVR_MODE_POLLING &&
        TRANSVR_INFO_CACHE_ENABLE) {
        return self->len_om4;
    }
    err = _check_by_mode(self,
                         &_common_update_attr_len_om4,
                         "common_get_len_om4");
    if (err < 0){
        return err;
    }
    return self->len_om4;
}


int
common_get_comp_extended(struct transvr_obj_s *self){

    int err_code = _check_by_mode(self,
                                  &_common_update_attr_transvr_comp_ext,
                                  "common_get_comp_extended");
    if (err_code < 0){
        return err_code;
    }
    return self->transvr_comp_ext;
}


int
common_get_comp_rev(struct transvr_obj_s *self){

    int err_code = _check_by_mode(self,
                                  &_common_update_attr_comp_rev,
                                  "common_get_comp_rev");
    if (err_code < 0){
        return err_code;
    }
    return self->comp_rev;
}


int
common_get_info(struct transvr_obj_s *self){

    if (self->state != STATE_TRANSVR_CONNECTED) {
        return self->state;
    }
    return self->info;
}


int
_common_get_if_lane(struct transvr_obj_s *self,
                    char *result){
    int  i = 0;
    int  tmp_val = 0;
    char tmp_str[LEN_TRANSVR_M_STR] = DEBUG_TRANSVR_STR_VAL;

    memset(result, 0, LEN_TRANSVR_M_STR);

    for (i=0; i<ARRAY_SIZE(self->lane_id); i++) {
        tmp_val = self->lane_id[i];
        if (tmp_val < 1) {
            break;
        }
        memset(tmp_str, 0, LEN_TRANSVR_M_STR);
        if (i == 0) {
            snprintf(tmp_str, LEN_TRANSVR_M_STR, "%d", tmp_val);
        } else {
            snprintf(tmp_str, LEN_TRANSVR_M_STR, ",%d", tmp_val);
        }
        strncat(result, tmp_str, LEN_TRANSVR_M_STR);
    }
    if (i == 0) {
        return EVENT_TRANSVR_TASK_FAIL;
    }
    return 0;
}


int
common_get_if_lane(struct transvr_obj_s *self,
                   char *buf_p){

    char tmp_str[LEN_TRANSVR_M_STR] = DEBUG_TRANSVR_STR_VAL;

    if (self->ioexp_obj_p->state != STATE_IOEXP_NORMAL) {
        return snprintf(buf_p, LEN_TRANSVR_M_STR, "%d\n", ERR_TRANSVR_ABNORMAL);
    }
    if (_common_get_if_lane(self, tmp_str) < 0) {
        return snprintf(buf_p, LEN_TRANSVR_M_STR, "%d\n" ,ERR_TRANSVR_ABNORMAL);
    }
    return snprintf(buf_p, LEN_TRANSVR_M_STR, "%s\n" ,tmp_str);
}


int
sfp_get_len_sm(struct transvr_obj_s *self){

    int err_code = _check_by_mode(self,
                                  &_sfp_update_attr_len_sm,
                                  "sfp_get_len_sm");
    if (err_code < 0){
        return err_code;
    }
    return self->len_sm;
}


int
sfp_get_rate_id(struct transvr_obj_s *self){

    int err_code = _check_by_mode(self,
                                  &_sfp_update_attr_rate_id,
                                  "sfp_get_rate_id");
    if (err_code < 0){
        return err_code;
    }
    return self->rate_id;
}


int
sfp_get_soft_rs0(struct transvr_obj_s *self){
    /* Note:
     *   SFP Soft Rate_Select Select [aka. "RS(0)"] address
     *   A2h, offset: 110, bit 3 (begin form 0)
     */
    int err_code    = DEBUG_TRANSVR_INT_VAL;
    int bit_shift   = 3;
    uint8_t result  = 0x00;
    uint8_t bitmask = (1 << bit_shift);

    /* Check rate identifier is supported */
    err_code = self->get_rate_id(self);
    if (err_code <= 0) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    /* Update and check */
    err_code = _check_by_mode(self,
                              &_sfp_update_attr_soft_rs0,
                              "sfp_get_soft_rs0");
    if (err_code <0){
        return err_code;
    }
    result = (self->soft_rs0 & bitmask);
    if (result == bitmask) {
        return 1;
    }
    if (result == 0) {
        return 0;
    }
    return ERR_TRANSVR_UNEXCPT;
}


int
sfp_get_soft_rs1(struct transvr_obj_s *self){
    /* Note:
     *   SFP Soft RS(1) Select address
     *   A2h, offset: 118, bit 3 (begin form 0)
     */
    int err_code = DEBUG_TRANSVR_INT_VAL;
    int bit_shift = 3;
    uint8_t result = 0x00;
    uint8_t bitmask = (1 << bit_shift);

    /* Check rate identifier is supported */
    err_code = self->get_rate_id(self);
    if (err_code <= 0) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    /* Update and check */
    err_code = _check_by_mode(self,
                              &_sfp_update_attr_soft_rs1,
                              "sfp_get_soft_rs1");
    if (err_code <0){
        return err_code;
    }
    result = (self->soft_rs1 & bitmask);
    if (result == bitmask) {
        return 1;
    }
    if (result == 0) {
        return 0;
    }
    return ERR_TRANSVR_UNEXCPT;
}


int
sfp_get_transvr_temp(struct transvr_obj_s *self,
                     char *buf_p) {

    int lmax = 8;
    int err_code = DEBUG_TRANSVR_INT_VAL;

    err_code = _check_by_mode(self,
                              &_sfp_update_attr_curr_temp,
                              "sfp_get_transvr_temp");
    if (err_code < 0) {
        return snprintf(buf_p, lmax, "%d\n", err_code);
    }
    if ((self->curr_temp[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    return _common_count_temp(self->curr_temp[0],
                              self->curr_temp[1],
                              buf_p);
}


int
sfp_get_transvr_voltage(struct transvr_obj_s *self,
                        char *buf_p) {

    int lmax = 8;
    int err_code = DEBUG_TRANSVR_INT_VAL;

    err_code = _check_by_mode(self,
                              &_sfp_update_attr_curr_voltage,
                              "sfp_get_transvr_voltage");
    if (err_code < 0) {
        return snprintf(buf_p, lmax, "%d\n", err_code);
    }
    if ((self->curr_voltage[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    /* Return Unit: 1 Volt */
    return _common_count_voltage(self->curr_voltage[0],
                                 self->curr_voltage[1],
                                 buf_p);
}


int
sfp_get_transvr_tx_bias(struct transvr_obj_s *self,
                        char *buf_p) {

    int lmax = 8;
    int err_code = DEBUG_TRANSVR_INT_VAL;

    err_code = _check_by_mode(self,
                              &_sfp_update_attr_curr_tx_bias,
                              "sfp_get_transvr_tx_bias");
    if (err_code < 0) {
        return snprintf(buf_p, lmax, "%d\n", err_code);
    }
    if ((self->curr_tx_bias[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    /* Return Unit: 1 mA */
    return _common_count_tx_bias(self->curr_tx_bias[0],
                                 self->curr_tx_bias[1],
                                 buf_p);
}


int
sfp_get_transvr_tx_power(struct transvr_obj_s *self,
                         char *buf_p) {

    int lmax = 8;
    int err_code = DEBUG_TRANSVR_INT_VAL;

    err_code = _check_by_mode(self,
                              &_sfp_update_attr_curr_tx_power,
                              "sfp_get_transvr_tx_power");
    if (err_code < 0) {
        return snprintf(buf_p, lmax, "%d\n", err_code);
    }
    if ((self->curr_tx_bias[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    /* Return Unit: 1 mW */
    return _common_count_tx_power(self->curr_tx_power[0],
                                  self->curr_tx_power[1],
                                  buf_p);
}


int
sfp_get_transvr_rx_power(struct transvr_obj_s *self,
                         char *buf_p) {

    int lmax = 8;
    int err_code = DEBUG_TRANSVR_INT_VAL;

    err_code = _check_by_mode(self,
                              &_sfp_update_attr_curr_rx_power,
                              "sfp_get_transvr_rx_power");
    if (err_code < 0) {
        return snprintf(buf_p, lmax, "%d\n", err_code);
    }
    if ((self->curr_tx_bias[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    /* Return Unit: 1 mW */
    return _common_count_rx_power(self->curr_rx_power[0],
                                  self->curr_rx_power[0],
                                  buf_p);
}


int
sfp_get_transvr_rx_em(struct transvr_obj_s *self,
                      char *buf_p) {

    int limt = 8;
    int err  = DEBUG_TRANSVR_INT_VAL;

    err = _check_by_mode(self,
                         &_sfp_update_attr_rx_em,
                         "sfp_get_transvr_rx_em");
    if (err < 0) {
        return snprintf(buf_p, limt, "%d\n", err);
    }
    if ((self->tx_eq[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, limt, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    return snprintf(buf_p, limt, "0x%02x\n", self->rx_em[0]);
}


int
sfp_get_transvr_tx_eq(struct transvr_obj_s *self,
                      char *buf_p) {

    int limt = 8;
    int err  = DEBUG_TRANSVR_INT_VAL;

    err = _check_by_mode(self,
                         &_sfp_update_attr_tx_eq,
                         "sfp_get_transvr_tx_eq");
    if (err < 0) {
        return snprintf(buf_p, limt, "%d\n", err);
    }
    if ((self->tx_eq[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, limt, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    return snprintf(buf_p, limt, "0x%02x\n", self->tx_eq[0]);
}


int
_sfp_get_comp_extended(struct transvr_obj_s *self) {
    /* Address: A0h / 36
     * Reference: SFF-8024 TABLE 4-4
     */
    if ((self->state == STATE_TRANSVR_CONNECTED) ||
        (self->state == STATE_TRANSVR_INIT) ) {
        return (int)(self->transvr_comp_ext);
    }
    return ERR_TRANSVR_ABNORMAL;
}


int
__sfp_get_comp_attr(struct transvr_obj_s *self,
                     int array_offset) {
    /* SFP Specification Compliance: A0h / 3-10
     * transvr_comp[0-7] = 3 - 10
     */
    if ((self->state == STATE_TRANSVR_CONNECTED) ||
        (self->state == STATE_TRANSVR_INIT) ) {
        return (int)(self->transvr_comp[array_offset]);
    }
    return ERR_TRANSVR_ABNORMAL;
}


int
_sfp_get_comp_10g_eth_comp(struct transvr_obj_s *self) {
    /* transvr_comp[0] = address A0h / 3
     *
     * 3 7: 10G Base-ER
     * 3 6: 10GBASE-LRM
     * 3 5: 10GBASE-LR
     * 3 4: 10GBASE-SR
     */
    int bitmask = 0xf0; /* 11110000 */
    return (__sfp_get_comp_attr(self, 0) & bitmask);
}


int
_sfp_get_comp_1g_eth_comp(struct transvr_obj_s *self) {
    /* transvr_comp[3] = address A0h / 6
     *
     * 6 7: BASE-PX *3
     * 6 6: BASE-BX10 *3
     * 6 5: 100BASE-FX
     * 6 4: 100BASE-LX/LX10
     * 6 3: 1000BASE-T
     * 6 2: 1000BASE-CX
     * 6 1: 1000BASE-LX *3
     * 6 0: 1000BASE-SX
     */
    return __sfp_get_comp_attr(self, 3);
}


int
_sfp_get_cable_tech(struct transvr_obj_s *self) {
    /* transvr_comp[5] = address A0h / 8
     *
     * 8 3: Active Cable *8
     * 8 2: Passive Cable *8
     */
    int bitmask = 0x0c; /* 00001100 */
    return (__sfp_get_comp_attr(self, 5) & bitmask);
}


int
sfp_get_comp_eth_1(struct transvr_obj_s *self){

    int err_code = _check_by_mode(self,
                                  &_common_update_attr_transvr_comp,
                                  "sfp_get_comp_eth_1");
    if (err_code < 0){
        return err_code;
    }
    return _sfp_get_comp_1g_eth_comp(self);
}


int
sfp_get_comp_eth_10(struct transvr_obj_s *self){

    int err_code = _check_by_mode(self,
                                  &_common_update_attr_transvr_comp,
                                  "sfp_get_comp_eth_10");
    if (err_code < 0){
        return err_code;
    }
    return _sfp_get_comp_10g_eth_comp(self);
}


int
_sfp_get_connector_type(struct transvr_obj_s *self) {
    /* Address: A0h / 2
     * Reference: SFF-8024 TABLE 4-3
     */
    if ((self->state == STATE_TRANSVR_CONNECTED) ||
        (self->state == STATE_TRANSVR_INIT) ) {
        return (int)(self->connector);
    }
    return ERR_TRANSVR_ABNORMAL;
}


int
sfp_get_wavelength(struct transvr_obj_s *self,
                   char *buf_p) {
    /* [Note] Optical and Cable Variants Specification Compliance (SFF-8472)
     * [Addr] A0h, Bytes 60-61
     * [Note] For optical variants, as defined by having zero's in A0h Byte 8
     *        bits 2 and 3, Bytes 60 and 61 denote nominal transmitter output
     *        wavelength at room temperature. 16 bit value with byte 60 as high
     *        order byte and byte 61 as low order byte. The laser wavelength is
     *        equal to the 16 bit integer value in nm. This field allows the user
     *        to read the laser wavelength directly, so it is not necessary to
     *        infer it from the Transceiver Codes A0h Bytes 3 to 10 (see Table
     *        5-3). This also allows specification of wavelengths not covered
     *        in the Transceiver Codes, such as those used in coarse WDM systems.
     *
     *        For passive and active cable variants, a value of 00h for both A0h
     *        Byte 60 and Byte 61 denotes laser wavelength or cable specification
     *        compliance is unspecified.
     */

    int lmax = 8;
    int err_code = DEBUG_TRANSVR_INT_VAL;

    err_code = _check_by_mode(self,
                              &_common_update_attr_wavelength,
                              "common_get_wavelength");
    if (err_code < 0) {
        return snprintf(buf_p, lmax, "%d\n", err_code);
    }
    if ((self->wavelength[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    /* unit: 1 um */
    return snprintf(buf_p, lmax, "%d\n",
            _common_count_wavelength(self,
                                     self->wavelength[0],
                                     self->wavelength[1]));
}


int
sfp_get_1g_rj45_extphy_offset(struct transvr_obj_s *self, char *buf) {

    if (self->state != STATE_TRANSVR_CONNECTED) {
        return ERR_TRANSVR_UNPLUGGED;
    }
    if ((self->info != TRANSVR_CLASS_BASE_T_1000) &&
        (self->info != TRANSVR_CLASS_BASE_T_1000_up) ){
        return ERR_TRANSVR_NOTSUPPORT;
    }
    return snprintf(buf, LEN_TRANSVR_S_STR, "0x%02x\n", self->extphy_offset);
}


int
sfp_get_1g_rj45_extphy_reg(struct transvr_obj_s *self, char *buf) {

    int i      = 0;
    int ret    = 0;
    int retry  = 3;
    int delay  = 200;

    if (self->state != STATE_TRANSVR_CONNECTED) {
        return ERR_TRANSVR_UNPLUGGED;
    }
    if ((self->info != TRANSVR_CLASS_BASE_T_1000) &&
        (self->info != TRANSVR_CLASS_BASE_T_1000_up) ){
        return ERR_TRANSVR_NOTSUPPORT;
    }
    if (_common_setup_page(self, VAL_TRANSVR_EXTPHY_ADDR_56,
                           -1, self->extphy_offset, 1, 0) < 0) {
        return -EIO;
    }
    for (i=0; i<retry; i++) {
        ret = i2c_smbus_read_word_data(self->i2c_client_p, self->extphy_offset);
        if (ret >=0) {
            goto ok_sfp_get_1g_rj45_extphy_reg;
        }
        msleep(delay);
    }
    SWPS_INFO("%s: retry:%d fail <port>:%s <offset>:0x%02x\n",
              __func__, retry, self->swp_name, self->extphy_offset);
    return -EIO;

ok_sfp_get_1g_rj45_extphy_reg:
    ret = ((ret & 0x00ff) << 8) | ((ret & 0xff00) >> 8);
    return snprintf(buf, LEN_TRANSVR_S_STR, "0x%04x\n", ret);
}


int
__qsfp_get_power_cls(struct transvr_obj_s *self,
                     int direct_access){

    int err_code;
    uint8_t detect_val;

    /* Detect and Update power class attribute */
    if (direct_access){
        err_code = _check_by_mode(self,
                                  &_common_update_attr_extended_id,
                                  "__qsfp_get_power_cls");
    } else {
        err_code = self->ext_id;
    }
    if (err_code <0){
        return err_code;
    }
    if (err_code == DEBUG_TRANSVR_HEX_VAL){
        return ERR_TRANSVR_UPDATE_FAIL;
    }
    /* Clean data */
    detect_val = self->ext_id;
    SWP_BIT_CLEAR(detect_val, 2); /* Bit2: CDR RX present */
    SWP_BIT_CLEAR(detect_val, 3); /* Bit3: CDR TX present */
    SWP_BIT_CLEAR(detect_val, 4); /* Bit4: CLEI present   */
    SWP_BIT_CLEAR(detect_val, 5); /* Bit5: reserved       */
    /* Identify power class */
    switch (detect_val) {
        case 0:   /* Class_1: 00000000 */
            return 1;
        case 64:  /* Class_2: 01000000 */
            return 2;
        case 128: /* Class_3: 10000000 */
            return 3;
        case 192: /* Class_4: 11000000 */
            return 4;
        case 1:   /* Class_5: 00000001 */
        case 193: /* Class_5: 11000001 */
            return 5;
        case 2:   /* Class_6: 00000010 */
        case 194: /* Class_6: 11000010 */
            return 6;
        case 3:   /* Class_7: 00000011 */
        case 195: /* Class_7: 11000011 */
            return 7;
        default:
            break;
    }
    SWPS_INFO("%s: Detect undefined power class:%d\n", __func__, detect_val);
    return ERR_TRANSVR_UNDEFINED;
}


int
qsfp_get_power_cls(struct transvr_obj_s *self) {
    return __qsfp_get_power_cls(self, 1);
}


int
__qsfp_get_cdr_present(struct transvr_obj_s *self,
                       int direct_access){

    int retval;
    int BIT_SHIFT = 2;
    int BIT_MASK  = 0x3;

    /* Detect and Update power class attribute */
    if (direct_access) {
        retval = _check_by_mode(self,
                                &_common_update_attr_extended_id,
                                "__qsfp_get_cdr_present");
        if (retval < 0){
            return retval;
        }
    }
    retval = self->ext_id;
    if (retval == DEBUG_TRANSVR_HEX_VAL){
        return ERR_TRANSVR_UPDATE_FAIL;
    }
    /* Clean data and return */
    return (int)(retval >> BIT_SHIFT & BIT_MASK);
}


int
qsfp_get_cdr_present(struct transvr_obj_s *self) {
    return __qsfp_get_cdr_present(self, 1);
}


int
qsfp_get_cdr(struct transvr_obj_s *self){

    int err_code = _check_by_mode(self,
                                  &_qsfp_update_attr_cdr,
                                  "qsfp_get_cdr");
    if (err_code <0){
        return err_code;
    }

    return self->cdr;
}


int
__qsfp_get_comp_attr(struct transvr_obj_s *self,
                     int array_offset) {
    /* QSFP Specification Compliance: 00h / 131-138
     * transvr_comp[0-7] = 131 - 138
     */
    if ((self->state == STATE_TRANSVR_CONNECTED) ||
        (self->state == STATE_TRANSVR_INIT) ) {
        return (int)(self->transvr_comp[array_offset]);
    }
    return ERR_TRANSVR_ABNORMAL;
}


int
_qsfp_get_comp_10_40_100_ethernet(struct transvr_obj_s *self) {
    /* transvr_comp[0] = address 00h / 131
     *
     * 131 7: Extended: See section 6.3.23. The Extended Specification Compliance
     *        Codes are maintained in the Transceiver Management section of SFF-
     *        8024.
     * 131 6: 10GBASE-LRM
     * 131 5: 10GBASE-LR
     * 131 4: 10GBASE-SR
     * 131 3: 40GBASE-CR4
     * 131 2: 40GBASE-SR4
     * 131 1: 40GBASE-LR4
     * 131 0: 40G Active Cable (XLPPI)
     */
    return __qsfp_get_comp_attr(self, 0);
}


int
_qsfp_get_comp_sonet(struct transvr_obj_s *self) {
    /* transvr_comp[1] = address 00h / 132
     *
     * 132 7-3: Reserved
     * 132 2: OC 48, long reach
     * 132 1: OC 48, intermediate reach
     * 132 0: OC 48 short reach
     */
    return __qsfp_get_comp_attr(self, 1);
}


int
_qsfp_get_comp_sas_sata(struct transvr_obj_s *self) {
    /* transvr_comp[1] = address 00h / 132
     *
     * 133 7: SAS 24.0 Gb/s
     * 133 6: SAS 12.0 Gb/s
     * 133 5: SAS 6.0 Gb/s
     * 133 4: SAS 3.0 Gb/s
     * 133 3-0: Reserved
     */
    return __qsfp_get_comp_attr(self, 2);
}


int
_qsfp_get_comp_ethernet(struct transvr_obj_s *self) {
    /* transvr_comp[1] = address 00h / 132
     *
     * 134 7-4: Reserved
     * 134 3: 1000BASE-T
     * 134 2: 1000BASE-CX
     * 134 1: 1000BASE-LX
     * 134 0: 1000BASE-SX
     */
    return __qsfp_get_comp_attr(self, 3);
}


int
_qsfp_get_comp_fc_link_length(struct transvr_obj_s *self) {
    /* transvr_comp[1] = address 00h / 132
     *
     * 135 7: Very long distance (V)
     * 135 6: Short distance (S)
     * 135 5: Intermediate distance (I)
     * 135 4: Long distance (L)
     * 135 3: Medium (M)
     */
    int mask = 0xFC; /* 11111100 */
    return (__qsfp_get_comp_attr(self, 4) & mask);
}


int
_qsfp_get_comp_fc_trans_tech(struct transvr_obj_s *self) {
    /* transvr_comp[1] = address 00h / 132
     *
     * 135 2: Reserved
     * 135 1: Longwave laser (LC)
     * 135 0: Electrical inter-enclosure (EL)
     *
     * 136 7: Electrical intra-enclosure
     * 136 6: Shortwave laser w/o OFC (SN)
     * 136 5: Shortwave laser w OFC (SL)
     * 136 4: Longwave Laser (LL)
     * 136 3-0: Reserved
     *
     * return value = [bit 8-15:addr 135][bit 0-7:addr 136]
     */
    int mask_135 = 7; /* 00000111 */
    int val_135  = (__qsfp_get_comp_attr(self, 4) & mask_135);
    int val_136  = __qsfp_get_comp_attr(self, 5);
    return ((val_135 << 7) + val_136);
}


int
_qsfp_get_comp_fc_trans_media(struct transvr_obj_s *self) {
    /* transvr_comp[1] = address 00h / 132
     *
     * 137 7: Twin Axial Pair (TW)
     * 137 6: Shielded Twisted Pair (TP)
     * 137 5: Miniature Coax (MI)
     * 137 4: Video Coax (TV)
     * 137 3: Multi-mode 62.5 m (M6)
     * 137 2: Multi-mode 50 m (M5)
     * 137 1: Multi-mode 50 um (OM3)
     * 137 0: Single Mode (SM)
     */
    return __qsfp_get_comp_attr(self, 6);
}


int
_qsfp_get_comp_fc_speed(struct transvr_obj_s *self) {
    /* transvr_comp[1] = address 00h / 132
     *
     * 138 7: 1200 MBps (per channel)
     * 138 6: 800 MBps
     * 138 5: 1600 MBps (per channel)
     * 138 4: 400 MBps
     * 138 3: 3200 MBps (per channel)
     * 138 2: 200 MBps
     * 138 1: Extended: See section 6.3.23. The Extended Specification
     *        Compliance Codes are maintained in the Transceiver Management
     *        section of SFF-8024.
     * 138 0: 100 MBps
     */
    return __qsfp_get_comp_attr(self, 7);
}


int
_qsfp_get_comp_extended(struct transvr_obj_s *self) {
    /* Address: 00h / 192
     * Reference: SFF-8024 TABLE 4-4
     */
    if ((self->state == STATE_TRANSVR_CONNECTED) ||
        (self->state == STATE_TRANSVR_INIT) ) {
        return (int)(self->transvr_comp_ext);
    }
    return ERR_TRANSVR_ABNORMAL;
}


int
qsfp_get_comp_eth(struct transvr_obj_s *self){

    int err_code = _check_by_mode(self,
                                  &_common_update_attr_transvr_comp,
                                  "qsfp_get_comp_eth");
    if (err_code < 0){
        return err_code;
    }
    return _qsfp_get_comp_ethernet(self);
}


int
qsfp_get_comp_10_40(struct transvr_obj_s *self) {

    int err_code = _check_by_mode(self,
                                  &_common_update_attr_transvr_comp,
                                  "qsfp_get_comp_10_40");
    if (err_code < 0){
        return err_code;
    }
    return _qsfp_get_comp_10_40_100_ethernet(self);
}


int
_qsfp_get_connector_type(struct transvr_obj_s *self) {
    /* Address: 00h / 130
     * Reference: SFF-8024 TABLE 4-3
     */
    if ((self->state == STATE_TRANSVR_CONNECTED) ||
        (self->state == STATE_TRANSVR_INIT) ) {
        return (int)(self->connector);
    }
    return ERR_TRANSVR_ABNORMAL;
}


int
qsfp_get_transvr_temp(struct transvr_obj_s *self,
                     char *buf_p) {

    int lmax = 8;
    int err_code = DEBUG_TRANSVR_INT_VAL;

    err_code = _check_by_mode(self,
                              &_qsfp_update_attr_curr_temp,
                              "qsfp_get_transvr_temp");
    if (err_code < 0) {
        return snprintf(buf_p, lmax, "%d\n", err_code);
    }
    if ((self->curr_temp[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    return _common_count_temp(self->curr_temp[0],
                              self->curr_temp[1],
                              buf_p);
}


int
qsfp_get_transvr_voltage(struct transvr_obj_s *self,
                         char *buf_p) {

    int lmax = 8;
    int err_code = DEBUG_TRANSVR_INT_VAL;

    err_code = _check_by_mode(self,
                              &_qsfp_update_attr_curr_voltage,
                              "qsfp_get_transvr_voltage");
    if (err_code < 0) {
        return snprintf(buf_p, lmax, "%d\n", err_code);
    }
    if ((self->curr_voltage[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    /* Return Unit: 1 Volt */
    return _common_count_voltage(self->curr_voltage[0],
                                 self->curr_voltage[1],
                                 buf_p);
}


int
qsfp_get_transvr_tx_eq(struct transvr_obj_s *self,
                       char *buf_p) {

    int limt = 8;
    int err  = DEBUG_TRANSVR_INT_VAL;

    err = _check_by_mode(self,
                         &_qsfp_update_attr_tx_eq,
                         "qsfp_get_transvr_tx_eq");
    if (err < 0) {
        return snprintf(buf_p, limt, "%d\n", err);
    }
    if ((self->tx_eq[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, limt, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    return snprintf(buf_p, limt, "0x%02x%02x\n",
                    self->tx_eq[0], self->tx_eq[1]);
}


int
qsfp_get_transvr_rx_am(struct transvr_obj_s *self,
                       char *buf_p) {

    int limt = 8;
    int err  = DEBUG_TRANSVR_INT_VAL;

    err = _check_by_mode(self,
                         &_qsfp_update_attr_rx_am,
                         "qsfp_get_transvr_rx_am");
    if (err < 0) {
        return snprintf(buf_p, limt, "%d\n", err);
    }
    if ((self->rx_am[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, limt, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    return snprintf(buf_p, limt, "0x%02x%02x\n",
                    self->rx_am[0], self->rx_am[1]);
}


int
qsfp_get_transvr_rx_em(struct transvr_obj_s *self,
                       char *buf_p) {

    int limt = 8;
    int err  = DEBUG_TRANSVR_INT_VAL;

    err = _check_by_mode(self,
                         &_qsfp_update_attr_rx_em,
                         "qsfp_get_transvr_rx_em");
    if (err < 0) {
        return snprintf(buf_p, limt, "%d\n", err);
    }
    if ((self->rx_em[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, limt, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    return snprintf(buf_p, limt, "0x%02x%02x\n",
                    self->rx_em[0], self->rx_em[1]);
}


int
_qsfp_get_channel_diag(uint8_t *data_array,
                       int (*count_func)(uint8_t high_byte, uint8_t low_byte, char *buf_p),
                       char *ch_name,
                       char *result_p) {
    int i, high, low;
    int len_max = 128;
    char ch_buf[4][16] = { DEBUG_TRANSVR_STR_VAL,
                           DEBUG_TRANSVR_STR_VAL,
                           DEBUG_TRANSVR_STR_VAL,
                           DEBUG_TRANSVR_STR_VAL };

    for (i=0; i<4; i++) {
        high = (i*2);
        low  = ((i*2) + 1);
        count_func(data_array[high], data_array[low], ch_buf[i]);
    }
    return snprintf(result_p, len_max,
                    "%s-%d:%s%s-%d:%s%s-%d:%s%s-%d:%s",
                    ch_name, 1, ch_buf[0],
                    ch_name, 2, ch_buf[1],
                    ch_name, 3, ch_buf[2],
                    ch_name, 4, ch_buf[3]);
}


int
qsfp_get_soft_rx_los(struct transvr_obj_s *self,
                     char *buf_p) {

    int lmax      = 8;
    int mask      = 0x0f; /* Bit 0 ~ Bit 3 */
    int err_code  = DEBUG_TRANSVR_INT_VAL;

    err_code = _check_by_mode(self,
                              &_qsfp_update_attr_soft_rx_los,
                              "qsfp_get_soft_rx_los");
    if (err_code < 0) {
        return snprintf(buf_p, lmax, "%d\n", err_code);
    }
    return snprintf(buf_p, lmax, "0x%02x\n", (self->rx_los & mask));
}


int
qsfp_get_soft_tx_disable(struct transvr_obj_s *self,
                         char *buf_p) {

    int lmax      = 8;
    int mask      = 0x0f; /* Bit 0 ~ Bit 3 */
    int err_code  = DEBUG_TRANSVR_INT_VAL;

    err_code = _check_by_mode(self,
                              &_qsfp_update_attr_soft_tx_disable,
                              "qsfp_get_soft_tx_disable");
    if (err_code < 0) {
        return snprintf(buf_p, lmax, "%d\n", err_code);
    }
    return snprintf(buf_p, lmax, "0x%02x\n", (self->tx_disable & mask));
}


int
qsfp_get_soft_tx_fault(struct transvr_obj_s *self,
                       char *buf_p) {

    int lmax      = 8;
    int mask      = 0x0f; /* Bit 0 ~ Bit 3 */
    int err_code  = DEBUG_TRANSVR_INT_VAL;

    err_code = _check_by_mode(self,
                              &_qsfp_update_attr_soft_tx_fault,
                              "qsfp_get_soft_tx_fault");
    if (err_code < 0) {
        return snprintf(buf_p, lmax, "%d\n", err_code);
    }
    return snprintf(buf_p, lmax, "0x%02x\n", (self->tx_fault & mask));
}


int
qsfp_get_auto_tx_disable(struct transvr_obj_s *self,
                         char *buf_p) {

    if (self->auto_tx_disable == VAL_TRANSVR_FUNCTION_DISABLE) {
        return snprintf(buf_p, LEN_TRANSVR_S_STR,
                        "%d\n", ERR_TRANSVR_FUNC_DISABLE);
    }
    return snprintf(buf_p, LEN_TRANSVR_S_STR,
                    "0x%02x\n", self->auto_tx_disable);
}


int
qsfp_get_transvr_tx_bias(struct transvr_obj_s *self,
                         char *buf_p) {

    int lmax      = 8;
    int err_code  = DEBUG_TRANSVR_INT_VAL;
    char *ch_name = "TX";

    err_code = _check_by_mode(self,
                              &_qsfp_update_attr_curr_tx_bias,
                              "qsfp_get_transvr_tx_bias");
    if (err_code < 0) {
        return snprintf(buf_p, lmax, "%d\n", err_code);
    }
    if ((self->curr_tx_bias[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    /* Return Unit: 1 mA */
    return _qsfp_get_channel_diag(self->curr_tx_bias,
                                  _common_count_tx_bias,
                                  ch_name,
                                  buf_p);
}


int
qsfp_get_transvr_tx_power(struct transvr_obj_s *self,
                          char *buf_p) {

    int lmax      = 8;
    int err_code  = DEBUG_TRANSVR_INT_VAL;
    char *ch_name = "TX";

    err_code = _check_by_mode(self,
                              &_qsfp_update_attr_curr_tx_power,
                              "qsfp_get_transvr_tx_power");
    if (err_code < 0) {
        return snprintf(buf_p, lmax, "%d\n", err_code);
    }
    if ((self->curr_tx_power[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    /* Return Unit: 1 mW */
    return _qsfp_get_channel_diag(self->curr_tx_power,
                                  _common_count_tx_power,
                                  ch_name,
                                  buf_p);
}


int
qsfp_get_transvr_rx_power(struct transvr_obj_s *self,
                          char *buf_p) {

    int lmax      = 8;
    int err_code  = DEBUG_TRANSVR_INT_VAL;
    char *ch_name = "RX";

    err_code = _check_by_mode(self,
                              &_qsfp_update_attr_curr_rx_power,
                              "qsfp_get_transvr_rx_power");
    if (err_code < 0) {
        return snprintf(buf_p, lmax, "%d\n", err_code);
    }
    if ((self->curr_tx_power[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    /* Return Unit: 1 mW */
    return _qsfp_get_channel_diag(self->curr_rx_power,
                                  _common_count_rx_power,
                                  ch_name,
                                  buf_p);
}


int
qsfp_get_wavelength(struct transvr_obj_s *self,
                    char *buf_p) {
    /* [Desc] Wavelength or Copper Cable Attenuation (SFF-8636)
     * [Addr] 00h 186-187
     * [Note]
     *  For optical free side devices, this parameter identifies the nominal
     *  transmitter output wavelength at room temperature. This parameter is
     *  a 16-bit hex value with Byte 186 as high order byte and Byte 187 as
     *  low order byte. The laser wavelength is equal to the 16-bit integer value
     *  divided by 20 in nm (units of 0.05 nm). This resolution should be adequate
     *  to cover all relevant wavelengths yet provide enough resolution for all
     *  expected DWDM applications. For accurate representation of controlled
     *  wavelength applications, this value should represent the center of the
     *  guaranteed wavelength range.
     *  If the free side device is identified as copper cable these registers will
     *  be used to define the cable attenuation. An indication of 0 dB attenuation
     *  refers to the case where the attenuation is not known or is unavailable.
     *  Byte 186 (00-FFh) is the copper cable attenuation at 2.5 GHz in units of 1 dB.
     *  Byte 187 (00-FFh) is the copper cable attenuation at 5.0 GHz in units of 1 dB.
     */
    int lmax     = 8;
    int err_code = DEBUG_TRANSVR_INT_VAL;

    err_code = _check_by_mode(self,
                              &_common_update_attr_wavelength,
                              "common_get_wavelength");
    if (err_code < 0) {
        return snprintf(buf_p, lmax, "%d\n", err_code);
    }
    if ((self->wavelength[0]) == DEBUG_TRANSVR_HEX_VAL) {
        return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL);
    }
    /* unit: 1 um */
    return snprintf(buf_p, lmax, "%d\n",
            _common_count_wavelength(self,
                                     self->wavelength[0],
                                     self->wavelength[1]));
}


/*  Public Function for Setup Features
 */
static int
__sfp_set_soft_rs(struct transvr_obj_s *self,
                  int input_val,
                  int address,
                  int page,
                  int offset,
                  int bit_shift,
                  uint8_t *attr_p,
                  char *caller,
                  int show_err) {

    int   retval   = ERR_TRANSVR_UNEXCPT;
    int   err_code = ERR_TRANSVR_UNEXCPT;
    char *err_msg  = DEBUG_TRANSVR_STR_VAL;
    uint8_t update_val = (*attr_p);

    switch (input_val) {
       case 0:
           SWP_BIT_CLEAR(update_val, bit_shift);
           break;
       case 1:
           SWP_BIT_SET(update_val, bit_shift);
           break;
       default:
           retval   = ERR_TRANSVR_UNEXCPT;
           err_code = ERR_TRANSVR_UNEXCPT;
           err_msg  = "Exception occurs";
           goto err_private_sfp_set_soft_rs_1;
    }
    err_code = _common_set_uint8_attr(self,
                                      address,
                                      page,
                                      offset,
                                      update_val,
                                      attr_p,
                                      caller,
                                      show_err);
    if (err_code < 0) {
        retval   = err_code;
        err_msg  = "Write data via i2c fail!";
        goto err_private_sfp_set_soft_rs_1;
    }
    (*attr_p) = update_val;
    return 0;

err_private_sfp_set_soft_rs_1:
    if (show_err) {
        SWPS_INFO("%s: %s <ERR>:%d <Port>:%s\n <Input>:%d\n",
                   __func__, err_msg, err_code, self->swp_name, input_val);
    }
    return retval;
}


static int
_sfp_set_soft_rs(struct transvr_obj_s *self,
                 int input_val,
                 int address,
                 int page,
                 int offset,
                 int bit_shift,
                 int (*attr_update_func)(struct transvr_obj_s *self, int show_err),
                 uint8_t *attr_p,
                 char *caller,
                 int show_err) {

    int retval    = ERR_TRANSVR_UNEXCPT;
    int err_code  = ERR_TRANSVR_UNEXCPT;
    char *err_msg = DEBUG_TRANSVR_STR_VAL;

    /* Check input value */
    if ((input_val != 0) && (input_val != 1)){
        retval   = ERR_TRANSVR_BADINPUT;
        err_code = ERR_TRANSVR_BADINPUT;
        err_msg  = "Input range incorrect!";
        goto err_common_sfp_set_soft_rs_1;
    }
    /* Check rate identifier is supported */
    err_code = self->get_rate_id(self);
    if (err_code <= 0) {
        switch (err_code) {
            case 0:
                retval  = ERR_TRANSVR_NOTSUPPORT;
                err_msg = "Not support this feature";
                break;
            case ERR_TRANSVR_UNINIT:
                retval  = ERR_TRANSVR_UNINIT;
                err_msg = "Check CDR present fail!";
                break;
            case ERR_TRANSVR_UNPLUGGED:
                retval  = ERR_TRANSVR_UNPLUGGED;
                err_msg = "Transceiver unplugged!";
                break;
            default:
                retval  = err_code;
                err_msg = "Check Rate_ID fail!";
                break;
        }
        goto err_common_sfp_set_soft_rs_1;
    }
    /* Check and update */
    err_code = _check_by_mode(self,
                              attr_update_func,
                              caller);
    if ( (err_code < 0) ||
         ((*attr_p) == DEBUG_TRANSVR_HEX_VAL) ){
        retval  = err_code;
        err_msg = "Get current value fail!";
        goto err_common_sfp_set_soft_rs_1;
    }
    /* Generate and update value */
    return __sfp_set_soft_rs(self,
                             input_val,
                             address,
                             page,
                             offset,
                             bit_shift,
                             attr_p,
                             caller,
                             show_err);

err_common_sfp_set_soft_rs_1:
    if (show_err) {
        SWPS_INFO("%s: %s <ERR>:%d <Port>:%s\n <Input>:%d\n",
                  __func__, err_msg, err_code, self->swp_name, input_val);
    }
    return retval;
}


int
sfp_set_soft_rs0(struct transvr_obj_s *self,
                 int input_val) {
    /* Note:
     *   SFP Soft Rate_Select Select RX ["RS(0)"] address
     *   A2h, offset: 110, bit 3
     */
    int bit_shift = 3;
    int show_err  = 1;
    return _sfp_set_soft_rs(self,
                            input_val,
                            self->eeprom_map_p->addr_soft_rs0,
                            self->eeprom_map_p->page_soft_rs0,
                            self->eeprom_map_p->offset_soft_rs0,
                            bit_shift,
                            &_sfp_update_attr_soft_rs0,
                            &(self->soft_rs0),
                            "sfp_set_soft_rs0",
                            show_err);
}


int
sfp_set_soft_rs1(struct transvr_obj_s *self,
                 int input_val) {
    /* Note:
     *   SFP Soft Rate_Select Select RX ["RS(1)"] address
     *   A2h, offset: 118, bit 3
     */
    int bit_shift = 3;
    int show_err  = 1;
    return _sfp_set_soft_rs(self,
                            input_val,
                            self->eeprom_map_p->addr_soft_rs1,
                            self->eeprom_map_p->page_soft_rs1,
                            self->eeprom_map_p->offset_soft_rs1,
                            bit_shift,
                            &_sfp_update_attr_soft_rs1,
                            &(self->soft_rs1),
                            "sfp_set_soft_rs1",
                            show_err);
}


int
__sfp_set_tx_eq(struct transvr_obj_s *self,
                int input,
                int show_e) {

    int     err  = DEBUG_TRANSVR_INT_VAL;
    char   *emsg = DEBUG_TRANSVR_STR_VAL;
    uint8_t setv = DEBUG_TRANSVR_HEX_VAL;

    if ((input < 0) || (input > 0xFF)) {
        emsg = "input incorrect";
        err = ERR_TRANSVR_BADINPUT;
        goto err_sfp_set_tx_eq;
    }
    setv = (uint8_t)input;
    if (self->tx_eq[0] == setv) {
        return 0;
    }
    err = _common_set_uint8_attr(self,
                                 self->eeprom_map_p->addr_tx_eq,
                                 self->eeprom_map_p->page_tx_eq,
                                 self->eeprom_map_p->offset_tx_eq,
                                 setv,
                                 &(self->tx_eq[0]),
                                 "_sfp_set_tx_eq",
                                 show_e);
    if (err < 0) {
        emsg = "set_uint8_attr fail";
        goto err_sfp_set_tx_eq;
    }
    return 0;

err_sfp_set_tx_eq:
    if (show_e) {
        SWPS_INFO("%s: %s <input>:%d\n", __func__, emsg, input);
    }
    return err;
}


int
_sfp_set_tx_eq(struct transvr_obj_s *self,
               int input,
               int show_e) {

    uint8_t tmp;
    int i = 0;
    int retry = 3;

    for (i=0; i<retry; i++) {
        if (__sfp_set_tx_eq(self, input, show_e) < 0){
            continue;
        }
        tmp = self->tx_eq[0];
        if (_sfp_update_attr_tx_eq(self, show_e) < 0){
            continue;
        }
        if (self->tx_eq[0] == tmp){
            return 0;
        }
    }
    return ERR_TRANSVR_UPDATE_FAIL;
}


int
sfp_set_tx_eq(struct transvr_obj_s *self,
              int input) {

    int err = _check_by_mode(self,
                             &_sfp_update_attr_tx_eq,
                             "sfp_set_tx_eq");
    if (err < 0) {
        SWPS_DEBUG("%s: check fail <err>:%d\n", __func__, err);
        return err;
    }
    return _sfp_set_tx_eq(self, input, 1);
}


int
__sfp_set_rx_em(struct transvr_obj_s *self,
                int input,
                int show_e) {

    int     err  = DEBUG_TRANSVR_INT_VAL;
    char   *emsg = DEBUG_TRANSVR_STR_VAL;
    uint8_t setv = DEBUG_TRANSVR_HEX_VAL;

    if ((input < 0) || (input > 0xFF)) {
        emsg = "input incorrect";
        err = ERR_TRANSVR_BADINPUT;
        goto err_sfp_set_rx_em;
    }
    setv = (uint8_t)input;
    if (self->rx_em[0] == setv) {
        return 0;
    }
    err = _common_set_uint8_attr(self,
                                 self->eeprom_map_p->addr_rx_em,
                                 self->eeprom_map_p->page_rx_em,
                                 self->eeprom_map_p->offset_rx_em,
                                 setv,
                                 &(self->rx_em[0]),
                                 "_sfp_set_rx_em",
                                 show_e);
    if (err < 0) {
        emsg = "set_uint8_attr fail";
        goto err_sfp_set_rx_em;
    }
    return 0;

err_sfp_set_rx_em:
    if (show_e) {
        SWPS_INFO("%s: %s <input>:%d\n", __func__, emsg, input);
    }
    return err;
}


int
_sfp_set_rx_em(struct transvr_obj_s *self,
               int input,
               int show_e) {

    uint8_t tmp;
    int i = 0;
    int retry = 3;

    for (i=0; i<retry; i++) {
        if (__sfp_set_rx_em(self, input, show_e) < 0){
            continue;
        }
        tmp = self->rx_em[0];
        if (_sfp_update_attr_rx_em(self, show_e) < 0){
            continue;
        }
        if (self->rx_em[0] == tmp){
            return 0;
        }
    }
    return -1;
}


int
sfp_set_rx_em(struct transvr_obj_s *self,
              int input) {

    int err = _check_by_mode(self,
                             &_sfp_update_attr_rx_em,
                             "sfp_set_rx_em");
    if (err < 0) {
        SWPS_DEBUG("%s: check fail <err>:%d\n", __func__, err);
        return err;
    }
    return _sfp_set_rx_em(self, input, 1);
}


int
sfp_set_1g_rj45_extphy_offset(struct transvr_obj_s *self,
                              int input) {

    if (self->state != STATE_TRANSVR_CONNECTED) {
        return ERR_TRANSVR_UNPLUGGED;
    }
    if ((self->info != TRANSVR_CLASS_BASE_T_1000) &&
        (self->info != TRANSVR_CLASS_BASE_T_1000_up) ){
        return ERR_TRANSVR_NOTSUPPORT;
    }
    if ((input < 0) || (input > 0xff)) {
        return ERR_TRANSVR_BADINPUT;
    }
    self->extphy_offset = (uint8_t)input;
    return 0;
}


int
sfp_set_1g_rj45_extphy_reg(struct transvr_obj_s *self,
                           int input) {

    int i      = 0;
    int retry  = 3;
    int delay  = 200;
    uint16_t tmp = 0;

    if (self->state != STATE_TRANSVR_CONNECTED) {
        return ERR_TRANSVR_UNPLUGGED;
    }
    if ((self->info != TRANSVR_CLASS_BASE_T_1000) &&
        (self->info != TRANSVR_CLASS_BASE_T_1000_up) ){
        return ERR_TRANSVR_NOTSUPPORT;
    }
    if ((input < 0) || (input > 0xffff)) {
        return ERR_TRANSVR_BADINPUT;
    }
    tmp = ((input & 0x00ff) << 8) | ((input & 0xff00) >> 8);
    if (_common_setup_page(self, VAL_TRANSVR_EXTPHY_ADDR_56,
                           -1, self->extphy_offset, 1, 0) < 0) {
        return -EIO;
    }
    for (i=0; i<=retry; i++) {
        if (i2c_smbus_write_word_data(self->i2c_client_p,
                                      self->extphy_offset,
                                      tmp) >= 0) {
            return 0;
        }
        msleep(delay);
    }
    SWPS_INFO("%s: retry:%d fail <port>:%s <offset>:0x%02x\n",
              __func__, retry, self->swp_name, self->extphy_offset);
    return -EIO;
}


static int
__qsfp_set_cdr(struct transvr_obj_s *self,
               int input_val,
               int show_err) {

    uint8_t update_val;
    int CDR_FEATURE_SUPPORTED = 0x3;
    int retval    = ERR_TRANSVR_UNEXCPT;
    int err_code  = ERR_TRANSVR_UNEXCPT;
    char *err_msg = DEBUG_TRANSVR_STR_VAL;
    char *func_name = "__qsfp_set_cdr";

    /* Check input value */
    if ((input_val < 0) || (input_val > 0xff)){
        retval   = ERR_TRANSVR_BADINPUT;
        err_code = ERR_TRANSVR_BADINPUT;
        err_msg  = "Input range incorrect!";
        goto err_qsfp_set_cdr_1;
    }
    update_val = (uint8_t)input_val;
    /* Check CDR supported by transceiver */
    err_code = qsfp_get_cdr_present(self);
    if (err_code < 0) {
        retval   = err_code;
        switch (err_code) {
            case ERR_TRANSVR_UNINIT:
                err_msg  = "Check CDR present fail!";
                break;
            case ERR_TRANSVR_UNPLUGGED:
                err_msg  = "Transceiver unplugged!";
                break;
            default:
                err_msg  = "Check CDR present fail!";
                break;
        }
        goto err_qsfp_set_cdr_1;
    }
    if (err_code != CDR_FEATURE_SUPPORTED) {
        retval   = ERR_TRANSVR_NOTSUPPORT;
        err_msg  = "This transceiver not support CDR!";
        goto err_qsfp_set_cdr_1;
    }
    /* Check and update */
    err_code = _check_by_mode(self,
                              &_qsfp_update_attr_cdr,
                              func_name);
    if ( (err_code < 0) ||
         (self->cdr == DEBUG_TRANSVR_HEX_VAL) ){
        retval   = err_code;
        err_msg  = "Get current value fail!";
        goto err_qsfp_set_cdr_1;
    }
    /* Write input value to transceiver */
    return _common_set_uint8_attr(self,
                                  self->eeprom_map_p->addr_cdr,
                                  self->eeprom_map_p->page_cdr,
                                  self->eeprom_map_p->offset_cdr,
                                  update_val,
                                  &(self->cdr),
                                  func_name,
                                  show_err);

err_qsfp_set_cdr_1:
    if (show_err) {
        SWPS_INFO("%s: %s <ERR>:%d <Port>:%s\n <Input>:%d\n",
                  __func__, err_msg, err_code, self->swp_name, input_val);
    }
    return retval;
}


int
qsfp_set_cdr(struct transvr_obj_s *self,
             int input_val) {
    return __qsfp_set_cdr(self, input_val, 1);
}


int
qsfp_set_soft_tx_disable(struct transvr_obj_s *self,
                         int input_val) {

    int show_err     = 1;
    int in_max       = 0xf; /* 1111 */
    int in_min       = 0x0; /* 0000 */
    int retval       = DEBUG_TRANSVR_INT_VAL;
    int update_val   = DEBUG_TRANSVR_INT_VAL;
    char err_msg[64] = DEBUG_TRANSVR_STR_VAL;

    retval = _check_by_mode(self,
                            &_qsfp_update_attr_soft_tx_disable,
                            "qsfp_set_soft_tx_disable");
    if (retval < 0) {
        snprintf(err_msg, 63, "Not ready. err:%d", retval);
        goto err_qsfp_set_soft_tx_disable;
    }
    if ((input_val > in_max) ||
        (input_val < in_min) ){
        retval = ERR_TRANSVR_BADINPUT;
        snprintf(err_msg, 63, "Input value:%d incorrect!", input_val);
        goto err_qsfp_set_soft_tx_disable;
    }
    if ((self->tx_disable & 0x0f) == input_val) {
        return 0;
    }
    update_val = ((self->tx_disable & 0xf0) & input_val);
    retval = _common_set_uint8_attr(self,
                                    self->eeprom_map_p->addr_tx_disable,
                                    self->eeprom_map_p->page_tx_disable,
                                    self->eeprom_map_p->offset_tx_disable,
                                    input_val,
                                    &(self->tx_disable),
                                    "qsfp_set_tx_disable",
                                    show_err);
    if (retval < 0) {
        snprintf(err_msg, 63, "_common_set_uint8_attr:%d fail!", retval);
        goto err_qsfp_set_soft_tx_disable;
    }
    return 0;

err_qsfp_set_soft_tx_disable:
    SWPS_INFO("%s: %s <port>:%s\n", __func__, err_msg, self->swp_name);
    return retval;
}


int
_qsfp_set_auto_tx_disable(struct transvr_obj_s *self,
                          uint8_t update) {

    uint8_t tx_enable = 0x0;
    int show_e = 1;
    int err    = DEBUG_TRANSVR_INT_VAL;
    char *emsg = DEBUG_TRANSVR_STR_VAL;

    /* Handle timing issues */
    if (update != tx_enable) {
        /* Note:
         *  Because there are some txvr has timing issues,
         *  therefore we need to execute reset cycle first.
         *  (enable -> other settings)
          */
        err = _common_set_uint8_attr(self,
                                     self->eeprom_map_p->addr_tx_disable,
                                     self->eeprom_map_p->page_tx_disable,
                                     self->eeprom_map_p->offset_tx_disable,
                                     tx_enable,
                                     &(self->tx_disable),
                                     "_qsfp_set_auto_tx_disable",
                                     show_e);
        if (err < 0) {
            emsg = "I2C set reset value fail";
            goto err_qsfp_set_auto_tx_disable;
        }
        mdelay(10);
    }
    /* Setup target value */
    err = _common_set_uint8_attr(self,
                                 self->eeprom_map_p->addr_tx_disable,
                                 self->eeprom_map_p->page_tx_disable,
                                 self->eeprom_map_p->offset_tx_disable,
                                 self->auto_tx_disable,
                                 &(self->tx_disable),
                                 "_qsfp_set_auto_tx_disable",
                                 show_e);
    if (err < 0) {
        emsg = "I2C set target value fail";
        goto err_qsfp_set_auto_tx_disable;
    }
    /* Check and update */
    err = _common_update_uint8_attr(self,
                                    self->eeprom_map_p->addr_tx_disable,
                                    self->eeprom_map_p->page_tx_disable,
                                    self->eeprom_map_p->offset_tx_disable,
                                    self->eeprom_map_p->length_tx_disable,
                                    &(self->tx_disable),
                                    "_qsfp_set_auto_tx_disable",
                                    show_e);
    if (err < 0) {
        emsg = "I2C get value fail";
        goto err_qsfp_set_auto_tx_disable;
    }
    if (self->tx_disable != update) {
        emsg = "data not become effective";
        goto err_qsfp_set_auto_tx_disable;
    }
    return 0;

err_qsfp_set_auto_tx_disable:
    SWPS_DEBUG("%s: %s <port>:%s\n",
               __func__, emsg, self->swp_name);
    return ERR_TRANSVR_UPDATE_FAIL;
}


int
qsfp_set_auto_tx_disable(struct transvr_obj_s *self,
                         int input_val) {

    int in_max = 0xf; /* 1111 */
    int in_min = 0x0; /* 0000 */
    int retval = DEBUG_TRANSVR_INT_VAL;
    char *emsg = DEBUG_TRANSVR_STR_VAL;

    /* Update settings*/
    if (input_val == VAL_TRANSVR_FUNCTION_DISABLE) {
        emsg = "User disable auto tx_disable";
        self->auto_tx_disable = VAL_TRANSVR_FUNCTION_DISABLE;
        goto out_qsfp_set_auto_tx_disable;
    }
    if ((input_val > in_max) || (input_val < in_min) ){
        SWPS_INFO("%s: Input value:%d incorrect! <port>:%s\n",
                  __func__, input_val, self->swp_name);
        return ERR_TRANSVR_BADINPUT;
    }
    self->auto_tx_disable = input_val;
    /* Check current soft tx_disable */
    retval = _check_by_mode(self,
                            &_qsfp_update_attr_soft_tx_disable,
                            "qsfp_set_auto_tx_disable");
    switch (retval) {
        case 0:
            break;
        case ERR_TRANSVR_UNPLUGGED:
            emsg = "Doesn't need to update";
            goto out_qsfp_set_auto_tx_disable;
        default:
            SWPS_INFO("%s: setup fail <err>:%d <port>:%s\n",
                      __func__, retval, self->swp_name);
            return retval;
    }
    return _qsfp_set_auto_tx_disable(self, input_val);

out_qsfp_set_auto_tx_disable:
    SWPS_DEBUG("%s: %s <port>:%s <input>:%d\n <ret>:%d",
               __func__, emsg, self->swp_name, input_val, retval);
    return 0;
}


int
__qsfp_set_tx_eq(struct transvr_obj_s *self,
                 int input,
                 int show_e) {
    /* [Note]
     *   0x<CH-1><CH-2><CH-3><CH-4>
     */
    int   err  = DEBUG_TRANSVR_INT_VAL;
    char *emsg = DEBUG_TRANSVR_STR_VAL;
    uint8_t setv[2] = {0x00, 0x00};

    if ((input < 0) || (input > 0xFFFF)) {
        emsg = "input incorrect";
        err = ERR_TRANSVR_BADINPUT;
        goto err_qsfp_set_tx_eq;
    }
    setv[0] = (uint8_t)((input & 0xFF00) >> 8);
    setv[1] = (uint8_t)(input & 0xFF);
    if ((self->tx_eq[0] == setv[0]) &&
        (self->tx_eq[1] == setv[1]) ) {
        return 0;
    }
    err = _common_set_uint8_array(self,
                                  self->eeprom_map_p->addr_tx_eq,
                                  self->eeprom_map_p->page_tx_eq,
                                  self->eeprom_map_p->offset_tx_eq,
                                  self->eeprom_map_p->length_tx_eq,
                                  setv,
                                  self->tx_eq,
                                  "_qsfp_set_tx_eq",
                                  show_e);
    if (err < 0) {
        emsg = "set_uint8_array fail";
        goto err_qsfp_set_tx_eq;
    }
    return 0;

err_qsfp_set_tx_eq:
    if (show_e) {
        SWPS_INFO("%s: %s <input>:%d\n", __func__, emsg, input);
    }
    return err;
}


int
_qsfp_set_tx_eq(struct transvr_obj_s *self,
                int input,
                int show_e) {

    int i = 0;
    int retry = 3;
    uint8_t tmp[2];

    for (i=0; i<retry; i++) {
        if (__qsfp_set_tx_eq(self, input, show_e) < 0){
            continue;
        }
        tmp[0] = self->tx_eq[0];
        tmp[1] = self->tx_eq[1];
        if (_qsfp_update_attr_tx_eq(self, show_e) < 0){
            continue;
        }
        if ((self->tx_eq[0] == tmp[0]) &&
            (self->tx_eq[1] == tmp[1]) ){
            return 0;
        }
    }
    return -1;
}


int
qsfp_set_tx_eq(struct transvr_obj_s *self,
               int input) {

    int err = _check_by_mode(self,
                             &_qsfp_update_attr_tx_eq,
                             "qsfp_set_tx_eq");
    if (err < 0) {
        SWPS_DEBUG("%s: check fail <err>:%d\n", __func__, err);
        return err;
    }
    return _qsfp_set_tx_eq(self, input, 1);
}


int
__qsfp_set_rx_am(struct transvr_obj_s *self,
                 int input,
                 int show_e) {
    /* [Note]
     *   0x<CH-1><CH-2><CH-3><CH-4>
     */
    int   err  = DEBUG_TRANSVR_INT_VAL;
    char *emsg = DEBUG_TRANSVR_STR_VAL;
    uint8_t setv[2] = {0x00, 0x00};

    if ((input < 0) || (input > 0xFFFF)) {
        emsg = "input incorrect";
        err = ERR_TRANSVR_BADINPUT;
        goto err_qsfp_set_rx_am;
    }
    setv[0] = (uint8_t)((input & 0xFF00) >> 8);
    setv[1] = (uint8_t)(input & 0xFF);
    if ((self->rx_am[0] == setv[0]) &&
        (self->rx_am[1] == setv[1]) ) {
        return 0;
    }
    err = _common_set_uint8_array(self,
                                  self->eeprom_map_p->addr_rx_am,
                                  self->eeprom_map_p->page_rx_am,
                                  self->eeprom_map_p->offset_rx_am,
                                  self->eeprom_map_p->length_rx_am,
                                  setv,
                                  self->rx_am,
                                  "_qsfp_set_rx_am",
                                  show_e);
    if (err < 0) {
        emsg = "set_uint8_array fail";
        goto err_qsfp_set_rx_am;
    }
    return 0;

err_qsfp_set_rx_am:
    if (show_e) {
        SWPS_INFO("%s: %s <input>:%d\n", __func__, emsg, input);
    }
    return err;
}


int
_qsfp_set_rx_am(struct transvr_obj_s *self,
                int input,
                int show_e) {

    int i = 0;
    int retry = 3;
    uint8_t tmp[2];

    for (i=0; i<retry; i++) {
        if (__qsfp_set_rx_am(self, input, show_e) < 0){
            continue;
        }
        tmp[0] = self->rx_am[0];
        tmp[1] = self->rx_am[1];
        if (_qsfp_update_attr_rx_am(self, show_e) < 0){
            continue;
        }
        if ((self->rx_am[0] == tmp[0]) &&
            (self->rx_am[1] == tmp[1]) ){
            return 0;
        }
    }
    return -1;
}


int
qsfp_set_rx_am(struct transvr_obj_s *self,
               int input) {

    int err = _check_by_mode(self,
                             &_qsfp_update_attr_rx_am,
                             "qsfp_set_rx_am");
    if (err < 0) {
        SWPS_DEBUG("%s: check fail <err>:%d\n", __func__, err);
        return err;
    }
    return _qsfp_set_rx_am(self, input, 1);
}


int
__qsfp_set_rx_em(struct transvr_obj_s *self,
                 int input,
                 int show_e) {
    /* [Note]
     *   0x<CH-1><CH-2><CH-3><CH-4>
     */
    int   err  = DEBUG_TRANSVR_INT_VAL;
    char *emsg = DEBUG_TRANSVR_STR_VAL;
    uint8_t setv[2] = {0x00, 0x00};

    if ((input < 0) || (input > 0xFFFF)) {
        emsg = "input incorrect";
        err = ERR_TRANSVR_BADINPUT;
        goto err_qsfp_set_rx_em;
    }
    setv[0] = (uint8_t)((input & 0xFF00) >> 8);
    setv[1] = (uint8_t)(input & 0xFF);
    if ((self->rx_em[0] == setv[0]) &&
        (self->rx_em[1] == setv[1]) ) {
        return 0;
    }
    err = _common_set_uint8_array(self,
                                  self->eeprom_map_p->addr_rx_em,
                                  self->eeprom_map_p->page_rx_em,
                                  self->eeprom_map_p->offset_rx_em,
                                  self->eeprom_map_p->length_rx_em,
                                  setv,
                                  self->rx_em,
                                  "_qsfp_set_rx_em",
                                  show_e);
    if (err < 0) {
        emsg = "set_uint8_array fail";
        goto err_qsfp_set_rx_em;
    }
    return 0;

err_qsfp_set_rx_em:
    if (show_e) {
        SWPS_INFO("%s: %s <input>:%d\n", __func__, emsg, input);
    }
    return err;
}


int
_qsfp_set_rx_em(struct transvr_obj_s *self,
                int input,
                int show_e) {

    int i = 0;
    int retry = 3;
    uint8_t tmp[2];

    for (i=0; i<retry; i++) {
        if (__qsfp_set_rx_em(self, input, show_e) < 0){
            continue;
        }
        tmp[0] = self->rx_em[0];
        tmp[1] = self->rx_em[1];
        if (_qsfp_update_attr_rx_em(self, show_e) < 0){
            continue;
        }
        if ((self->rx_em[0] == tmp[0]) &&
            (self->rx_em[1] == tmp[1]) ){
            return 0;
        }
    }
    return -1;
}


int
qsfp_set_rx_em(struct transvr_obj_s *self,
               int input) {

    int err = _check_by_mode(self,
                             &_qsfp_update_attr_rx_em,
                             "qsfp_set_rx_em");
    if (err < 0) {
        SWPS_DEBUG("%s: check fail <err>:%d\n", __func__, err);
        return err;
    }
    return _qsfp_set_rx_em(self, input, 1);
}


int
common_transvr_dump(struct transvr_obj_s* self){

    char *type_name = "Undefined";

    if (TRANSVR_INFO_DUMP_ENABLE != 1) {
        return 0;
    }
    switch (self->type) {
        case TRANSVR_TYPE_SFP:
            type_name = STR_TRANSVR_SFP;
            break;
        case TRANSVR_TYPE_QSFP:
            type_name = STR_TRANSVR_QSFP;
            break;
        case TRANSVR_TYPE_QSFP_PLUS:
            type_name = STR_TRANSVR_QSFP_PLUS;
            break;
        case TRANSVR_TYPE_QSFP_28:
            type_name = STR_TRANSVR_QSFP28;
            break;
        case TRANSVR_TYPE_FAKE:
            type_name = "FAKE";
            goto ok_common_transvr_dump;
        case TRANSVR_TYPE_UNPLUGGED:
            type_name = "UNPLUGGED";
            goto err_common_transvr_dump;
        case TRANSVR_TYPE_INCONSISTENT:
            type_name = "INCONSISTENT";
            goto err_common_transvr_dump;
        case TRANSVR_TYPE_ERROR:
            type_name = "ERROR";
            goto err_common_transvr_dump;

        default:
            type_name = "UNEXPECTED";
            goto err_common_transvr_dump;
    }
    printk(KERN_INFO "[SWPS] Dump %s information:\n", self->swp_name);
    printk(KERN_INFO "       |- <Type>:%s\n", type_name);
    printk(KERN_INFO "       |- <VenderName>:%s\n", self->vendor_name);
    printk(KERN_INFO "       |- <VenderPN>:%s\n", self->vendor_pn);
    printk(KERN_INFO "       |- <VenderREV>:%s\n", self->vendor_rev);
    printk(KERN_INFO "       |- <VenderSN>:%s\n", self->vendor_sn);
    printk(KERN_INFO "       |- <BitRate>:0x%02x\n", self->br);
    printk(KERN_INFO "       |- <RevComp>:0x%02x\n", self->comp_rev);
    printk(KERN_INFO "       |- <LenOM1>:%d\n", self->len_om1);
    printk(KERN_INFO "       |- <LenOM2>:%d\n", self->len_om2);
    printk(KERN_INFO "       |- <LenOM3>:%d\n", self->len_om3);
    printk(KERN_INFO "       |- <LenOM4>:%d\n", self->len_om4);
    return 0;

ok_common_transvr_dump:
    SWPS_INFO("%s: %s is %s\n", __func__, self->swp_name, type_name);
    return 0;

err_common_transvr_dump:
    SWPS_INFO("%s: %s is %s\n", __func__, self->swp_name, type_name);
    return -1;
}


int
sfp_transvr_dump(struct transvr_obj_s* self) {

    if (TRANSVR_INFO_DUMP_ENABLE != 1) {
        return 0;
    }
    if (common_transvr_dump(self) < 0) {
        return -1;
    }
    printk(KERN_INFO "       |- <LenSM>:%d\n", self->len_sm);
    printk(KERN_INFO "       |- <LenSMF>:%d\n", self->len_smf);
    printk(KERN_INFO "       '- <RateID>:0x%02x\n", self->rate_id);
    return 0;
}


int
qsfp_transvr_dump(struct transvr_obj_s* self) {

    if (TRANSVR_INFO_DUMP_ENABLE != 1) {
        return 0;
    }
    if (common_transvr_dump(self) < 0) {
        return -1;
    }
    printk(KERN_INFO "       |- <LenSMF>:%d\n", self->len_smf);
    printk(KERN_INFO "       '- <PowerClass>:Class_%d\n", __qsfp_get_power_cls(self, 0));
    return 0;
}


int
fake_transvr_dump(struct transvr_obj_s* self) {

    printk(KERN_INFO "[SWPS] Dump transceiver information: %s\n", self->swp_name);
    printk(KERN_INFO "       |- <Type>:FAKE\n");
    printk(KERN_INFO "       |- <VenderName>:FAKE_VENDER_NAME\n");
    printk(KERN_INFO "       |- <VenderPN>:FAKE_VENDER_PN\n");
    printk(KERN_INFO "       |- <VenderREV>:FAKE_VENDER_REV\n");
    printk(KERN_INFO "       |- <VenderSN>:FAKE_VENDER_SN\n");
    printk(KERN_INFO "       |- <BitRate>:0x99\n");
    printk(KERN_INFO "       |- <LenOM1>:99\n");
    printk(KERN_INFO "       |- <LenOM2>:99\n");
    printk(KERN_INFO "       |- <LenOM3>:99\n");
    printk(KERN_INFO "       |- <LenOM4>:99\n");
    printk(KERN_INFO "       |- <LenSM>:99\n");
    printk(KERN_INFO "       |- <LenSMF>:99\n");
    printk(KERN_INFO "       '- <RevComp>:0x99\n");
    return 0;
}


/* ========== Object functions for fake type ==========
 */
int
fake_transvr_update(struct transvr_obj_s *self,
                    int show_err){
    self->state = STATE_TRANSVR_CONNECTED;
    return 0;
}


int
fake_get_binary(struct transvr_obj_s *self){
    return 1;
}

int
fake_get_int(struct transvr_obj_s *self){
    return 99;
}


int
fake_get_hex(struct transvr_obj_s *self){
    return 0x0f;
}


int
fake_get_str(struct transvr_obj_s *self, char *buf) {
    return snprintf(buf, 16, "fake_get_str\n");
}


int
fake_set_int(struct transvr_obj_s *self, int input){
    SWPS_INFO("%s: %d\n", __func__, input);
    return 0;
}


int
fake_set_hex(struct transvr_obj_s *self, int input){
    SWPS_INFO("%s: 0x%02x\n", __func__, input);
    return 0;
}


/* ========== Object functions for unsupported ==========
 */
int
unsupported_get_func(struct transvr_obj_s *self){
    return ERR_TRANSVR_NOTSUPPORT;
}


int
unsupported_get_func2(struct transvr_obj_s *self,
                      char *buf_p) {
    int len = snprintf(buf_p, 8, "%d\n", ERR_TRANSVR_NOTSUPPORT);
    return len;
}


int
unsupported_set_func(struct transvr_obj_s *self,
                     int input_val){
    return ERR_TRANSVR_NOTSUPPORT;
}



/* ========== Object functions for long term task ==========
 *
 * [Note]
 *   SWPS transceiver worker is likely the green-thread (coroutine).
 *   Due to resource and performance considerations. SWPS run all
 *   features in one kthread at the same time, and handle by it self.
 */

/* For Transceiver Task Handling
 */
static struct transvr_worker_s *
transvr_task_get(struct transvr_obj_s *self,
                 char *func_name) {

    struct transvr_worker_s *curr_p = self->worker_p;

    while(curr_p != NULL){
        if (strcmp((curr_p->func_name), func_name) == 0 ) {
            return curr_p;
        }
        curr_p = curr_p->next_p;
    }
    return NULL;
}


static struct transvr_worker_s*
transvr_task_creat(struct transvr_obj_s *self,
                   int (*main_task)(struct transvr_worker_s *task),
                   int (*post_task)(struct transvr_worker_s *task),
                   char *caller) {

    struct transvr_worker_s *task_p = NULL;
    struct transvr_worker_s *curr_p = NULL;
    char err_msg[64] = DEBUG_TRANSVR_STR_VAL;

    /* Check task not exist */
    task_p = transvr_task_get(self, caller);
    if (task_p) {
        snprintf(err_msg, sizeof(err_msg), "Task already created!");
        goto err_transvr_task_creat;
    }
    /* Create task worker */
    task_p = kzalloc(sizeof(struct transvr_worker_s), GFP_KERNEL);
    if (!task_p){
        snprintf(err_msg, sizeof(err_msg), "kzalloc fail");
        goto err_transvr_task_creat;
    }
    /* Setup task data */
    task_p->transvr_p    = self;
    task_p->next_p       = NULL;
    task_p->trigger_time = 0;
    task_p->retry        = 1;
    task_p->state        = STATE_T_TASK_INIT;
    task_p->main_task    = main_task;
    task_p->post_task    = post_task;
    task_p->p_data       = NULL;
    snprintf(task_p->func_name, sizeof(task_p->func_name), "%s", caller);
    /* Setup Link List */
    if (self->worker_p) {
        curr_p = self->worker_p;
        while(curr_p->next_p != NULL) {
            curr_p = curr_p->next_p;
        }
        curr_p->next_p = task_p;
        task_p->pre_p  = curr_p;
    } else {
        self->worker_p = task_p;
        task_p->pre_p  = NULL;
    }
    return task_p;

err_transvr_task_creat:
    SWPS_ERR("%s: %s <caller>:%s <port>:%s\n",
            __func__, err_msg, caller, self->swp_name);
    return NULL;
}


static void
transvr_task_free_one(struct transvr_worker_s *task_p){

    struct transvr_worker_s *pre_p  = NULL;
    struct transvr_worker_s *next_p = NULL;

    if (task_p) {
        pre_p  = task_p->pre_p;
        next_p = task_p->next_p;

        if ((pre_p) && (next_p)) {
            pre_p->next_p = next_p;
            next_p->pre_p = pre_p;

        } else if ((!pre_p) && (next_p)) {
            next_p->pre_p = NULL;

        } else if ((pre_p) && (!next_p)) {
            pre_p->next_p = NULL;

        } else if ((!pre_p) && (!next_p)) {
            task_p->transvr_p->worker_p = NULL;
        } else {
            SWPS_ERR("%s: Unexcept case!\n <port>:%s",
                    __func__, task_p->transvr_p->swp_name);
        }
        kfree(task_p->p_data);
        kfree(task_p);
    }
}


static void
transvr_task_free_all(struct transvr_obj_s *self) {

    struct transvr_worker_s *curr_p = NULL;
    struct transvr_worker_s *next_p = NULL;

    if (self->worker_p) {
        curr_p = self->worker_p;
        while(curr_p) {
            next_p = curr_p->next_p;
            transvr_task_free_one(curr_p);
            curr_p = next_p;
        }
        self->worker_p = NULL;
    }
}


static void
transvr_cache_free_all(struct transvr_obj_s *self) {

    memset(self->vendor_name, 0, (LEN_TRANSVR_M_STR * sizeof(char)) );
    memset(self->vendor_rev,  0, (LEN_TRANSVR_M_STR * sizeof(char)) );
    memset(self->vendor_pn,   0, (LEN_TRANSVR_M_STR * sizeof(char)) );
    memset(self->vendor_sn,   0, (LEN_TRANSVR_M_STR * sizeof(char)) );
    self->extphy_offset = 0;
}

static int
_transvr_task_run_main(struct transvr_worker_s *task_p) {

    int retval = DEBUG_TRANSVR_INT_VAL;
    char err_msg[64]  = DEBUG_TRANSVR_STR_VAL;

    if (!task_p){
        snprintf(err_msg, sizeof(err_msg), "main_task is NULL!");
        goto main_transvr_task_err;
    }
    if ((task_p->trigger_time) == 0){
        goto main_transvr_task_run;
    }
    if (time_before(jiffies, task_p->trigger_time)){
        goto main_transvr_task_wait;
    }
    goto main_transvr_task_run;

main_transvr_task_run:
    if (task_p->retry != VAL_TRANSVR_TASK_RETRY_FOREVER) {
        task_p->retry -= 1;
    }
    retval = task_p->main_task(task_p);
    if (retval < 0) {
        if (task_p->retry > 0) {
            task_p->state = STATE_T_TASK_WAIT;
            return EVENT_TRANSVR_TASK_WAIT;
        }
        snprintf(err_msg, sizeof(err_msg), "Run main_task fail!");
        goto main_transvr_task_err;
    }
    goto main_transvr_task_identify;

main_transvr_task_identify:
    switch (retval) {
        case EVENT_TRANSVR_TASK_WAIT:
            task_p->state = STATE_T_TASK_WAIT;
            return EVENT_TRANSVR_TASK_WAIT;

        case EVENT_TRANSVR_TASK_DONE:
            task_p->state = STATE_T_TASK_DONE;
            return EVENT_TRANSVR_TASK_DONE;

    default:
        break;
    }
    snprintf(err_msg, sizeof(err_msg), "Run main_task fail!");
    goto main_transvr_task_err;

main_transvr_task_wait:
    task_p->state = STATE_T_TASK_WAIT;
    return EVENT_TRANSVR_TASK_WAIT;

main_transvr_task_err:
    task_p->state = STATE_T_TASK_FAIL;
    SWPS_INFO("%s: %s <rval>:%d <port>:%s\n",
            __func__, err_msg, retval, task_p->transvr_p->swp_name);
    return EVENT_TRANSVR_INIT_FAIL;
}


static int
_transvr_task_run_post(struct transvr_worker_s *task_p) {

    char err_msg[64]  = DEBUG_TRANSVR_STR_VAL;

    if ((task_p->post_task) == NULL) {
        return EVENT_TRANSVR_TASK_DONE;
    }
    switch (task_p->state) {
        case STATE_T_TASK_WAIT:
        case STATE_T_TASK_INIT:
            goto post_transvr_task_wait;

        case STATE_T_TASK_DONE:
        case STATE_T_TASK_FAIL:
            goto post_transvr_task_run;

    default:
        break;
    }
    snprintf(err_msg, sizeof(err_msg), "Unexcept task state");
    goto post_transvr_task_err;

post_transvr_task_run:
    task_p->post_task(task_p);
    return EVENT_TRANSVR_TASK_DONE;

post_transvr_task_wait:
    return EVENT_TRANSVR_TASK_WAIT;

post_transvr_task_err:
    SWPS_INFO("%s: %s <state>:%d <port>:%s\n",
              __func__, err_msg, task_p->state, task_p->transvr_p->swp_name);
    return EVENT_TRANSVR_TASK_FAIL;
}


static int
transvr_task_run_one(struct transvr_worker_s *task_p) {

    int retval_main  = DEBUG_TRANSVR_INT_VAL;
    int retval_post  = DEBUG_TRANSVR_INT_VAL;
    char err_msg[64] = DEBUG_TRANSVR_STR_VAL;

    retval_main = _transvr_task_run_main(task_p);
    if (retval_main < 0) {
        snprintf(err_msg, sizeof(err_msg), "Execute main_task fail!");
        goto err_transvr_task_run_one;
    }
    retval_post = _transvr_task_run_post(task_p);
    if (retval_post < 0) {
        snprintf(err_msg, sizeof(err_msg), "Execute post_task fail!");
        goto err_transvr_task_run_one;
    }
    return retval_main;

err_transvr_task_run_one:
    SWPS_INFO("%s: %s <main>:%d <post>:%d <caller>:%s <port>:%s\n",
              __func__, err_msg, retval_main, retval_post,
              task_p->func_name, task_p->transvr_p->swp_name);
    return EVENT_TRANSVR_TASK_FAIL;
}


static int
transvr_task_run_all(struct transvr_obj_s *self) {

    int haserr = 0;
    int retval = DEBUG_TRANSVR_INT_VAL;
    struct transvr_worker_s *curr_p = NULL;
    struct transvr_worker_s *next_p = NULL;

    if ((self->worker_p) == NULL) {
        return EVENT_TRANSVR_TASK_DONE;
    }
    curr_p = self->worker_p;
    while (curr_p != NULL) {
        next_p = curr_p->next_p;
        retval = transvr_task_run_one(curr_p);
        if (curr_p->retry == VAL_TRANSVR_TASK_RETRY_FOREVER) {
            curr_p = next_p;
            continue;
        }
        switch (retval) {
            case EVENT_TRANSVR_TASK_WAIT:
                break;
            case EVENT_TRANSVR_TASK_DONE:
                transvr_task_free_one(curr_p);
                break;
            case EVENT_TRANSVR_TASK_FAIL:

            default:
                haserr = 1;
                transvr_task_free_one(curr_p);
                break;
        }
        curr_p = next_p;
    }
    if (haserr) {
        return EVENT_TRANSVR_TASK_FAIL;
    }
    return EVENT_TRANSVR_TASK_DONE;
}


static void
transvr_task_set_delay(struct transvr_worker_s *task_p,
                       unsigned long delay_msec) {

    task_p->trigger_time = (jiffies + (delay_msec * (HZ/1000)));
}


static void
transvr_task_set_retry(struct transvr_worker_s *task_p,
                       unsigned long retry_times) {

    task_p->retry = retry_times;
}


/* For Transceiver Post Task
 */
int
taskfunc_post_do_nothing(struct transvr_worker_s *task_p) {

    return EVENT_TRANSVR_TASK_DONE;
}


int
taskfunc_post_handle_task_state(struct transvr_worker_s *task_p) {

    struct transvr_obj_s* tp = task_p->transvr_p;

    switch (task_p->state) {
        case STATE_T_TASK_INIT:
        case STATE_T_TASK_WAIT:
            return EVENT_TRANSVR_TASK_WAIT;

        case STATE_T_TASK_DONE:
            tp->state = STATE_TRANSVR_CONNECTED;
            tp->send_uevent(tp, KOBJ_ADD);
            return EVENT_TRANSVR_TASK_DONE;

        case STATE_T_TASK_FAIL:
            tp->state = STATE_TRANSVR_UNEXCEPTED;
            return EVENT_TRANSVR_TASK_FAIL;

        default:
            break;
    }
    return EVENT_TRANSVR_TASK_FAIL;
}


/* For Transceiver Main Task
 */
int
_taskfunc_sfp_setup_soft_rs(struct transvr_worker_s *task_p,
                            int input_val,
                            int address,
                            int page,
                            int offset,
                            int bit_shift,
                            uint8_t *attr_p,
                            char *caller) {

    int show_err = 0;
    int err_code = DEBUG_TRANSVR_INT_VAL;
    char *err_str  = DEBUG_TRANSVR_STR_VAL;
    char *func_str = "_taskfunc_sfp_setup_soft_rs";

    err_code = _sfp_update_attr_soft_rs0(task_p->transvr_p, 0);
    if (err_code < 0) {
        err_str = "Get current soft_rs0 fail!";
        goto err_taskfunc_sfp_setup_soft_rs_1;
    }
    err_code = __sfp_set_soft_rs(task_p->transvr_p,
                                 input_val,
                                 address,
                                 page,
                                 offset,
                                 bit_shift,
                                 attr_p,
                                 caller,
                                 show_err);
    if (err_code < 0) {
        err_str = "Get current soft_rs0 fail!";
        goto err_taskfunc_sfp_setup_soft_rs_1;
    }
    return EVENT_TRANSVR_TASK_DONE;

err_taskfunc_sfp_setup_soft_rs_1:
    if ((task_p->retry) == 0) {
        SWPS_INFO("%s: %s <port>:%s <input>:%d <err>:%d\n",
                  func_str, err_str, task_p->transvr_p->swp_name, input_val, err_code);
    }
    return EVENT_TRANSVR_TASK_FAIL;
}


int
__taskfunc_sfp_setup_hard_rs(struct transvr_worker_s *task_p,
                             int input_val,
                             int (*get_func)(struct ioexp_obj_s *self, int virt_offset),
                             int (*set_func)(struct ioexp_obj_s *self, int virt_offset, int input_val)) {

    int err_val    = EVENT_TRANSVR_EXCEP_EXCEP;
    char *err_str  = DEBUG_TRANSVR_STR_VAL;

    err_val = get_func(task_p->transvr_p->ioexp_obj_p,
                       task_p->transvr_p->ioexp_virt_offset);

    if (err_val < 0) {
        if (err_val == ERR_IOEXP_NOTSUPPORT) {
            return EVENT_TRANSVR_TASK_DONE;
        }
        err_str = "Get current hard_rs fail!";
        goto err_p_taskfunc_sfp_setup_hard_rs_1;
    }
    if (err_val == input_val) {
        return EVENT_TRANSVR_TASK_DONE;
    }
    err_val = set_func(task_p->transvr_p->ioexp_obj_p,
                       task_p->transvr_p->ioexp_virt_offset,
                       input_val);
    if (err_val < 0) {
        err_str = "Setup hard_rs fail!";
        goto err_p_taskfunc_sfp_setup_hard_rs_1;
    }
    return EVENT_TRANSVR_TASK_DONE;

err_p_taskfunc_sfp_setup_hard_rs_1:
    if ((task_p->retry) == 0) {
        SWPS_INFO("%s: %s <port>:%s <input>:%d <err>:%d\n",
                  __func__, err_str, task_p->transvr_p->swp_name, input_val, err_val);
    }
    return EVENT_TRANSVR_TASK_FAIL;
}


int
_taskfunc_sfp_setup_hard_rs0(struct transvr_worker_s *task_p,
                             int input_val) {

    return __taskfunc_sfp_setup_hard_rs(task_p,
                                        input_val,
                                        task_p->transvr_p->ioexp_obj_p->get_hard_rs0,
                                        task_p->transvr_p->ioexp_obj_p->set_hard_rs0);
}


int
_taskfunc_sfp_setup_hard_rs1(struct transvr_worker_s *task_p,
                             int input_val) {

    return __taskfunc_sfp_setup_hard_rs(task_p,
                                        input_val,
                                        task_p->transvr_p->ioexp_obj_p->get_hard_rs1,
                                        task_p->transvr_p->ioexp_obj_p->set_hard_rs1);
}


int
_taskfunc_sfp_setup_rs0(struct transvr_worker_s *task_p,
                        int input_val) {

    int  bit_shift = 3;
    int  old_val   = DEBUG_TRANSVR_INT_VAL;
    int  err_val   = EVENT_TRANSVR_EXCEP_EXCEP;
    char *err_str  = DEBUG_TRANSVR_STR_VAL;
    char *func_str = "_taskfunc_sfp_setup_rs0";

    err_val = _taskfunc_sfp_setup_hard_rs0(task_p,
                                           input_val);
    if (err_val < 0) {
        err_str = "Setup hard_rs0 fail!";
        goto err_private_taskfunc_sfp_setup_rs0_1;
    }
    old_val = err_val;
    err_val = _taskfunc_sfp_setup_soft_rs(task_p,
                                          input_val,
                                          task_p->transvr_p->eeprom_map_p->addr_soft_rs0,
                                          task_p->transvr_p->eeprom_map_p->page_soft_rs0,
                                          task_p->transvr_p->eeprom_map_p->offset_soft_rs0,
                                          bit_shift,
                                          &(task_p->transvr_p->soft_rs0),
                                          func_str);
    if (err_val < 0) {
        err_str = "Setup soft_rs0 fail!";
        goto err_private_taskfunc_sfp_setup_rs0_1;
    }
    return EVENT_TRANSVR_TASK_DONE;

err_private_taskfunc_sfp_setup_rs0_1:
    if ((task_p->retry) == 0) {
        SWPS_INFO("%s: %s <port>:%s <input>:%d <err>:%d\n",
                  func_str, err_str, task_p->transvr_p->swp_name, input_val, err_val);
    }
    _taskfunc_sfp_setup_hard_rs0(task_p, old_val);
    return EVENT_TRANSVR_TASK_FAIL;
}


int
_taskfunc_sfp_setup_rs1(struct transvr_worker_s *task_p,
                        int input_val) {

    int  bit_shift = 3;
    int  old_val   = DEBUG_TRANSVR_INT_VAL;
    int  err_val   = EVENT_TRANSVR_EXCEP_EXCEP;
    char *err_str  = DEBUG_TRANSVR_STR_VAL;
    char *func_str = "_taskfunc_sfp_setup_rs1";

    err_val = _taskfunc_sfp_setup_hard_rs1(task_p,
                                           input_val);
    if (err_val < 0) {
        err_str = "Setup hard_rs1 fail!";
        goto err_private_taskfunc_sfp_setup_rs1_1;
    }
    old_val = err_val;
    err_val = _taskfunc_sfp_setup_soft_rs(task_p,
                                          input_val,
                                          task_p->transvr_p->eeprom_map_p->addr_soft_rs1,
                                          task_p->transvr_p->eeprom_map_p->page_soft_rs1,
                                          task_p->transvr_p->eeprom_map_p->offset_soft_rs1,
                                          bit_shift,
                                          &(task_p->transvr_p->soft_rs1),
                                          func_str);
    if (err_val < 0) {
        err_str = "Setup soft_rs1 fail!";
        goto err_private_taskfunc_sfp_setup_rs1_1;
    }
    return EVENT_TRANSVR_TASK_DONE;

err_private_taskfunc_sfp_setup_rs1_1:
    if ((task_p->retry) == 0) {
        SWPS_INFO("%s: %s <port>:%s <input>:%d <err>:%d\n",
                  func_str, err_str, task_p->transvr_p->swp_name, input_val, err_val);
    }
    _taskfunc_sfp_setup_hard_rs1(task_p, old_val);
    return EVENT_TRANSVR_TASK_FAIL;
}


int
taskfunc_sfp_setup_SFF8431_case1(struct transvr_worker_s *task_p) {
    /* SFF-8431 (8/4/2G Rx Rate_Select only) */
    int update_val = 1;

    return _taskfunc_sfp_setup_rs0(task_p, update_val);
}



int
taskfunc_sfp_setup_SFF8431_case2(struct transvr_worker_s *task_p) {
    /* SFF-8431 (8/4/2G Tx Rate_Select only) */
    int update_val = 1;

    return _taskfunc_sfp_setup_rs1(task_p, update_val);
}


int
taskfunc_sfp_setup_SFF8431_case3(struct transvr_worker_s *task_p) {
    /* SFF-8431 (8/4/2G Independent Rx & Tx Rate_select) */
    int update_rs0 = 1;
    int update_rs1 = 1;
    int err_code   = DEBUG_TRANSVR_INT_VAL;

    err_code = _taskfunc_sfp_setup_rs0(task_p, update_rs0);
    if (err_code < 0) {
        return err_code;
    }
    return _taskfunc_sfp_setup_rs1(task_p, update_rs1);
}


int
taskfunc_sfp_handle_1g_rj45(struct transvr_worker_s *task_p) {

    /* Not all of platform support 0x56 for transceiver
     * external PHY, Support list as below:
     * => 1. Magnolia-PVT (PS: EVT & DVT not ready)
     */
    int ext_phy_addr   = 0x56;
    int ext_phy_page   = -1;
    int ext_phy_offs   = 0x11;
    int ext_phy_len    = 1;
    int lstate_mask    = 0x04; /* 00000100 */
    int show_err       = 0;
    int fail_retry     = 5;
    int fail_delay     = 1000; /* msec */
    int err_code       = DEBUG_TRANSVR_INT_VAL;
    uint8_t detect_val = DEBUG_TRANSVR_HEX_VAL;
    char err_str[64]   = DEBUG_TRANSVR_STR_VAL;
    int *tmp_p         = NULL;
    char *func_name    = "taskfunc_sfp_handle_1g_rj45";

    if (task_p->transvr_p->state != STATE_TRANSVR_CONNECTED) {
        return EVENT_TRANSVR_TASK_DONE;
    }
    if ( (task_p->transvr_p->info != TRANSVR_CLASS_BASE_T_1000) &&
         (task_p->transvr_p->info != TRANSVR_CLASS_BASE_T_1000_up) ) {
        goto err_taskfunc_sfp_handle_1g_rj45_1;
    }
    err_code = _common_update_uint8_attr(task_p->transvr_p,
                                         ext_phy_addr,
                                         ext_phy_page,
                                         ext_phy_offs,
                                         ext_phy_len,
                                         &detect_val,
                                         func_name,
                                         show_err);
    if ( (err_code < 0) ||
         (detect_val == DEBUG_TRANSVR_HEX_VAL) ) {
        snprintf(err_str, sizeof(err_str), "Detect external link status fail");
        goto err_taskfunc_sfp_handle_1g_rj45_2;
    }
    if ((detect_val & lstate_mask) == lstate_mask) {
        goto ok_taskfunc_sfp_handle_1g_rj45_link_up;
    }
    goto ok_taskfunc_sfp_handle_1g_rj45_link_down;

ok_taskfunc_sfp_handle_1g_rj45_link_up:
    /* Filter out noise */
    if (!(task_p->p_data)) {
        tmp_p = kzalloc(sizeof(int), GFP_KERNEL);
        if (!tmp_p) {
            snprintf(err_str, sizeof(err_str), "kzalloc p_data fail");
            goto err_taskfunc_sfp_handle_1g_rj45_2;
        }
        *tmp_p = TRANSVR_CLASS_BASE_T_1000_up;
        task_p->p_data = tmp_p;
        goto ok_taskfunc_sfp_handle_1g_rj45_done;
    }
    if ((*(int *)(task_p->p_data)) != TRANSVR_CLASS_BASE_T_1000_up) {
        kfree(task_p->p_data);
        task_p->p_data = NULL;
        snprintf(err_str, sizeof(err_str), "Internal error");
        goto err_taskfunc_sfp_handle_1g_rj45_2;
    }
    task_p->transvr_p->info = TRANSVR_CLASS_BASE_T_1000_up;
    kfree(task_p->p_data);
    task_p->p_data = NULL;
    goto ok_taskfunc_sfp_handle_1g_rj45_done;

ok_taskfunc_sfp_handle_1g_rj45_link_down:
    if (task_p->p_data) {
        kfree(task_p->p_data);
        task_p->p_data = NULL;
    }
    task_p->transvr_p->info = TRANSVR_CLASS_BASE_T_1000;
    goto ok_taskfunc_sfp_handle_1g_rj45_done;

ok_taskfunc_sfp_handle_1g_rj45_done:
    if (task_p->retry != VAL_TRANSVR_TASK_RETRY_FOREVER) {
        transvr_task_set_retry(task_p, VAL_TRANSVR_TASK_RETRY_FOREVER);
    }
    return EVENT_TRANSVR_TASK_DONE;

err_taskfunc_sfp_handle_1g_rj45_1:
    snprintf(err_str, sizeof(err_str), "Detect transceiver:%d not Base-T, remove task.",
            task_p->transvr_p->info);
    SWPS_INFO("%s: %s <port>:%s\n", __func__, err_str, task_p->transvr_p->swp_name);
    transvr_task_set_retry(task_p, 0);
    return EVENT_TRANSVR_TASK_DONE;

err_taskfunc_sfp_handle_1g_rj45_2:
    if (task_p->retry == VAL_TRANSVR_TASK_RETRY_FOREVER) {
        transvr_task_set_retry(task_p, fail_retry);
    }
    if ((task_p->retry) == 0) {
        /* Error case:
         * => In this case, SWPS will stop external Link state monitor features
         *    and keeps transvr_p->info on TRANSVR_CLASS_BASE_T_1000_up.
         *    Upper layer will see it always Linkup that because of these type of
         *    transceiver has external phy, BCM chip see it as Loopback transceiver.
         */
        SWPS_WARN("%s can not access external PHY of Base-T SFP transceiver\n",
                task_p->transvr_p->swp_name);
        task_p->transvr_p->info = TRANSVR_CLASS_BASE_T_1000_up;
        return EVENT_TRANSVR_TASK_DONE;
    } else {
        transvr_task_set_delay(task_p, fail_delay);
    }
    return EVENT_TRANSVR_TASK_FAIL;
}


int
_taskfunc_qsfp_setup_power_mod(struct transvr_obj_s *self,
                               int setup_val) {

    int curr_val   = DEBUG_TRANSVR_INT_VAL;
    int err_val    = DEBUG_TRANSVR_INT_VAL;
    char *err_msg  = DEBUG_TRANSVR_STR_VAL;

    curr_val = self->ioexp_obj_p->get_lpmod(self->ioexp_obj_p,
                                            self->ioexp_virt_offset);
    if (curr_val < 0){
        err_msg = "Get current value fail!";
        goto err_private_taskfunc_qsfp_setup_power_mod_1;
    }
    if (curr_val == setup_val){
        return EVENT_TRANSVR_TASK_DONE;
    }
    err_val = self->ioexp_obj_p->set_lpmod(self->ioexp_obj_p,
                                           self->ioexp_virt_offset,
                                           setup_val);
    if (err_val < 0){
        err_msg = "Setup power mode fail!";
        goto err_private_taskfunc_qsfp_setup_power_mod_1;
    }
    return EVENT_TRANSVR_TASK_DONE;

err_private_taskfunc_qsfp_setup_power_mod_1:
    SWPS_INFO("%s: %s <err>:%d <curr>:%d <input>:%d\n",
              __func__, err_msg, err_val, curr_val, setup_val);
    return EVENT_TRANSVR_TASK_FAIL;
}


int
taskfunc_qsfp_handle_tx_disable(struct transvr_worker_s *task_p) {

    int i = 0;
    int retry = 5;
    int delay_ms = 100;

    if (task_p->transvr_p->auto_tx_disable == VAL_TRANSVR_FUNCTION_DISABLE) {
        return EVENT_TRANSVR_TASK_DONE;
    }
    if (!_qsfp_is_implement_tx_disable(task_p->transvr_p)) {
        return EVENT_TRANSVR_TASK_DONE;
    }
    for (i=0; i<retry; i++) {
        if (_qsfp_set_auto_tx_disable(task_p->transvr_p,
                                      task_p->transvr_p->auto_tx_disable)
                                      == EVENT_TRANSVR_TASK_DONE) {
            goto ok_taskfunc_qsfp_handle_tx_disable;
        }
        mdelay(delay_ms);
    }
    SWPS_INFO("%s auto setup tx_disable:0x%02x fail.\n",
              task_p->transvr_p->swp_name,
              task_p->transvr_p->auto_tx_disable);
    return EVENT_TRANSVR_INIT_FAIL;

ok_taskfunc_qsfp_handle_tx_disable:
    SWPS_INFO("%s auto setup tx_disable:0x%02x ok.\n",
              task_p->transvr_p->swp_name,
              task_p->transvr_p->auto_tx_disable);
    return EVENT_TRANSVR_TASK_DONE;
}


int
taskfunc_qsfp_set_hpmod(struct transvr_worker_s *task_p) {

    int err = DEBUG_TRANSVR_INT_VAL;
    int HIGH_POWER_MODE = 0;

    /* Handle power mode */
    err = _taskfunc_qsfp_setup_power_mod(task_p->transvr_p,
                                         HIGH_POWER_MODE);
    if (err < 0) {
        SWPS_INFO("%s: setup hpmod fail <err>:%d <port>:%s\n",
                  __func__, err, task_p->transvr_p->swp_name);
        return err;
    }
    /* Handle auto tx_disable
     * [Note]
     * => Because there are some transceiver have timing issues or
     *    setup sequence issues, therefore we handle auto tx_disable
     *    after handle power mode.
     */
    mdelay(100);
    return taskfunc_qsfp_handle_tx_disable(task_p);
}


int
taskfunc_qsfp_set_lpmod(struct transvr_worker_s *task_p) {

    int LOW_POWER_MODE = 1;
    return _taskfunc_qsfp_setup_power_mod(task_p->transvr_p,
                                          LOW_POWER_MODE);
}


static int
initfunc_sfp_handle_multi_rate_mode(struct transvr_obj_s *self) {

    int task_retry = 3;
    int err_code   = DEBUG_TRANSVR_INT_VAL;
    char *err_str  = DEBUG_TRANSVR_STR_VAL;
    char *func_str = "sfp_handle_multi_rate_mode";
    struct transvr_worker_s *task_p = NULL;

    switch (self->rate_id) {
        case 0x00: /* Unspecified */
        case 0x03: /* Unspecified */
        case 0x05: /* Unspecified */
        case 0x07: /* Unspecified */
        case 0x09: /* Unspecified */
        case 0x0B: /* Unspecified */
        case 0x0D: /* Unspecified */
        case 0x0F: /* Unspecified */
            goto sfp_handle_multi_rate_mode_4_unspecified;

        case 0x02: /* SFF-8431 (8/4/2G Rx Rate_Select only) */
            task_p = transvr_task_creat(self,
                                        taskfunc_sfp_setup_SFF8431_case1,
                                        taskfunc_post_handle_task_state,
                                        func_str);
            goto sfp_handle_multi_rate_mode_4_sff8431;

        case 0x04: /* SFF-8431 (8/4/2G Tx Rate_Select only) */
            task_p = transvr_task_creat(self,
                                        taskfunc_sfp_setup_SFF8431_case2,
                                        taskfunc_post_handle_task_state,
                                        func_str);
            goto sfp_handle_multi_rate_mode_4_sff8431;

        case 0x06: /* SFF-8431 (8/4/2G Independent Rx & Tx Rate_select) */
            task_p = transvr_task_creat(self,
                                        taskfunc_sfp_setup_SFF8431_case3,
                                        taskfunc_post_handle_task_state,
                                        func_str);
            goto sfp_handle_multi_rate_mode_4_sff8431;

        case 0x01: /* SFF-8079 (4/2/1G Rate_Select & AS0/AS1) */
            err_str = "SFF-8079 (4/2/1G Rate_Select & AS0/AS1)";
            goto sfp_handle_multi_rate_mode_4_not_support;

        case 0x08: /* FC-PI-5 (16/8/4G Rx Rate_select only)
                    * High=16G only, Low=8G/4G
                    */
            err_str = "FC-PI-5 (16/8/4G Rx Rate_select only)";
            goto sfp_handle_multi_rate_mode_4_not_support;

        case 0x0A: /* FC-PI-5 (16/8/4G Independent Rx, Tx Rate_select)
                    * High=16G only, Low=8G/4G
                    */
            err_str = "FC-PI-5 (16/8/4G Independent Rx, Tx Rate_select)";
            goto sfp_handle_multi_rate_mode_4_not_support;

        case 0x0C: /* FC-PI-6 (32/16/8G Independent Rx, Tx Rate_Select)
                    * High=32G only, Low = 16G/8G
                    */
            err_str = "FC-PI-6 (32/16/8G Independent Rx, Tx Rate_Select)";
            goto sfp_handle_multi_rate_mode_4_not_support;

        case 0x0E: /* 10/8G Rx and Tx Rate_Select controlling the operation or
                    * locking modes of the internal signal conditioner, retimer
                    * or CDR, according to the logic table defined in Table 10-2,
                    * High Bit Rate (10G) =9.95-11.3 Gb/s; Low Bit Rate (8G) =
                    * 8.5 Gb/s. In this mode, the default value of bit 110.3 (Soft
                    * Rate Select RS(0), Table 9-11) and of bit 118.3 (Soft Rate
                    * Select RS(1), Table 10-1) is 1.
                    */
            err_str = "cable type: 0x0E";
            goto sfp_handle_multi_rate_mode_4_not_support;

        default:
            err_str = "cable type: UNKNOW";
            goto sfp_handle_multi_rate_mode_4_not_support;
    }

sfp_handle_multi_rate_mode_4_sff8431:
    if (!task_p) {
        err_str = "Create task fail!";
        goto sfp_handle_multi_rate_mode_4_fail_1;
    }
    transvr_task_set_retry(task_p, task_retry);
    return EVENT_TRANSVR_TASK_WAIT;

sfp_handle_multi_rate_mode_4_unspecified:
    return EVENT_TRANSVR_TASK_DONE;

sfp_handle_multi_rate_mode_4_not_support:
    SWPS_INFO("%s: Does not support %s <port>:%s <type>:0x%02x\n",
            func_str, err_str, self->swp_name, self->rate_id);
    return EVENT_TRANSVR_TASK_DONE;

sfp_handle_multi_rate_mode_4_fail_1:
    SWPS_INFO("%s: %s <port>:%s <type>:0x%02x, <err>:%d\n",
              func_str, err_str, self->swp_name, self->rate_id, err_code);
    return EVENT_TRANSVR_INIT_FAIL;
}


static int
initfunc_sfp_handle_1g_rj45(struct transvr_obj_s *self) {

    struct transvr_worker_s *task_p = NULL;
    int detect_cls   = DEBUG_TRANSVR_INT_VAL;
    char err_str[64] = DEBUG_TRANSVR_STR_VAL;
    char *func_str   = "initfunc_sfp_handle_1g_rj45";


    if (self->info == TRANSVR_CLASS_BASE_T_1000) {
        task_p = transvr_task_creat(self,
                                    taskfunc_sfp_handle_1g_rj45,
                                    taskfunc_post_do_nothing,
                                    func_str);
        if (!task_p) {
            snprintf(err_str, sizeof(err_str), "Create task fail");
            goto err_initfunc_sfp_handle_1g_rj45;
        }
        transvr_task_set_retry(task_p, VAL_TRANSVR_TASK_RETRY_FOREVER);
    }
    return EVENT_TRANSVR_TASK_DONE;

err_initfunc_sfp_handle_1g_rj45:
    SWPS_INFO("%s: %s <port>:%s <type>:%d\n",
              __func__, err_str, self->swp_name, detect_cls);
    return EVENT_TRANSVR_TASK_FAIL;
}


static int
initfunc_qsfp_handle_power_mode(struct transvr_obj_s *self) {

    int err_code      = EVENT_TRANSVR_EXCEP_INIT;
    int power_class   = DEBUG_TRANSVR_INT_VAL;
    int hpmod_retry   = 3;
    int lpower_config = 1;
    char err_msg[64]  = DEBUG_TRANSVR_STR_VAL;
    unsigned long hpmod_delay = 500; /* msec */
    struct transvr_worker_s *task_p = NULL;

    /* Handle power mode for IOEXP */
    power_class = __qsfp_get_power_cls(self, 0);
    switch (power_class) {
        case 1: /* Case: Low power mode (Class = 1) */
            err_code = _taskfunc_qsfp_setup_power_mod(self, lpower_config);
            if (err_code < 0){
                snprintf(err_msg, sizeof(err_msg), "Setup lpmod fail <ERR>:%d", err_code);
                goto err_initfunc_qsfp_handle_power_mode;
            }
            return EVENT_TRANSVR_TASK_DONE;

        case 2: /* Case: High power mode (Class > 1) */
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
            task_p = transvr_task_creat(self,
                                        taskfunc_qsfp_set_hpmod,
                                        taskfunc_post_handle_task_state,
                                        "transvr_init_qsfp");
            if (!task_p) {
                snprintf(err_msg, sizeof(err_msg), "Setup lpmod fail <ERR>:%d", err_code);
                goto err_initfunc_qsfp_handle_power_mode;
            }
            transvr_task_set_retry(task_p, hpmod_retry);
            transvr_task_set_delay(task_p, hpmod_delay);
            return EVENT_TRANSVR_TASK_WAIT;

        default:
            break;
    }
    snprintf(err_msg, sizeof(err_msg), "Exception case");
    goto err_initfunc_qsfp_handle_power_mode;

err_initfunc_qsfp_handle_power_mode:
    SWPS_INFO("%s: %s <port>:%s \n", __func__, err_msg, self->swp_name);
    return EVENT_TRANSVR_INIT_FAIL;
}


int
initfunc_qsfp28_handle_cdr(struct transvr_obj_s *self) {

    uint8_t DEFAULT_VAL_CDR = 0xff;
    int CDR_FUNC_EXISTED    = 0x3;
    int show_err   = 1;
    int err_val    = EVENT_TRANSVR_TASK_FAIL;
    char *err_msg  = DEBUG_TRANSVR_STR_VAL;
    char *func_str = "initfunc_qsfp28_handle_cdr";

    err_val = __qsfp_get_cdr_present(self, 0);
    if ( (err_val < 0) ||
         (err_val == DEBUG_TRANSVR_HEX_VAL) ) {
        err_msg = "detect cdr_present fail!";
        goto err_taskfunc_qsfp_handle_cdr_1;
    }
    if (err_val == CDR_FUNC_EXISTED) {
        err_val = _common_set_uint8_attr(self,
                                         self->eeprom_map_p->addr_cdr,
                                         self->eeprom_map_p->addr_cdr,
                                         self->eeprom_map_p->offset_cdr,
                                         DEFAULT_VAL_CDR,
                                         &(self->cdr),
                                         func_str,
                                         show_err);
        if (err_val < 0) {
            err_msg = "set CDR fail!";
            goto err_taskfunc_qsfp_handle_cdr_1;
        }
    }
    return EVENT_TRANSVR_TASK_DONE;

err_taskfunc_qsfp_handle_cdr_1:
    SWPS_INFO("%s: %s <err>:%d <port>:%s\n",
              func_str, err_msg, err_val, self->swp_name);
    return EVENT_TRANSVR_INIT_FAIL;
}

/* ========== Object functions for Final State Machine ==========
 */
int
is_plugged(struct transvr_obj_s *self){

    int  limit    = 63;
    int  present  = DEBUG_TRANSVR_INT_VAL;
    char emsg[64] = DEBUG_TRANSVR_STR_VAL;
    struct ioexp_obj_s *ioexp_p = self->ioexp_obj_p;

    if (!ioexp_p) {
        snprintf(emsg, limit, "ioexp_p is null!");
        goto err_is_plugged_1;
    }
    present = ioexp_p->get_present(ioexp_p, self->ioexp_virt_offset);
    switch (present){
        case 0:
            return 1;
        case 1:
            return 0;
        case ERR_IOEXP_UNINIT:
            snprintf(emsg, limit, "ioexp_p not ready!");
            goto err_is_plugged_1;
        default:
            if (ioexp_p->state == STATE_IOEXP_INIT){
                snprintf(emsg, limit, "ioexp_p not ready!");
                goto err_is_plugged_1;
            }
            break;
    }
    SWPS_INFO("%s: Exception case! <pres>:%d <istate>:%d\n",
              __func__, present, ioexp_p->state);
    return 0;

err_is_plugged_1:
    SWPS_DEBUG("%s: %s\n", __func__, emsg);
    return 0;
}


static int
detect_transvr_type(struct transvr_obj_s* self){

    int type = TRANSVR_TYPE_ERROR;

    self->i2c_client_p->addr = VAL_TRANSVR_COMID_ARREESS;
    type = i2c_smbus_read_byte_data(self->i2c_client_p,
                                    VAL_TRANSVR_COMID_OFFSET);

    /* Case: 1. Wait transceiver I2C module.
     *       2. Transceiver I2C module failure.
     * Note: 1. SFF allow maximum transceiver initial time is 2 second. So, there
     *          are exist some case that we need to wait transceiver.
     *          For these case, we keeps status on "TRANSVR_TYPE_UNPLUGGED", than
     *          state machine will keep trace with it.
     *       2. There exist some I2C failure case we need to handle. Such as user
     *          insert the failure transceiver, or any reason cause it abnormal.
     */
    if (type < 0){
        switch (type) {
            case -EIO:
                SWPS_DEBUG("%s: %s smbus return:-5 (I/O error)\n",
                        __func__, self->swp_name);
                return TRANSVR_TYPE_UNPLUGGED;
            case -ENXIO:
                SWPS_DEBUG("%s: %s smbus return:-6 (No such device or address)\n",
                        __func__, self->swp_name);
                return TRANSVR_TYPE_UNPLUGGED;
            default:
                break;
        }
        SWPS_INFO("%s: %s unexpected smbus return:%d \n",
                __func__, self->swp_name, type);
        return TRANSVR_TYPE_ERROR;
    }    
    /* Identify valid transceiver type */
    switch (type){
        case TRANSVR_TYPE_SFP:
        case TRANSVR_TYPE_QSFP:
        case TRANSVR_TYPE_QSFP_PLUS:
        case TRANSVR_TYPE_QSFP_28:
            break;
        case TRANSVR_TYPE_UNKNOW_1:
        case TRANSVR_TYPE_UNKNOW_2:
            type = TRANSVR_TYPE_UNKNOW_2;
            break;
        default:
            SWPS_DEBUG("%s: unknow type:0x%02x \n", __func__, type);
            type = TRANSVR_TYPE_ERROR;
            break;
    }
    return type;
}


static int
detect_transvr_state(struct transvr_obj_s *self,
                     int result[2]){
    /* [return]                  [result-0]                  [result-1]
     *  0                        STATE_TRANSVR_CONNECTED     TRANSVR_TYPE_FAKE
     *  0                        STATE_TRANSVR_DISCONNECTED  TRANSVR_TYPE_UNPLUGGED
     *  0                        STATE_TRANSVR_ISOLATED      TRANSVR_TYPE_ERROR
     *  0                        STATE_TRANSVR_INIT          <NEW_TYPE>/<OLD_TYPE>
     *  0                        STATE_TRANSVR_SWAPPED       <NEW_TYPE>
     *  0                        STATE_TRANSVR_CONNECTED     <OLD_TYPE>
     *  ERR_TRNASVR_BE_ISOLATED  STATE_TRANSVR_ISOLATED      TRANSVR_TYPE_ERROR  <Isolated>
     *  ERR_TRANSVR_I2C_CRASH    STATE_TRANSVR_UNEXCEPTED    TRANSVR_TYPE_ERROR  <New event>
     *  ERR_TRANSVR_UNEXCPT      STATE_TRANSVR_UNEXCEPTED    TRANSVR_TYPE_UNKNOW_1/2
     */
    result[0] = STATE_TRANSVR_UNEXCEPTED;  /* For return state */
    result[1] = TRANSVR_TYPE_ERROR;        /* For return type  */

    /* Case1: Fake type */
    if (self->type == TRANSVR_TYPE_FAKE){
        result[0] = STATE_TRANSVR_CONNECTED;
        result[1] = TRANSVR_TYPE_FAKE;
        return 0;
    }
    /* Case2: Transceiver unplugged */
    if (!is_plugged(self)){
        result[0] = STATE_TRANSVR_DISCONNECTED;
        result[1] = TRANSVR_TYPE_UNPLUGGED;
        return 0;
    }
    /* Case3: Transceiver be isolated */
    if (self->state == STATE_TRANSVR_ISOLATED){
        result[0] = STATE_TRANSVR_ISOLATED;
        result[1] = TRANSVR_TYPE_ERROR;
        return ERR_TRNASVR_BE_ISOLATED;
    }
    /* Case4: Transceiver plugged */
    result[1] = detect_transvr_type(self);
    /* Case4.1: I2C topology crash
     * Note   : There are some I2C issues cause by transceiver/cables.
     *          We need to check topology status when user insert it.
     *          But in this step, we can't not ensure this is the issues
     *          port. So, it return the ERR_TRANSVR_I2C_CRASH, then upper
     *          layer will diagnostic I2C topology.
     */
    if (check_channel_tier_1() < 0) {
        SWPS_INFO("%s: %s detect I2C crash <obj-state>:%d\n",
                __func__, self->swp_name, self->state);
        result[0] = STATE_TRANSVR_UNEXCEPTED;
        result[1] = TRANSVR_TYPE_ERROR;
        return ERR_TRANSVR_I2C_CRASH;
    }
    /* Case4.2: System initial not ready,
     * Note   : Sometime i2c channel or transceiver EEPROM will delay that will
     *          cause system in inconsistent state between EEPROM and IOEXP.
     *          In this case, SWP transceiver object keep state at LINK_DOWN
     *          to wait system ready.
     *          By the way, State Machine will handle these case.
     */
    if (result[1] == TRANSVR_TYPE_UNPLUGGED){
        result[0] = STATE_TRANSVR_DISCONNECTED;
        return 0;
    }
    /* Case4.3: Error transceiver type */
    if (result[1] == TRANSVR_TYPE_ERROR){
        result[0] = STATE_TRANSVR_ISOLATED;
        SWPS_INFO("%s: %s detect error type\n", __func__, self->swp_name);
        alarm_msg_2_user(self, "detected transceiver/cables not meet SFF standard!");
        return ERR_TRNASVR_BE_ISOLATED;
    }
    /* Case3.3: Unknow transceiver type */
    if ((result[1] == TRANSVR_TYPE_UNKNOW_1) ||
        (result[1] == TRANSVR_TYPE_UNKNOW_2) ){
        result[0] = STATE_TRANSVR_UNEXCEPTED;
        return ERR_TRANSVR_UNEXCPT;
    }
    /* Case3.4: During initial process */
    if (self->state == STATE_TRANSVR_INIT){
        result[0] = STATE_TRANSVR_INIT;
        return 0;
    }
    /* Case3.5: Transceiver be swapped */
    if (self->type != result[1]){
        result[0] = STATE_TRANSVR_SWAPPED;
        return 0;
    }
    /* Case3.6: Link up state */
    result[0] = STATE_TRANSVR_CONNECTED;
    return 0;
}


int
_sfp_detect_class_by_extend_comp(struct transvr_obj_s* self) {
    /* Reference: SFF-8024 (v3.8)
     */
    int detect_val = _sfp_get_comp_extended(self);

    switch(detect_val) {
        case 0x00: /* Unspecified */
            return TRANSVR_CLASS_UNSPECIFIED;

        case 0x01: /* 100G AOC (Active Optical Cable) or 25GAUI C2M */
        case 0x18: /* 100G AOC or 25GAUI C2M AOC. */
            return TRANSVR_CLASS_OPTICAL_25G_AOC;

        case 0x02: /* 100GBASE-SR4 or 25GBASE-SR */
            return TRANSVR_CLASS_OPTICAL_25G_SR;

        case 0x03: /* 100GBASE-LR4 or 25GBASE-LR */
            return TRANSVR_CLASS_OPTICAL_25G_LR;

        case 0x04: /* 100GBASE-ER4 or 25GBASE-ER */
            return TRANSVR_CLASS_OPTICAL_25G_ER;

        case 0x08: /* 100G ACC (Active Copper Cable) or 25GAUI C2M ACC. */
        case 0x0b: /* 100GBASE-CR4 or 25GBASE-CR CA-L */
        case 0x0c: /* 25GBASE-CR CA-S */
        case 0x0d: /* 25GBASE-CR CA-N */
        case 0x19: /* 100G ACC or 25GAUI C2M ACC. */
            return TRANSVR_CLASS_COPPER_L1_25G;

        default:
            break;
    }
    SWPS_INFO("%s: Unexcept value:0x%02x\n <port>:%s",
              __func__, detect_val, self->swp_name);
    return TRANSVR_CLASS_ERROR;
}


int
_sfp_detect_class_by_10_ethernet(struct transvr_obj_s* self) {
    /* Reference: SFF-8472 (v12.2)
     */
    int detect_val = DEBUG_TRANSVR_INT_VAL;

    detect_val = _sfp_get_comp_10g_eth_comp(self);
    /* Case: Unspecified */
    if (detect_val == 0x00) {
        return TRANSVR_CLASS_UNSPECIFIED;
    }
    /* Case: 10G Optical (x1) */
    if ((detect_val & 0x10) == 0x10) {    /* 00010000 : 10GBASE-SR  */
        return TRANSVR_CLASS_OPTICAL_10G_S_SR;
    }
    if ( ((detect_val & 0x20) == 0x20) || /* 00100000 : 10GBASE-LR  */
         ((detect_val & 0x40) == 0x40) ){ /* 01000000 : 10GBASE-LRM */
        return TRANSVR_CLASS_OPTICAL_10G_S_LR;
    }
    if ((detect_val & 0x80) == 0x80) {    /* 10000000 : 10GBASE-ER  */
        return TRANSVR_CLASS_OPTICAL_10G_S_ER;
    }
    /* Case: ERROR */
    SWPS_INFO("%s: Unexcept value:0x%02x\n <port>:%s",
              __func__, detect_val, self->swp_name);
    return TRANSVR_CLASS_ERROR;
}


int
_sfp_detect_if_sp_by_br(struct transvr_obj_s* self) {

    int lower_bound_1g  = 0x0b;
    int upper_bound_1g  = 0x1A;
    int lower_bound_10g = 0x60;
    int upper_bound_10g = 0x75;
    int lower_bound_25g = 0xf0;
    int upper_bound_25g = 0xff;
    int notmal_br = DEBUG_TRANSVR_INT_VAL;

    notmal_br = (int)(self->br); /* updated by update_all() */
    /* Check 25G */
    if ((notmal_br >= lower_bound_25g) &&
        (notmal_br <= upper_bound_25g) ) {
        return TRANSVR_CLASS_25G;
    }
    /* Check 10G */
    if ((notmal_br >= lower_bound_10g) &&
        (notmal_br <= upper_bound_10g) ) {
        return TRANSVR_CLASS_10G;
    }
    /* Check 1G */
    if ((notmal_br >= lower_bound_1g) &&
        (notmal_br <= upper_bound_1g) ) {
        return TRANSVR_CLASS_1G;
    }
    return TRANSVR_CLASS_UNSPECIFIED;
}


int
_sfp_detect_class_by_1g_ethernet(struct transvr_obj_s* self) {
    /* Reference: SFF-8472 (v12.2)
     */
    int detect_val   = DEBUG_TRANSVR_INT_VAL;
    int speed_br     = DEBUG_TRANSVR_INT_VAL;
    int speed_tmp    = DEBUG_TRANSVR_INT_VAL;
    char err_str[64] = DEBUG_TRANSVR_STR_VAL;

    speed_br   = _sfp_detect_if_sp_by_br(self);
    detect_val = _sfp_get_comp_1g_eth_comp(self);

    if (detect_val < 0) {
        snprintf(err_str, sizeof(err_str), "Detect abnormal value:%d", detect_val);
        goto err_p_sfp_detect_class_by_1g_ethernet;
    }
    /* Case: Unspecified */
    if (detect_val == 0x00) {
        return TRANSVR_CLASS_UNSPECIFIED;
    }
    /* Case: 1G (x1) */
    if ((detect_val & 0x01) == 0x01) {    /* 00000001 : 1000BASE-SX    */
        speed_tmp = TRANSVR_CLASS_OPTICAL_1G_SX;
        goto ok_sfp_detect_class_by_1g_ethernet_4_check_br_10g;
    }
    if ((detect_val & 0x02) == 0x02) {    /* 00000010 : 1000BASE-LX *3 */
        speed_tmp = TRANSVR_CLASS_OPTICAL_1G_LX;
        goto ok_sfp_detect_class_by_1g_ethernet_4_check_br_10g;
    }
    if ((detect_val & 0x04) == 0x04) {    /* 00000100 : 1000BASE-CX    */
        speed_tmp = TRANSVR_CLASS_COPPER_L1_1G;
        goto ok_sfp_detect_class_by_1g_ethernet_4_check_br_10g;
    }
    /* Case: 1000 Base-T (x1) */
    if ((detect_val & 0x08) == 0x08) {    /* 00001000 : 1000BASE-T     */
        return TRANSVR_CLASS_BASE_T_1000;
    }
    /* Case: 100 Base */
    if ( ((detect_val & 0x10) == 0x10) || /* 00010000 : 100BASE-LX/LX10  */
         ((detect_val & 0x20) == 0x20) || /* 00100000 : 100BASE-FX  */
         ((detect_val & 0x40) == 0x40) || /* 01000000 : BASE-BX10 *3 */
         ((detect_val & 0x80) == 0x80) ){ /* 10000000 : BASE-PX *3  */
        return TRANSVR_CLASS_OPTICAL_100;
    }
    /* Case: ERROR */
    snprintf(err_str, sizeof(err_str), "Case:ERROR, value:%d", detect_val);
    goto err_p_sfp_detect_class_by_1g_ethernet;

ok_sfp_detect_class_by_1g_ethernet_4_check_br_10g:
    switch (speed_br) {
        case TRANSVR_CLASS_UNSPECIFIED:
        case TRANSVR_CLASS_1G:
            return speed_tmp;
        case TRANSVR_CLASS_10G:
            goto ok_sfp_detect_class_by_1g_ethernet_4_transfer_10G;
    }

ok_sfp_detect_class_by_1g_ethernet_4_transfer_10G:
    switch (speed_tmp) {
        case TRANSVR_CLASS_OPTICAL_1G_SX:
            return TRANSVR_CLASS_OPTICAL_10G_S_SR;
        case TRANSVR_CLASS_OPTICAL_1G_LX:
            return TRANSVR_CLASS_OPTICAL_10G_S_LR;
        case TRANSVR_CLASS_COPPER_L1_1G:
            return TRANSVR_CLASS_COPPER_L1_10G;
        default:
            break;
    }
    snprintf(err_str, sizeof(err_str), "transfer_1to10 fail, speed:%d", speed_tmp);
    goto err_p_sfp_detect_class_by_1g_ethernet;

err_p_sfp_detect_class_by_1g_ethernet:
    SWPS_INFO("%s: %s <port>:%s", __func__, err_str, self->swp_name);
    return TRANSVR_CLASS_ERROR;
}


int
_sfp_detect_class_by_feature(struct transvr_obj_s* self) {
    /* Reference: SFF-8024 (v3.8)
     */
    int is_active    = 0;
    int conn_val     = DEBUG_TRANSVR_INT_VAL;
    int check_val    = DEBUG_TRANSVR_INT_VAL;
    int wave_len     = DEBUG_TRANSVR_INT_VAL;
    int speed_val    = DEBUG_TRANSVR_INT_VAL;
    char err_msg[64] = DEBUG_TRANSVR_STR_VAL;

    speed_val = _sfp_detect_if_sp_by_br(self);
    conn_val  = _sfp_get_connector_type(self);

    switch(conn_val) {
        case 0x00: /* Unspecified */
            goto ok_sfp_detect_class_by_feature_4_check_active_passive;
        case 0x07: /* LC (Lucent Connector) */
        case 0x0b: /* Optical Pigtail */
        case 0x0c: /* MPO 1x12 */
        case 0x0d: /* MPO 2x16 */
            /*
             * ToDo: Need verify Optical Pigtail
             */
            goto ok_sfp_detect_class_by_feature_4_optiocal;
        case 0x21: /* Copper pigtail */
            /*
             * ToDo: Need check ACC use case
             */
            goto ok_sfp_detect_class_by_feature_4_check_active_passive;
        case 0x23: /* No separable connector */
            /*
             * ToDo: Standard not clear, not all transceiver vendor
             *       have the same defined
             */
            goto ok_sfp_detect_class_by_feature_4_check_active_passive;
        default:
            break;
    }
    goto ok_sfp_detect_class_by_feature_4_unknow;

ok_sfp_detect_class_by_feature_4_check_active_passive:
    check_val = _sfp_get_cable_tech(self);
    switch(check_val) {
        case 0x00: /* Unspecified */
            goto ok_sfp_detect_class_by_feature_4_unknow;
        case 0x04: /* Passive */
            goto ok_sfp_detect_class_by_feature_4_copper;
        case 0x08: /* Active  */
            is_active = 1;
            goto ok_sfp_detect_class_by_feature_4_aoc;
        default:
            snprintf(err_msg, sizeof(err_msg),
                     "_sfp_get_cable_tech return Non define value:%d",
                     check_val);
            break;
    }
    goto err_sfp_detect_class_by_feature_1;

ok_sfp_detect_class_by_feature_4_optiocal:
    wave_len  = _common_count_wavelength(self,
                                         self->wavelength[0],
                                         self->wavelength[1]);
    switch(speed_val) {
        case TRANSVR_CLASS_25G:
            switch (wave_len) {
                case VAL_OPTICAL_WAVELENGTH_SR:
                    return TRANSVR_CLASS_OPTICAL_25G_SR;
                case VAL_OPTICAL_WAVELENGTH_LR:
                    return TRANSVR_CLASS_OPTICAL_25G_LR;
                case VAL_OPTICAL_WAVELENGTH_ER:
                    return TRANSVR_CLASS_OPTICAL_25G_ER;
                default:
                    break;
            }
            return TRANSVR_CLASS_OPTICAL_25G;

        case TRANSVR_CLASS_10G:
            switch (wave_len) {
                case VAL_OPTICAL_WAVELENGTH_SR:
                    return TRANSVR_CLASS_OPTICAL_10G_S_SR;
                case VAL_OPTICAL_WAVELENGTH_LR:
                    return TRANSVR_CLASS_OPTICAL_10G_S_LR;
                case VAL_OPTICAL_WAVELENGTH_ER:
                    return TRANSVR_CLASS_OPTICAL_10G_S_ER;
                default:
                    break;
            }
            return TRANSVR_CLASS_OPTICAL_10G;

        case TRANSVR_CLASS_1G:
            switch (wave_len) {
                case VAL_OPTICAL_WAVELENGTH_SR:
                    return TRANSVR_CLASS_OPTICAL_1G_SX;
                case VAL_OPTICAL_WAVELENGTH_LR:
                    return TRANSVR_CLASS_OPTICAL_1G_LX;
                case VAL_OPTICAL_WAVELENGTH_ER:
                    return TRANSVR_CLASS_OPTICAL_1G_EX;
                default:
                    break;
            }
            return TRANSVR_CLASS_OPTICAL_1G;

        default:
            return TRANSVR_CLASS_OPTICAL;
    }

ok_sfp_detect_class_by_feature_4_aoc:
    switch(speed_val) {
        case TRANSVR_CLASS_25G:
            return TRANSVR_CLASS_OPTICAL_25G_AOC;
        case TRANSVR_CLASS_10G:
            return TRANSVR_CLASS_OPTICAL_10G_S_AOC;
        case TRANSVR_CLASS_1G:
            return TRANSVR_CLASS_OPTICAL_1G_AOC;
        default:
            break;
    }
    goto ok_sfp_detect_class_by_feature_4_unknow;

ok_sfp_detect_class_by_feature_4_copper:
    switch(speed_val) {
        case TRANSVR_CLASS_25G:
            return TRANSVR_CLASS_COPPER_L1_25G;
        case TRANSVR_CLASS_10G:
            return TRANSVR_CLASS_COPPER_L1_10G;
        case TRANSVR_CLASS_1G:
            return TRANSVR_CLASS_COPPER_L1_1G;
        default:
            return TRANSVR_CLASS_COPPER;
    }

ok_sfp_detect_class_by_feature_4_unknow:
    return TRANSVR_CLASS_UNSPECIFIED;

err_sfp_detect_class_by_feature_1:
    SWPS_INFO("%s: %s\n <port>:%s", __func__, err_msg, self->swp_name);
    return TRANSVR_CLASS_ERROR;
}


int
sft_detect_transvr_class(struct transvr_obj_s* self) {

    int detect_val   = DEBUG_TRANSVR_INT_VAL;
    char err_msg[64] = DEBUG_TRANSVR_STR_VAL;

    /* Check Extended Compliance */
    detect_val = _sfp_detect_class_by_extend_comp(self);
    switch(detect_val) {
        case TRANSVR_CLASS_UNSPECIFIED:
            break;
        case TRANSVR_CLASS_OPTICAL_25G_AOC:
        case TRANSVR_CLASS_OPTICAL_25G_SR:
        case TRANSVR_CLASS_OPTICAL_25G_LR:
        case TRANSVR_CLASS_OPTICAL_25G_ER:
        case TRANSVR_CLASS_COPPER_L1_25G:
            return detect_val;
        default:
            snprintf(err_msg, sizeof(err_msg),
                     "Detect undefined extend_comp:%d",
                     detect_val);
            goto err_sft_detect_transceiver_class_1;
    }
    /* Check 10G Compliance */
    detect_val = _sfp_detect_class_by_10_ethernet(self);
    switch(detect_val) {
        case TRANSVR_CLASS_UNSPECIFIED:
            break;
        case TRANSVR_CLASS_OPTICAL_10G_S_SR:
        case TRANSVR_CLASS_OPTICAL_10G_S_LR:
        case TRANSVR_CLASS_OPTICAL_10G_S_ER:
            return detect_val;
        default:
            snprintf(err_msg, sizeof(err_msg),
                    "Detect undefined 10G_eth:%d",
                     detect_val);
            goto err_sft_detect_transceiver_class_1;
    }
    /* Check 1G Compliance */
    detect_val = _sfp_detect_class_by_1g_ethernet(self);
    switch(detect_val) {
        case TRANSVR_CLASS_UNSPECIFIED:
            break;
        case TRANSVR_CLASS_OPTICAL_1G_SX:
        case TRANSVR_CLASS_OPTICAL_1G_LX:
        case TRANSVR_CLASS_COPPER_L1_1G:
        case TRANSVR_CLASS_BASE_T_1000:
        case TRANSVR_CLASS_OPTICAL_100:
            /*
             * ToDo: Need Check 0.1G
             */
        case TRANSVR_CLASS_OPTICAL_10G_S_SR:
        case TRANSVR_CLASS_OPTICAL_10G_S_LR:
        case TRANSVR_CLASS_COPPER_L1_10G:
            /* Transfer speed case
             * => Example: Raycom 10G DAC
             */
            return detect_val;
        default:
            snprintf(err_msg, sizeof(err_msg),
                     "Detect undefined 1G_eth:%d",
                     detect_val);
            goto err_sft_detect_transceiver_class_1;
    }
    /* Check by connector, br, wavelength */
    detect_val = _sfp_detect_class_by_feature(self);
    switch(detect_val) {
        case TRANSVR_CLASS_UNSPECIFIED:
            break;
        case TRANSVR_CLASS_OPTICAL:
        case TRANSVR_CLASS_OPTICAL_1G:
        case TRANSVR_CLASS_OPTICAL_1G_SX:
        case TRANSVR_CLASS_OPTICAL_1G_LX:
        case TRANSVR_CLASS_OPTICAL_1G_EX:
        case TRANSVR_CLASS_OPTICAL_1G_AOC:
        case TRANSVR_CLASS_OPTICAL_10G:
        case TRANSVR_CLASS_OPTICAL_10G_S_SR:
        case TRANSVR_CLASS_OPTICAL_10G_S_LR:
        case TRANSVR_CLASS_OPTICAL_10G_S_ER:
        case TRANSVR_CLASS_OPTICAL_10G_S_AOC:
        case TRANSVR_CLASS_OPTICAL_25G:
        case TRANSVR_CLASS_OPTICAL_25G_SR:
        case TRANSVR_CLASS_OPTICAL_25G_LR:
        case TRANSVR_CLASS_OPTICAL_25G_ER:
        case TRANSVR_CLASS_OPTICAL_25G_AOC:
        case TRANSVR_CLASS_COPPER:
        case TRANSVR_CLASS_COPPER_L1_1G:
        case TRANSVR_CLASS_COPPER_L1_10G:
        case TRANSVR_CLASS_COPPER_L1_25G:
            return detect_val;
        default:
            snprintf(err_msg, sizeof(err_msg),
                     "Detect undefined get_connector:%d",
                     detect_val);
            goto err_sft_detect_transceiver_class_1;
    }
    /* Exception case: Can't verify */
    snprintf(err_msg, sizeof(err_msg), "Can not identify!");
    goto err_sft_detect_transceiver_class_1;

err_sft_detect_transceiver_class_1:
    SWPS_INFO("%s: %s <port>:%s\n", __func__,  err_msg, self->swp_name);
    return TRANSVR_CLASS_ERROR;
}


int
_sfp_set_trident2_if_type(struct transvr_obj_s* self,
                          int transvr_cls,
                          char *result){

    int lmax = 8;
    char err_msg[64] = DEBUG_TRANSVR_STR_VAL;

    switch(transvr_cls) {
        case TRANSVR_CLASS_ERROR:
        case TRANSVR_CLASS_UNSPECIFIED:
            break;
        /* 25G OPTICAL */
        case TRANSVR_CLASS_OPTICAL_25G_AOC:
        case TRANSVR_CLASS_OPTICAL_25G_SR:
        case TRANSVR_CLASS_OPTICAL_25G_LR:
        case TRANSVR_CLASS_OPTICAL_25G_ER:
        case TRANSVR_CLASS_OPTICAL_25G:
            return snprintf(result, lmax, TRANSVR_IF_SFI);
        /* 25G COPPER */
        case TRANSVR_CLASS_COPPER_L1_25G:
            return snprintf(result, lmax, TRANSVR_IF_SFI);
        /* 10G OPTICAL */
        case TRANSVR_CLASS_OPTICAL_10G_S_AOC:
        case TRANSVR_CLASS_OPTICAL_10G_S_SR:
        case TRANSVR_CLASS_OPTICAL_10G_S_LR:
        case TRANSVR_CLASS_OPTICAL_10G_S_ER:
        case TRANSVR_CLASS_OPTICAL_10G:
            return snprintf(result, lmax, TRANSVR_IF_SFI);
        /* 10G COPPER */
        case TRANSVR_CLASS_COPPER_L1_10G:
            return snprintf(result, lmax, TRANSVR_IF_SFI);
        /* 1G OPTICAL */
        case TRANSVR_CLASS_OPTICAL_1G_AOC:
        case TRANSVR_CLASS_OPTICAL_1G_SX:
        case TRANSVR_CLASS_OPTICAL_1G_LX:
        case TRANSVR_CLASS_OPTICAL_1G_EX:
        case TRANSVR_CLASS_OPTICAL_1G:
            return snprintf(result, lmax, TRANSVR_IF_IF_GMII);
        /* 1G COPPER */
        case TRANSVR_CLASS_COPPER_L1_1G:
            return snprintf(result, lmax, TRANSVR_IF_IF_GMII);
        /* 1G BASE_T */
        case TRANSVR_CLASS_BASE_T_1000:
            return snprintf(result, lmax, TRANSVR_IF_IF_GMII);
        /* 100 Base */
        case TRANSVR_CLASS_OPTICAL_100:
            return snprintf(result, lmax, TRANSVR_IF_IF_GMII);
        default:
            snprintf(err_msg, sizeof(err_msg),
                     "Detect undefined value:%d",
                     transvr_cls);
            goto err_sfp_set_trident2_if_type_1;
    }
    /* Exception case: Can't verify */
    snprintf(err_msg, sizeof(err_msg), "Can not identify!");
    goto err_sfp_set_trident2_if_type_1;

err_sfp_set_trident2_if_type_1:
    snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW);
    SWPS_INFO("%s: %s <port>:%s\n", __func__, err_msg, self->swp_name);
    return ERR_TRANSVR_ABNORMAL;
}


int
_sfp_set_tomahawk_if_type(struct transvr_obj_s* self,
                          int transvr_cls,
                          char *result) {

    int lmax = 8;
    char err_msg[64] = DEBUG_TRANSVR_STR_VAL;

    switch(transvr_cls) {
        case TRANSVR_CLASS_ERROR:
        case TRANSVR_CLASS_UNSPECIFIED:
            break;
        /* 25G OPTICAL */
        case TRANSVR_CLASS_OPTICAL_25G_AOC:
        case TRANSVR_CLASS_OPTICAL_25G_SR:
        case TRANSVR_CLASS_OPTICAL_25G_LR:
        case TRANSVR_CLASS_OPTICAL_25G_ER:
        case TRANSVR_CLASS_OPTICAL_25G:
            return snprintf(result, lmax, TRANSVR_IF_SR);
        /* 25G COPPER */
        case TRANSVR_CLASS_COPPER_L1_25G:
            return snprintf(result, lmax, TRANSVR_IF_KR);
        /* 10G OPTICAL */
        case TRANSVR_CLASS_OPTICAL_10G_S_AOC:
        case TRANSVR_CLASS_OPTICAL_10G_S_SR:
        case TRANSVR_CLASS_OPTICAL_10G_S_LR:
        case TRANSVR_CLASS_OPTICAL_10G_S_ER:
        case TRANSVR_CLASS_OPTICAL_10G:
            return snprintf(result, lmax, TRANSVR_IF_SFI);
        /* 10G COPPER */
        case TRANSVR_CLASS_COPPER_L1_10G:
            return snprintf(result, lmax, TRANSVR_IF_SFI);
        /* 1G OPTICAL */
        case TRANSVR_CLASS_OPTICAL_1G_AOC:
        case TRANSVR_CLASS_OPTICAL_1G_SX:
        case TRANSVR_CLASS_OPTICAL_1G_LX:
        case TRANSVR_CLASS_OPTICAL_1G_EX:
        case TRANSVR_CLASS_OPTICAL_1G:
            return snprintf(result, lmax, TRANSVR_IF_IF_GMII);
        /* 1G COPPER */
        case TRANSVR_CLASS_COPPER_L1_1G:
            return snprintf(result, lmax, TRANSVR_IF_IF_GMII);
        /* 1G BASE_T */
        case TRANSVR_CLASS_BASE_T_1000:
            return snprintf(result, lmax, TRANSVR_IF_IF_GMII);
        /* 100 Base */
        case TRANSVR_CLASS_OPTICAL_100:
            return snprintf(result, lmax, TRANSVR_IF_IF_GMII);
        default:
            snprintf(err_msg, sizeof(err_msg),
                     "Detect undefined value:%d",
                     transvr_cls);
            goto err_sfp_set_tomahawk_if_type_1;
    }
    /* Exception case: Can't verify */
    snprintf(err_msg, sizeof(err_msg), "Can not identify!");
    goto err_sfp_set_tomahawk_if_type_1;

err_sfp_set_tomahawk_if_type_1:
    snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW);
    SWPS_INFO("%s: %s\n <port>:%s", __func__, err_msg, self->swp_name);
    return ERR_TRANSVR_ABNORMAL;
}


int
_sfp_set_d5254_if_type(struct transvr_obj_s* self,
                           int transvr_cls,
                           char *result) {
    /* (TBD)
     *  Due to d5254 looks like doesn't have interface type.
     *  We bypass it currently.
     */
    int lmax = 8;    
    return snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW);
}


int
_sfp_detect_if_type(struct transvr_obj_s* self,
                    char *result){

    int lmax = 8;
    int detect_cls = DEBUG_TRANSVR_INT_VAL;

    detect_cls = sft_detect_transvr_class(self);
    switch (self->chipset_type) {
        case BCM_CHIP_TYPE_TRIDENT_2:
            return _sfp_set_trident2_if_type(self, detect_cls, result);
        
        case BCM_CHIP_TYPE_TRIDENT_3:
        case BCM_CHIP_TYPE_TOMAHAWK:
            return _sfp_set_tomahawk_if_type(self, detect_cls, result);

        case CHIP_TYPE_D5254:
            return _sfp_set_d5254_if_type(self, detect_cls, result);
            
        default:
            SWPS_INFO("%s: non-defined chipset_type:%d <port>:%s\n",
                      __func__, self->chipset_type, self->swp_name);
            break;
    }
    snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW);
    return ERR_TRANSVR_ABNORMAL;
}


int
sfp_get_if_type(struct transvr_obj_s *self,
                char *buf_p){

    int lmax = 16;
    char tmp_result[16] = DEBUG_TRANSVR_STR_VAL;

    if (self->state != STATE_TRANSVR_CONNECTED) {
        return snprintf(buf_p, lmax, "%d\n", self->state);
    }
    if (_sfp_detect_if_type(self, tmp_result) < 0) {
        return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_ABNORMAL);
    }
    return snprintf(buf_p, lmax, "%s\n", tmp_result);
}


int
_sfp_detect_if_speed(struct transvr_obj_s* self,
                     char *result){

    int lmax = 16;
    int detect_val   = DEBUG_TRANSVR_INT_VAL;
    char err_msg[64] = DEBUG_TRANSVR_STR_VAL;

    detect_val = sft_detect_transvr_class(self);
    switch(detect_val) {
        case TRANSVR_CLASS_ERROR:
        case TRANSVR_CLASS_UNSPECIFIED:
            break;
        /* 25G OPTICAL */
        case TRANSVR_CLASS_OPTICAL_25G_AOC:
        case TRANSVR_CLASS_OPTICAL_25G_SR:
        case TRANSVR_CLASS_OPTICAL_25G_LR:
        case TRANSVR_CLASS_OPTICAL_25G_ER:
        case TRANSVR_CLASS_OPTICAL_25G:
            return snprintf(result, lmax, TRANSVR_IF_SP_25G);
        /* 25G COPPER */
        case TRANSVR_CLASS_COPPER_L1_25G:
            return snprintf(result, lmax, TRANSVR_IF_SP_25G);
        /* 10G OPTICAL */
        case TRANSVR_CLASS_OPTICAL_10G_S_AOC:
        case TRANSVR_CLASS_OPTICAL_10G_S_SR:
        case TRANSVR_CLASS_OPTICAL_10G_S_LR:
        case TRANSVR_CLASS_OPTICAL_10G_S_ER:
        case TRANSVR_CLASS_OPTICAL_10G:
            return snprintf(result, lmax, TRANSVR_IF_SP_10G);
        /* 10G COPPER */
        case TRANSVR_CLASS_COPPER_L1_10G:
            return snprintf(result, lmax, TRANSVR_IF_SP_10G);
        /* 1G OPTICAL */
        case TRANSVR_CLASS_OPTICAL_1G_AOC:
        case TRANSVR_CLASS_OPTICAL_1G_SX:
        case TRANSVR_CLASS_OPTICAL_1G_LX:
        case TRANSVR_CLASS_OPTICAL_1G_EX:
        case TRANSVR_CLASS_OPTICAL_1G:
            return snprintf(result, lmax, TRANSVR_IF_SP_1G);
        /* 1G COPPER */
        case TRANSVR_CLASS_COPPER_L1_1G:
            return snprintf(result, lmax, TRANSVR_IF_SP_1G);
        /* 1G BASE_T */
        case TRANSVR_CLASS_BASE_T_1000:
            return snprintf(result, lmax, TRANSVR_IF_SP_1G);
        /* 100 Base */
        case TRANSVR_CLASS_OPTICAL_100:
            return snprintf(result, lmax, TRANSVR_IF_SP_100);
        default:
            snprintf(err_msg, sizeof(err_msg),
                     "Detect undefined value:%d",
                     detect_val);
            goto err_sfp_detect_if_speed_1;
    }
    /* Check by BR */
    detect_val = _sfp_detect_if_sp_by_br(self);
    switch (detect_val) {
        case TRANSVR_CLASS_25G:
            return snprintf(result, lmax, TRANSVR_IF_SP_25G);
        case TRANSVR_CLASS_10G:
            return snprintf(result, lmax, TRANSVR_IF_SP_10G);
        case TRANSVR_CLASS_1G:
            return snprintf(result, lmax, TRANSVR_IF_SP_1G);
        default:
            break;
    }
    /* Exception case: Can't verify */
    snprintf(err_msg, sizeof(err_msg), "Can not identify!");
    goto err_sfp_detect_if_speed_1;

err_sfp_detect_if_speed_1:
    snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW);
    SWPS_INFO("%s %s\n <port>:%s", __func__, err_msg, self->swp_name);
    return ERR_TRANSVR_ABNORMAL;
}


int
sfp_get_if_speed(struct transvr_obj_s *self,
                 char *buf_p){

    int lmax = 16;
    char tmp_result[16] = DEBUG_TRANSVR_STR_VAL;

    if (self->state != STATE_TRANSVR_CONNECTED) {
        return snprintf(buf_p, lmax, "%d\n", self->state);
    }
    if (_sfp_detect_if_speed(self, tmp_result) < 0) {
        return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_ABNORMAL);
    }
    return snprintf(buf_p, lmax, "%s\n", tmp_result);
}


int
_qsfp_detect_class_by_extend_comp(struct transvr_obj_s* self) {
    /* Reference: SFF-8024 (v3.8)
     */
    int detect_val = DEBUG_TRANSVR_INT_VAL;

    detect_val = _qsfp_get_comp_extended(self);
    switch(detect_val) {
        case 0x00: /* Unspecified */
            return TRANSVR_CLASS_UNSPECIFIED;

        case 0x01: /* 100G AOC (Active Optical Cable) or 25GAUI C2M */
        case 0x18: /* 100G AOC or 25GAUI C2M AOC. */
            return TRANSVR_CLASS_OPTICAL_100G_AOC;

        case 0x06: /* 100G CWDM4 */
        case 0x09: /* Obsolete (assigned before 100G CWDM4 MSA required FEC) */
        case 0x17: /* 100G CLR4 */
        case 0x1A: /* 100GE-DWDM2 */
            return TRANSVR_CLASS_OPTICAL_100G;

        case 0x02: /* 100GBASE-SR4 or 25GBASE-SR */
            return TRANSVR_CLASS_OPTICAL_100G_SR4;

        case 0x03: /* 100GBASE-LR4 or 25GBASE-LR */
            return TRANSVR_CLASS_OPTICAL_100G_LR4;

        case 0x04: /* 100GBASE-ER4 or 25GBASE-ER */
            return TRANSVR_CLASS_OPTICAL_100G_ER4;

        case 0x07: /* 100G PSM4 Parallel SMF */
            return TRANSVR_CLASS_OPTICAL_100G_PSM4;

        case 0x12: /* 40G PSM4 Parallel SMF */
            return TRANSVR_CLASS_OPTICAL_40G;

        case 0x11: /* 4 x 10GBASE-SR */
            return TRANSVR_CLASS_OPTICAL_40G_SR4;

        case 0x10: /* 40GBASE-ER4 */
            return TRANSVR_CLASS_OPTICAL_40G_ER4;

        case 0x08: /* 100G ACC (Active Copper Cable) or 25GAUI C2M ACC. */
        case 0x0b: /* 100GBASE-CR4 or 25GBASE-CR CA-L */
        case 0x19: /* 100G ACC or 25GAUI C2M ACC. */
            return TRANSVR_CLASS_COPPER_L4_100G;

        default:
            break;
    }
    SWPS_INFO("%s: Unexcept value:0x%02x\n <port>:%s",
              __func__, detect_val, self->swp_name);
    return TRANSVR_CLASS_ERROR;
}


int
_qsfp_detect_class_by_10_40_100_ethernet(struct transvr_obj_s* self) {
    /* Reference: SFF-8472 (v12.2)
     */
    int detect_val = DEBUG_TRANSVR_INT_VAL;

    detect_val = _qsfp_get_comp_10_40_100_ethernet(self);
    /* Case: Unspecified */
    if (detect_val == 0x00) {
        return TRANSVR_CLASS_UNSPECIFIED;
    }
    /* Case: 40G Optical */
    if ((detect_val & 0x01) == 0x01) {    /* 00000001 : 40G Active Cable (XLPPI) */
        return TRANSVR_CLASS_OPTICAL_40G_AOC;
    }
    if ((detect_val & 0x04) == 0x04) {    /* 00000100 : 40GBASE-SR4 */
        return TRANSVR_CLASS_OPTICAL_40G_SR4;
    }
    if ( (detect_val & 0x02) == 0x02) {   /* 00000010 : 40GBASE-LR4 */
        return TRANSVR_CLASS_OPTICAL_40G_LR4;
    }
    if ( (detect_val & 0x08) == 0x08) {   /* 00001000 : 40GBASE-CR4 */
        return TRANSVR_CLASS_COPPER_L4_40G;
    }
    /* Case: 10G Optical */
    if ( (detect_val & 0x10) == 0x10) {   /* 00010000 : 10GBASE-SR  */
        return TRANSVR_CLASS_OPTICAL_10G_Q_SR;
    }
    if ( ((detect_val & 0x20) == 0x20) || /* 00100000 : 10GBASE-LR  */
         ((detect_val & 0x40) == 0x40) ){ /* 01000000 : 10GBASE-LRM */
        return TRANSVR_CLASS_OPTICAL_10G_Q_LR;
    }
    /* Case: Extend Compliance */
    if ( ((detect_val & 0x80) == 0x80) ){ /* 10000000 : Use Extend Compliance */
        return TRANSVR_CLASS_EXTEND_COMP;
    }
    /* Case: ERROR */
    SWPS_INFO("%s: Unexcept value:0x%02x\n <port>:%s",
              __func__, detect_val, self->swp_name);
    return TRANSVR_CLASS_ERROR;
}


int
_qsfp_detect_if_sp_by_br(struct transvr_obj_s* self) {

    int lower_bound_10g  = 0x10;
    int upper_bound_10g  = 0x25;
    int lower_bound_40g  = 0x60;
    int upper_bound_40g  = 0x75;
    int lower_bound_100g = 0x60;
    int upper_bound_100g = 0x75;
    int used_extend_br   = 0xff;
    int notmal_br = DEBUG_TRANSVR_INT_VAL;
    int extend_br = DEBUG_TRANSVR_INT_VAL;

    notmal_br = (int)(self->br); /* updated by update_all() */
    /* Check 40G */
    if ((notmal_br >= lower_bound_40g) &&
        (notmal_br <= upper_bound_40g) ) {
        return TRANSVR_CLASS_40G;
    }
    /* Check 100G */
    if (notmal_br == used_extend_br) {
        extend_br = (int)(self->extbr); /* updated by update_all() */
        if ((extend_br >= lower_bound_100g) &&
            (extend_br <= upper_bound_100g) ) {
            return TRANSVR_CLASS_100G;
        }
    }
    /* Check 10G */
    if ((notmal_br >= lower_bound_10g) &&
        (notmal_br <= upper_bound_10g) ) {
        return TRANSVR_CLASS_10G;
    }
    return TRANSVR_CLASS_UNSPECIFIED;
}


int
_qsfp_detect_class_by_feature(struct transvr_obj_s* self) {
    /* Reference: SFF-8024 (v3.8)
     */
    int conn_val     = DEBUG_TRANSVR_INT_VAL;
    int wave_len     = DEBUG_TRANSVR_INT_VAL;
    int speed_val    = DEBUG_TRANSVR_INT_VAL;
    char err_msg[64] = DEBUG_TRANSVR_STR_VAL;

    speed_val = _qsfp_detect_if_sp_by_br(self);
    conn_val  = _qsfp_get_connector_type(self);

    switch(conn_val) {
        case 0x00: /* Unspecified */
            return TRANSVR_CLASS_UNSPECIFIED;
        case 0x07: /* LC (Lucent Connector) */
        case 0x0b: /* Optical Pigtail */
        case 0x0c: /* MPO 1x12 (Multifiber Parallel Optic) */
        case 0x0d: /* MPO 2x16 */
            goto ok_qsfp_detect_class_by_feature_4_optiocal;
        case 0x21: /* Copper pigtail */
            goto ok_qsfp_detect_class_by_feature_4_copper;
        case 0x23: /* No separable connector */
            if ((_qsfp_get_comp_fc_link_length(self) > 0) ||
                (_qsfp_get_comp_fc_trans_tech(self) > 0)  ||
                (_qsfp_get_comp_fc_trans_media(self) > 0) ||
                (_qsfp_get_comp_fc_speed(self) > 0) ) {
                goto ok_qsfp_detect_class_by_feature_4_aoc;
            }
            goto ok_qsfp_detect_class_by_feature_4_copper;
        default:
            snprintf(err_msg, sizeof(err_msg),
                     "_qsfp_get_connector_type return Non define value:%d",
                     conn_val);
            goto err_qsfp_detect_class_by_feature_1;
    }
    return TRANSVR_CLASS_UNSPECIFIED;

ok_qsfp_detect_class_by_feature_4_optiocal:
    wave_len  = _common_count_wavelength(self,
                                         self->wavelength[0],
                                         self->wavelength[1]);
    switch(speed_val) {
        case TRANSVR_CLASS_100G:
            switch (wave_len) {
                case VAL_OPTICAL_WAVELENGTH_SR:
                    return TRANSVR_CLASS_OPTICAL_100G_SR4;
                case VAL_OPTICAL_WAVELENGTH_LR:
                    return TRANSVR_CLASS_OPTICAL_100G_LR4;
                case VAL_OPTICAL_WAVELENGTH_ER:
                    return TRANSVR_CLASS_OPTICAL_100G_ER4;
                default:
                    break;
            }
            return TRANSVR_CLASS_OPTICAL_100G;

        case TRANSVR_CLASS_40G:
            switch (wave_len) {
                case VAL_OPTICAL_WAVELENGTH_SR:
                    return TRANSVR_CLASS_OPTICAL_40G_SR4;
                case VAL_OPTICAL_WAVELENGTH_LR:
                    return TRANSVR_CLASS_OPTICAL_40G_LR4;
                case VAL_OPTICAL_WAVELENGTH_ER:
                    return TRANSVR_CLASS_OPTICAL_40G_ER4;
                default:
                    break;
            }
            return TRANSVR_CLASS_OPTICAL_40G;

        case TRANSVR_CLASS_10G:
            switch (wave_len) {
                case VAL_OPTICAL_WAVELENGTH_SR:
                    return TRANSVR_CLASS_OPTICAL_10G_Q_SR;
                case VAL_OPTICAL_WAVELENGTH_LR:
                    return TRANSVR_CLASS_OPTICAL_10G_Q_LR;
                case VAL_OPTICAL_WAVELENGTH_ER:
                    return TRANSVR_CLASS_OPTICAL_10G_Q_ER;
                default:
                    break;
            }
            return TRANSVR_CLASS_OPTICAL_10G;

        default:
            return TRANSVR_CLASS_OPTICAL;
    }

ok_qsfp_detect_class_by_feature_4_aoc:
    switch(speed_val) {
        case TRANSVR_CLASS_100G:
            return TRANSVR_CLASS_OPTICAL_100G_AOC;
        case TRANSVR_CLASS_40G:
            return TRANSVR_CLASS_OPTICAL_40G_AOC;
        case TRANSVR_CLASS_10G:
            return TRANSVR_CLASS_OPTICAL_10G_Q_AOC;
        default:
            return TRANSVR_CLASS_OPTICAL;
    }

ok_qsfp_detect_class_by_feature_4_copper:
    switch(speed_val) {
        case TRANSVR_CLASS_100G:
            return TRANSVR_CLASS_COPPER_L4_100G;
        case TRANSVR_CLASS_40G:
            return TRANSVR_CLASS_COPPER_L4_40G;
        case TRANSVR_CLASS_10G:
            return TRANSVR_CLASS_COPPER_L4_10G;
        default:
            return TRANSVR_CLASS_COPPER;
    }

err_qsfp_detect_class_by_feature_1:
    SWPS_INFO("%s: %s\n <port>:%s",
              __func__, err_msg, self->swp_name);
    return TRANSVR_CLASS_ERROR;
}


int
qsft_detect_transvr_class(struct transvr_obj_s* self) {

    int detect_val   = DEBUG_TRANSVR_INT_VAL;
    char err_msg[64] = DEBUG_TRANSVR_STR_VAL;

    /* Check Extended Compliance */
    detect_val = _qsfp_detect_class_by_extend_comp(self);
    switch (detect_val) {
        case TRANSVR_CLASS_UNSPECIFIED:
            break;
        case TRANSVR_CLASS_OPTICAL_100G:
        case TRANSVR_CLASS_OPTICAL_100G_AOC:
        case TRANSVR_CLASS_OPTICAL_100G_SR4:
        case TRANSVR_CLASS_OPTICAL_100G_LR4:
        case TRANSVR_CLASS_OPTICAL_100G_ER4:
        case TRANSVR_CLASS_OPTICAL_100G_PSM4:
        case TRANSVR_CLASS_OPTICAL_40G:
        case TRANSVR_CLASS_OPTICAL_40G_AOC:
        case TRANSVR_CLASS_OPTICAL_40G_SR4:
        case TRANSVR_CLASS_OPTICAL_40G_LR4:
        case TRANSVR_CLASS_OPTICAL_40G_ER4:
        case TRANSVR_CLASS_COPPER_L4_100G:
            return detect_val;
        default:
            snprintf(err_msg, sizeof(err_msg),
                     "Detect undefined extend_comp:%d",
                     detect_val);
            goto err_qsft_detect_transvr_class_1;
    }
    /* Check 10/40G/100G Ethernet Compliance */
    detect_val = _qsfp_detect_class_by_10_40_100_ethernet(self);
    switch(detect_val) {
        case TRANSVR_CLASS_UNSPECIFIED:
            break;
        case TRANSVR_CLASS_OPTICAL_40G_AOC:
        case TRANSVR_CLASS_OPTICAL_40G_SR4:
        case TRANSVR_CLASS_OPTICAL_40G_LR4:
        case TRANSVR_CLASS_OPTICAL_10G_Q_SR: /* Need Check: SR4 or SR */
        case TRANSVR_CLASS_OPTICAL_10G_Q_LR: /* Need Check: SR4 or SR */
        case TRANSVR_CLASS_COPPER_L4_40G:
            return detect_val;
        case TRANSVR_CLASS_EXTEND_COMP:
            /* Format incorrect case (We already checked the Extend
             * Compliance is 0
             */
            snprintf(err_msg, sizeof(err_msg),
                    "Transceiver format incorrect");
            goto err_qsft_detect_transvr_class_1;
        default:
            snprintf(err_msg, sizeof(err_msg),
                     "Detect undefined 10/40/100:%d",
                     detect_val);
            goto err_qsft_detect_transvr_class_1;
    }
    /* Check by Connector type, BR and wavelength */
    detect_val = _qsfp_detect_class_by_feature(self);
    switch (detect_val) {
        case TRANSVR_CLASS_UNSPECIFIED:
            break;
        case TRANSVR_CLASS_OPTICAL_100G_ER4:
        case TRANSVR_CLASS_OPTICAL_100G_LR4:
        case TRANSVR_CLASS_OPTICAL_100G_SR4:
        case TRANSVR_CLASS_OPTICAL_100G_AOC:
        case TRANSVR_CLASS_OPTICAL_100G:
        case TRANSVR_CLASS_OPTICAL_40G_ER4:
        case TRANSVR_CLASS_OPTICAL_40G_LR4:
        case TRANSVR_CLASS_OPTICAL_40G_SR4:
        case TRANSVR_CLASS_OPTICAL_40G_AOC:
        case TRANSVR_CLASS_OPTICAL_40G:
        case TRANSVR_CLASS_OPTICAL_10G_Q_ER:
        case TRANSVR_CLASS_OPTICAL_10G_Q_LR:
        case TRANSVR_CLASS_OPTICAL_10G_Q_SR:
        case TRANSVR_CLASS_OPTICAL_10G_Q_AOC:
        case TRANSVR_CLASS_OPTICAL_10G:
        case TRANSVR_CLASS_OPTICAL:
        case TRANSVR_CLASS_COPPER_L4_100G:
        case TRANSVR_CLASS_COPPER_L4_40G:
        case TRANSVR_CLASS_COPPER_L4_10G:
        case TRANSVR_CLASS_COPPER:
            return detect_val;
        default:
            snprintf(err_msg, sizeof(err_msg),
                     "Detect undefined connector:%d",
                     detect_val);
            goto err_qsft_detect_transvr_class_1;
    }
    /* Exception case: Can't verify */
    snprintf(err_msg, sizeof(err_msg),
            "Can not identify!");
    goto err_qsft_detect_transvr_class_1;

err_qsft_detect_transvr_class_1:
    SWPS_INFO("%s: %s\n <port>:%s", __func__, err_msg, self->swp_name);
    return TRANSVR_CLASS_ERROR;
}


int
_qsfp_set_trident2_if_type(struct transvr_obj_s* self,
                           int transvr_cls,
                           char *result){

    int lmax = 8;
    char err_msg[64] = DEBUG_TRANSVR_STR_VAL;

    switch (transvr_cls) {
        case TRANSVR_CLASS_UNSPECIFIED:
        case TRANSVR_CLASS_ERROR:
            break;
        /* 100G Optical */
        case TRANSVR_CLASS_OPTICAL_100G:
        case TRANSVR_CLASS_OPTICAL_100G_AOC:
        case TRANSVR_CLASS_OPTICAL_100G_SR4:
        case TRANSVR_CLASS_OPTICAL_100G_LR4:
        case TRANSVR_CLASS_OPTICAL_100G_ER4:
        case TRANSVR_CLASS_OPTICAL_100G_PSM4:
            return snprintf(result, lmax, TRANSVR_IF_SR4);
        /* 100G Copper */
        case TRANSVR_CLASS_COPPER_L4_100G:
            return snprintf(result, lmax, TRANSVR_IF_KR4);
        /* 40G Optical */
        case TRANSVR_CLASS_OPTICAL_40G:
        case TRANSVR_CLASS_OPTICAL_40G_AOC:
        case TRANSVR_CLASS_OPTICAL_40G_SR4:
        case TRANSVR_CLASS_OPTICAL_40G_LR4:
        case TRANSVR_CLASS_OPTICAL_40G_ER4:
            return snprintf(result, lmax, TRANSVR_IF_IF_XGMII);
        /* 40G Copper */
        case TRANSVR_CLASS_COPPER_L4_40G:
            return snprintf(result, lmax, TRANSVR_IF_IF_XGMII);
        /* 10G Optical */
        case TRANSVR_CLASS_OPTICAL_10G:
        case TRANSVR_CLASS_OPTICAL_10G_Q_AOC:
        case TRANSVR_CLASS_OPTICAL_10G_Q_SR: /* Need Check: SR4 or SR */
        case TRANSVR_CLASS_OPTICAL_10G_Q_LR: /* Need Check: LR4 or LR */
        case TRANSVR_CLASS_OPTICAL_10G_Q_ER: /* Need Check: ER4 or ER */
            return snprintf(result, lmax, TRANSVR_IF_IF_XGMII);
        /* Optical */
        case TRANSVR_CLASS_OPTICAL:
            return snprintf(result, lmax, TRANSVR_IF_IF_XGMII);
        /* Copper */
        case TRANSVR_CLASS_COPPER:
            return snprintf(result, lmax, TRANSVR_IF_IF_XGMII);
        default:
            snprintf(err_msg, sizeof(err_msg),
                     "Detect undefined value:%d",
                     transvr_cls);
            goto err_qsfp_set_trident2_if_type_1;
    }
    /* Exception case: Can't verify */
    snprintf(err_msg, sizeof(err_msg), "Can not identify!");
    goto err_qsfp_set_trident2_if_type_1;

err_qsfp_set_trident2_if_type_1:
    snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW);
    SWPS_INFO("%s: %s\n <port>:%s", __func__, err_msg, self->swp_name);
    return ERR_TRANSVR_ABNORMAL;
}


int
_qsfp_set_tomahawk_if_type(struct transvr_obj_s* self,
                           int transvr_cls,
                           char *result){

    int lmax = 8;
    char err_msg[64] = DEBUG_TRANSVR_STR_VAL;

    switch (transvr_cls) {
        case TRANSVR_CLASS_UNSPECIFIED:
        case TRANSVR_CLASS_ERROR:
            break;
        /* 100G Optical */
        case TRANSVR_CLASS_OPTICAL_100G:
        case TRANSVR_CLASS_OPTICAL_100G_AOC:
        case TRANSVR_CLASS_OPTICAL_100G_SR4:
        case TRANSVR_CLASS_OPTICAL_100G_LR4:
        case TRANSVR_CLASS_OPTICAL_100G_ER4:
        case TRANSVR_CLASS_OPTICAL_100G_PSM4:
            return snprintf(result, lmax, TRANSVR_IF_SR4);
        /* 100G Copper */
        case TRANSVR_CLASS_COPPER_L4_100G:
            return snprintf(result, lmax, TRANSVR_IF_KR4);
        /* 40G Optical */
        case TRANSVR_CLASS_OPTICAL_40G:
        case TRANSVR_CLASS_OPTICAL_40G_AOC:
        case TRANSVR_CLASS_OPTICAL_40G_SR4:
        case TRANSVR_CLASS_OPTICAL_40G_LR4:
        case TRANSVR_CLASS_OPTICAL_40G_ER4:
            return snprintf(result, lmax, TRANSVR_IF_SR4);
        /* 40G Copper */
        case TRANSVR_CLASS_COPPER_L4_40G:
            return snprintf(result, lmax, TRANSVR_IF_KR4);
        /* 10G Optical */
        case TRANSVR_CLASS_OPTICAL_10G:
        case TRANSVR_CLASS_OPTICAL_10G_Q_AOC:
        case TRANSVR_CLASS_OPTICAL_10G_Q_SR: /* Need Check: SR4 or SR */
        case TRANSVR_CLASS_OPTICAL_10G_Q_LR: /* Need Check: SR4 or SR */
        case TRANSVR_CLASS_OPTICAL_10G_Q_ER:
            return snprintf(result, lmax, TRANSVR_IF_SR4);
        /* Optical */
        case TRANSVR_CLASS_OPTICAL:
            return snprintf(result, lmax, TRANSVR_IF_SR4);
        /* Copper */
        case TRANSVR_CLASS_COPPER:
            return snprintf(result, lmax, TRANSVR_IF_KR4);
        default:
            snprintf(err_msg, sizeof(err_msg),
                     "Detect undefined value:%d",
                     transvr_cls);
            goto err_qsfp_set_trident2_if_type_1;
    }
    /* Exception case: Can't verify */
    snprintf(err_msg, sizeof(err_msg), "Can not identify!");
    goto err_qsfp_set_trident2_if_type_1;

err_qsfp_set_trident2_if_type_1:
    snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW);
    SWPS_INFO("%s: %s\n <port>:%s", __func__, err_msg, self->swp_name);
    return ERR_TRANSVR_ABNORMAL;
}


int
_qsfp_set_d5254_if_type(struct transvr_obj_s* self,
                            int transvr_cls,
                            char *result) {
    /* (TBD)
     *  Due to d5254 looks like doesn't have interface type.
     *  We bypass it currently.
     */
    int lmax = 8;    
    return snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW);
}


int
_qsfp_detect_if_type(struct transvr_obj_s* self,
                     char *result){

    int lmax = 8;
    int detect_cls = DEBUG_TRANSVR_INT_VAL;

    detect_cls = qsft_detect_transvr_class(self);
    switch (self->chipset_type) {
        case BCM_CHIP_TYPE_TRIDENT_2:
            return _qsfp_set_trident2_if_type(self, detect_cls, result);
        
        case BCM_CHIP_TYPE_TRIDENT_3:
        case BCM_CHIP_TYPE_TOMAHAWK:
            return _qsfp_set_tomahawk_if_type(self, detect_cls, result);

        case CHIP_TYPE_D5254:
            return _qsfp_set_d5254_if_type(self, detect_cls, result);
            
        default:
            SWPS_INFO("%s: non-defined chipset_type:%d <port>:%s\n",
                      __func__, self->chipset_type, self->swp_name);
            break;
    }
    snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW);
    return ERR_TRANSVR_ABNORMAL;
}


int
qsfp_get_if_type(struct transvr_obj_s *self,
                 char *buf_p){

    int lmax = 8;
    char tmp_result[8] = DEBUG_TRANSVR_STR_VAL;

    if (self->state != STATE_TRANSVR_CONNECTED) {
        return snprintf(buf_p, lmax, "%d\n", self->state);
    }
    if (_qsfp_detect_if_type(self, tmp_result) < 0) {
        return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_ABNORMAL);
    }
    return snprintf(buf_p, lmax, "%s\n", tmp_result);
}


int
_qsfp_detect_if_speed(struct transvr_obj_s* self,
                      char *result){
    int lmax = 16;
    int detect_val   = DEBUG_TRANSVR_INT_VAL;
    char err_msg[64] = DEBUG_TRANSVR_STR_VAL;

    detect_val = qsft_detect_transvr_class(self);
    switch (detect_val) {
        case TRANSVR_CLASS_UNSPECIFIED:
        case TRANSVR_CLASS_ERROR:
            break;
        /* 100G Optical */
        case TRANSVR_CLASS_OPTICAL_100G:
        case TRANSVR_CLASS_OPTICAL_100G_AOC:
        case TRANSVR_CLASS_OPTICAL_100G_SR4:
        case TRANSVR_CLASS_OPTICAL_100G_LR4:
        case TRANSVR_CLASS_OPTICAL_100G_ER4:
        case TRANSVR_CLASS_OPTICAL_100G_PSM4:
            return snprintf(result, lmax, TRANSVR_IF_SP_100G);
        /* 100G Copper */
        case TRANSVR_CLASS_COPPER_L4_100G:
            return snprintf(result, lmax, TRANSVR_IF_SP_100G);
        /* 40G Optical */
        case TRANSVR_CLASS_OPTICAL_40G:
        case TRANSVR_CLASS_OPTICAL_40G_AOC:
        case TRANSVR_CLASS_OPTICAL_40G_SR4:
        case TRANSVR_CLASS_OPTICAL_40G_LR4:
        case TRANSVR_CLASS_OPTICAL_40G_ER4:
            return snprintf(result, lmax, TRANSVR_IF_SP_40G);
        /* 40G Copper */
        case TRANSVR_CLASS_COPPER_L4_40G:
            return snprintf(result, lmax, TRANSVR_IF_SP_40G);
        /* 10G Optical */
        case TRANSVR_CLASS_OPTICAL_10G:
        case TRANSVR_CLASS_OPTICAL_10G_Q_AOC:
        case TRANSVR_CLASS_OPTICAL_10G_Q_SR: /* Need Check: SR4 or SR */
        case TRANSVR_CLASS_OPTICAL_10G_Q_LR: /* Need Check: SR4 or SR */
        case TRANSVR_CLASS_OPTICAL_10G_Q_ER:
            return snprintf(result, lmax, TRANSVR_IF_SP_10G);
        /* 10G Copper */
        case TRANSVR_CLASS_COPPER_L4_10G:
            return snprintf(result, lmax, TRANSVR_IF_SP_10G);
        /* Optical */
        case TRANSVR_CLASS_OPTICAL:
            break;
        /* Copper */
        case TRANSVR_CLASS_COPPER:
            break;
        default:
            snprintf(err_msg, sizeof(err_msg),
                     "Detect undefined class case:%d",
                     detect_val);
            goto err_qsfp_detect_if_speed_1;
    }
    /* Check br and extbr */
    detect_val = _qsfp_detect_if_sp_by_br(self);
    switch(detect_val) {
        case TRANSVR_CLASS_UNSPECIFIED:
            break;
        case TRANSVR_CLASS_10G:
            return snprintf(result, lmax, TRANSVR_IF_SP_10G);
        case TRANSVR_CLASS_40G:
            return snprintf(result, lmax, TRANSVR_IF_SP_40G);
        case TRANSVR_CLASS_100G:
            return snprintf(result, lmax, TRANSVR_IF_SP_100G);
        default:
            snprintf(err_msg, sizeof(err_msg),
                     "Detect undefined BR case:%d",
                     detect_val);
            goto err_qsfp_detect_if_speed_1;
    }
    /* Exception case: Can't verify */
    snprintf(err_msg, sizeof(err_msg), "Can not identify!");
    goto err_qsfp_detect_if_speed_1;

err_qsfp_detect_if_speed_1:
    snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW);
    SWPS_INFO("%s: %s <port>:%s\n", __func__, err_msg, self->swp_name);
    return ERR_TRANSVR_ABNORMAL;
}


int
qsfp_get_if_speed(struct transvr_obj_s *self,
                 char *buf_p){

    int lmax = 16;
    char tmp_result[16] = DEBUG_TRANSVR_STR_VAL;

    if (self->state != STATE_TRANSVR_CONNECTED) {
        return snprintf(buf_p, lmax, "%d\n", self->state);
    }
    if (_qsfp_detect_if_speed(self, tmp_result) < 0) {
        return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_ABNORMAL);
    }
    return snprintf(buf_p, lmax, "%s\n", tmp_result);
}


int
_common_set_lane_map_str(struct transvr_obj_s* self,
                         char *result) {
    int  i = 0;
    int  tmp_val = 0;
    char tmp_str[LEN_TRANSVR_L_STR] = DEBUG_TRANSVR_STR_VAL;
    char err_msg[LEN_TRANSVR_L_STR] = DEBUG_TRANSVR_STR_VAL;

    memset(result, 0, LEN_TRANSVR_L_STR);
    snprintf(result, LEN_TRANSVR_L_STR, "%s=", TRANSVR_UEVENT_KEY_LANE);

    for (i=0; i<ARRAY_SIZE(self->lane_id); i++) {
        tmp_val = self->lane_id[i];
        if (tmp_val < 1) {
            break;
        }
        if (tmp_val > 256) {
            snprintf(err_msg, sizeof(err_msg),
                    "detect abnormal value:%d", tmp_val);
            goto err_common_set_lane_map_str_1;
        }
        memset(tmp_str, 0, sizeof(tmp_str));
        if (i == 0) {
            snprintf(tmp_str, LEN_TRANSVR_L_STR, "%d", tmp_val);
        } else {
            snprintf(tmp_str, LEN_TRANSVR_L_STR, ",%d", tmp_val);
        }
        strncat(result, tmp_str, LEN_TRANSVR_L_STR);
    }
    if (i == 0) {
        goto err_common_set_lane_map_str_2;
    }
    return 0;

err_common_set_lane_map_str_1:
    SWPS_INFO("%s: %s", __func__, err_msg);
err_common_set_lane_map_str_2:
    snprintf(result, LEN_TRANSVR_L_STR, "%s=%s", TRANSVR_UEVENT_KEY_LANE, TRANSVR_UEVENT_UNKNOW);
    return EVENT_TRANSVR_TASK_FAIL;
}


int
_common_send_uevent(struct transvr_obj_s* self,
                    enum kobject_action u_action,
                    int (*detect_if_type)(struct transvr_obj_s *self, char *result),
                    int (*detect_if_speed)(struct transvr_obj_s *self, char *result),
                    int send_anyway) {

    char *uevent_envp[4];
    char err_msg[64]   = DEBUG_TRANSVR_STR_VAL;
    char tmp_str[32]   = DEBUG_TRANSVR_STR_VAL;
    char tmp_str_1[32] = DEBUG_TRANSVR_STR_VAL;
    char tmp_str_2[32] = DEBUG_TRANSVR_STR_VAL;
    char tmp_str_3[64] = DEBUG_TRANSVR_STR_VAL;

    if (TRANSVR_UEVENT_ENABLE != 1) {
        return ERR_TRANSVR_NOTSUPPORT;
    }
    if (_common_get_if_lane(self, tmp_str) < 0) {
        snprintf(tmp_str_3, sizeof(tmp_str_3),
                "%s=%s", TRANSVR_UEVENT_KEY_LANE, TRANSVR_UEVENT_UNKNOW);
    } else {
        snprintf(tmp_str_3, sizeof(tmp_str_3),
                "%s=%s", TRANSVR_UEVENT_KEY_LANE, tmp_str);
    }
    switch (u_action) {
        case KOBJ_ADD:
            /* Detect type */
            if (detect_if_type(self, tmp_str) < 0) {
                snprintf(err_msg, sizeof(err_msg), "%s", "Detect interface type fail!");
                snprintf(tmp_str_1, sizeof(tmp_str_1), "%s=%s", TRANSVR_UEVENT_KEY_IF, TRANSVR_UEVENT_UNKNOW);
                snprintf(tmp_str_2, sizeof(tmp_str_2), "%s=%s", TRANSVR_UEVENT_KEY_SP, TRANSVR_UEVENT_UNKNOW);
                uevent_envp[0] = tmp_str_1;
                uevent_envp[1] = tmp_str_2;
                uevent_envp[2] = tmp_str_3;
                uevent_envp[3] = NULL;
                goto private_common_send_uevent_4_fail;
            }
            snprintf(tmp_str_1, sizeof(tmp_str_1), "%s=%s", TRANSVR_UEVENT_KEY_IF, tmp_str);
            uevent_envp[0] = tmp_str_1;
            /* Detect speed */
            if (detect_if_speed(self, tmp_str) < 0) {
                snprintf(err_msg, sizeof(err_msg), "%s", "Detect interface speed fail!");
                snprintf(tmp_str_2, sizeof(tmp_str_2), "%s=%s", TRANSVR_UEVENT_KEY_SP, TRANSVR_UEVENT_UNKNOW);
                uevent_envp[1] = tmp_str_2;
                uevent_envp[2] = tmp_str_3;
                uevent_envp[3] = NULL;
                goto private_common_send_uevent_4_fail;
            }
            snprintf(tmp_str_2, sizeof(tmp_str_2), "%s=%s", TRANSVR_UEVENT_KEY_SP, tmp_str);
            uevent_envp[1] = tmp_str_2;
            uevent_envp[2] = tmp_str_3;
            uevent_envp[3] = NULL;
            goto private_common_send_uevent_4_send;

        case KOBJ_REMOVE:
            snprintf(tmp_str_1, sizeof(tmp_str_1), "%s=%s", TRANSVR_UEVENT_KEY_IF, TRANSVR_UEVENT_UNKNOW);
            snprintf(tmp_str_2, sizeof(tmp_str_2), "%s=%s", TRANSVR_UEVENT_KEY_SP, TRANSVR_UEVENT_UNKNOW);
            uevent_envp[0] = tmp_str_1;
            uevent_envp[1] = tmp_str_2;
            uevent_envp[2] = tmp_str_3;
            uevent_envp[3] = NULL;
            goto private_common_send_uevent_4_send;

        default:
            snprintf(err_msg, sizeof(err_msg), "kobject_action:%d not support", u_action);
            goto private_common_send_uevent_4_fail;
    }
    snprintf(err_msg, sizeof(err_msg), "%s", "Exception case");
    goto private_common_send_uevent_4_fail;

private_common_send_uevent_4_fail:
    SWPS_INFO("%s: %s <port>:%s\n", __func__, err_msg, self->swp_name);
    if (send_anyway) {
        goto private_common_send_uevent_4_send;
    }
    return ERR_TRANSVR_UEVENT_FAIL;

private_common_send_uevent_4_send:
    return kobject_uevent_env(&(self->transvr_dev_p->kobj),
                              u_action,
                              uevent_envp);
}

int
sfp_send_uevent(struct transvr_obj_s* self,
                enum kobject_action u_action) {
    int send_anyway = 1;
    return _common_send_uevent(self,
                               u_action,
                               &_sfp_detect_if_type,
                               &_sfp_detect_if_speed,
                               send_anyway);
}


int
qsfp_send_uevent(struct transvr_obj_s* self,
                enum kobject_action u_action) {
    int send_anyway = 1;
    return _common_send_uevent(self,
                               u_action,
                               &_qsfp_detect_if_type,
                               &_qsfp_detect_if_speed,
                               send_anyway);
}


int
fake_send_uevent(struct transvr_obj_s* self,
                 enum kobject_action u_action) {
    return EVENT_TRANSVR_TASK_DONE;
}


int
common_fsm_4_direct_mode(struct transvr_obj_s* self,
                         char *caller_name){

    int err;
    int detect_result[2];
    int current_state = STATE_TRANSVR_UNEXCEPTED;
    int current_type  = TRANSVR_TYPE_ERROR;

    if (self->state == STATE_TRANSVR_NEW) {
        if (_transvr_init_handler(self) < 0){
            return ERR_TRANSVR_INIT_FAIL;
        }
    }
    err = detect_transvr_state(self, detect_result);
    if (err < 0) {
        return err;
    }
    /* In Direct mode, driver only detect transceiver when user call driver interface
     * which on sysfs. So it only need consider the state of Transceiver.
     */
    current_state = detect_result[0];
    current_type  = detect_result[1];

    switch (current_state){

        case STATE_TRANSVR_DISCONNECTED:   /* Transceiver is not plugged */
            self->state = current_state;
            self->type  = current_type;
            return ERR_TRANSVR_UNPLUGGED;

        case STATE_TRANSVR_INIT:           /* Transceiver is plugged, system not ready */
            return ERR_TRANSVR_UNINIT;

        case STATE_TRANSVR_ISOLATED:       /* Transceiver is plugged, but has some issues */
            return ERR_TRNASVR_BE_ISOLATED;

        case STATE_TRANSVR_CONNECTED:      /* Transceiver is plugged, system is ready */
            self->state = current_state;
            self->type  = current_type;
            return 0;

        case STATE_TRANSVR_SWAPPED:        /* Transceiver is plugged, system detect user changed */
            self->type = current_type;
            if (reload_transvr_obj(self, current_type) < 0){
                self->state = STATE_TRANSVR_UNEXCEPTED;
                return ERR_TRANSVR_UNEXCPT;
            }
            self->state = current_state;
            return 0;

        case STATE_TRANSVR_UNEXCEPTED:     /* Transceiver type or state is unexpected case */
            self->state = STATE_TRANSVR_UNEXCEPTED;
            self->type  = TRANSVR_TYPE_ERROR;
            return ERR_TRANSVR_UNEXCPT;

        default:
            SWPS_INFO("%s: state:%d not in define.\n", __func__, current_state);
            break;
    }
    return ERR_TRANSVR_UNEXCPT;
}


static int
_is_except_happened_4_pmode(struct transvr_obj_s* self,
                            int new_state) {

    int event_chk = 0;

    if (self->temp == 0){
        return 0;
    }
    switch (new_state) {
        case STATE_TRANSVR_INIT:
            event_chk = EVENT_TRANSVR_EXCEP_INIT;
            goto check_event_happened_4_pmode;

        case STATE_TRANSVR_CONNECTED:
            event_chk = EVENT_TRANSVR_EXCEP_UP;
            goto check_event_happened_4_pmode;

        case STATE_TRANSVR_DISCONNECTED:
            event_chk = EVENT_TRANSVR_EXCEP_DOWN;
            goto check_event_happened_4_pmode;

        case STATE_TRANSVR_SWAPPED:
            event_chk = EVENT_TRANSVR_EXCEP_SWAP;
            goto check_event_happened_4_pmode;

        case STATE_TRANSVR_UNEXCEPTED:
            event_chk = EVENT_TRANSVR_EXCEP_EXCEP;
            goto check_event_happened_4_pmode;

        case STATE_TRANSVR_ISOLATED:
            event_chk = EVENT_TRANSVR_EXCEP_ISOLATED;
            goto check_event_happened_4_pmode;

        default:
            SWPS_INFO("%s: unexcepted case:%d\n", __func__, new_state);
            break;
    }
    return 0;

check_event_happened_4_pmode:
    if (self->temp == event_chk){
        return 1;
    }
    return 0;
}


int
common_fsm_4_polling_mode(struct transvr_obj_s* self,
                          char *caller_name){
    /* [Return Value]:
     *   ERR_TRANSVR_UNINIT      : (1) Initial not ready
     *   ERR_TRANSVR_UNPLUGGED   : (1) Any -> Down
     *   ERR_TRANSVR_TASK_BUSY   : (1) Wait Initial task
     *   ERR_TRANSVR_UNEXCPT     : (1) Initial fail
     *                             (2) Task fail
     *                             (3) Reload fail
     *   ERR_TRNASVR_BE_ISOLATED : (1) Already be isolated
     *   OK Case (return 0)      : (1) action_4_connected
     *                             (2) action_4_nothing (initial retry)
     */
    int curr_state[2];
    int old_state  = self->state;
    int old_type   = self->type;
    int new_state  = STATE_TRANSVR_UNEXCEPTED;
    int new_type   = TRANSVR_TYPE_ERROR;
    int return_val = ERR_TRANSVR_UNEXCPT;

    /* Never initial */
    if (self->state == STATE_TRANSVR_NEW) {
        goto comfsm_action_4_reinit_obj;
    }
    /* Detect current state */
    switch (detect_transvr_state(self, curr_state)) {
      case 0:
          new_state = curr_state[0];
          new_type  = curr_state[1];
          break;

      case ERR_TRNASVR_BE_ISOLATED:
          new_state = STATE_TRANSVR_ISOLATED;
          new_type  = old_type;
          break;

      case ERR_TRANSVR_I2C_CRASH:
          goto comfsm_action_4_report_i2c_crash;

      case ERR_TRANSVR_UNEXCPT:
      default:
          new_state = STATE_TRANSVR_UNEXCEPTED;
          new_type  = old_type;
    }
    /* State handling  */
    switch (old_state) {
       case STATE_TRANSVR_INIT:                  /* INIT -> <ANY> */
           return_val = ERR_TRANSVR_UNINIT;
           goto comfsm_action_4_keep_state;

       case STATE_TRANSVR_CONNECTED:
           switch (new_state) {
               case STATE_TRANSVR_INIT:          /* Case 1-1: UP -> INIT */
                   SWPS_INFO("Detect %s is present. <case>:1-1\n",self->swp_name);
                   return_val = ERR_TRANSVR_UNINIT;
                   goto comfsm_action_4_keep_state;

               case STATE_TRANSVR_CONNECTED:     /* Case 1-2: UP -> UP */
                   return_val = 0;
                   goto comfsm_action_4_keep_state;

               case STATE_TRANSVR_DISCONNECTED:  /* Case 1-3: UP -> DOWN */
                   SWPS_INFO("Detect %s is removed. <case>:1-3\n",self->swp_name);
                   goto comfsm_action_4_disconnected;

               case STATE_TRANSVR_SWAPPED:       /* Case 1-4: UP -> SWAP */
                   SWPS_INFO("Detect %s is swapped. <case>:1-4\n",self->swp_name);
                   goto comfsm_action_4_reload_obj;

               case STATE_TRANSVR_UNEXCEPTED:    /* Case 1-5: UP -> UNEXPET */
                   SWPS_INFO("Detect %s has error. <case>:1-5\n",self->swp_name);
                   goto comfsm_action_4_unexpected;

               case STATE_TRANSVR_ISOLATED:      /* Case 1-6: UP -> ISOLATE */
                   SWPS_INFO("Detect %s be isolated. <case>:1-6\n",self->swp_name);
                   goto comfsm_action_4_isolate_obj;

               default:
                   break;
           }
           goto comfsm_action_4_unexpected;

       case STATE_TRANSVR_DISCONNECTED:
           switch (new_state) {
               case STATE_TRANSVR_INIT:          /* Case 2-1: DOWN -> INIT */
                   SWPS_INFO("Detect %s is present. <case>:2-1\n",self->swp_name);
                   return_val   = ERR_TRANSVR_UNINIT;
                   goto comfsm_action_4_keep_state;

               case STATE_TRANSVR_CONNECTED:     /* Case 2-2: DOWN -> UP */
                   SWPS_INFO("Detect %s is present. <case>:2-2\n",self->swp_name);
                   goto comfsm_action_4_reinit_obj;

               case STATE_TRANSVR_DISCONNECTED:  /* Case 2-3: DOWN -> DOWN */
                   return_val = ERR_TRANSVR_UNPLUGGED;
                   goto comfsm_action_4_keep_state;

               case STATE_TRANSVR_SWAPPED:       /* Case 2-4: DOWN -> SWAP */
                   SWPS_INFO("Detect %s is swapped. <case>:2-4\n",self->swp_name);
                   goto comfsm_action_4_reload_obj;

               case STATE_TRANSVR_UNEXCEPTED:    /* Case 2-5: DOWN -> UNEXPET */
                   SWPS_INFO("Detect %s has error. <case>:2-5\n",self->swp_name);
                   goto comfsm_action_4_unexpected;

               case STATE_TRANSVR_ISOLATED:      /* Case 2-6: DOWN -> ISOLATE */
                   SWPS_INFO("Detect %s be isolated. <case>:2-6\n",self->swp_name);
                   goto comfsm_action_4_isolate_obj;

               default:
                   break;
           }
           goto comfsm_action_4_unexpected;

       case STATE_TRANSVR_UNEXCEPTED:
           /* Filter out re-action */
           if (_is_except_happened_4_pmode(self, new_state)) {
               goto comfsm_action_4_keep_state;
           }
           /* First action */
           switch (new_state) {
               case STATE_TRANSVR_INIT:          /* Case 3-1: UNEXPET -> INIT */
                   SWPS_INFO("Detect %s is present. <case>:3-1\n",self->swp_name);
                   self->temp = EVENT_TRANSVR_EXCEP_INIT;
                   return_val = ERR_TRANSVR_UNINIT;
                   goto comfsm_action_4_keep_state;

               case STATE_TRANSVR_CONNECTED:     /* Case 3-2: UNEXPET -> UP */
                   SWPS_INFO("Detect %s is present. <case>:3-2\n",self->swp_name);
                   self->temp = EVENT_TRANSVR_EXCEP_UP;
                   goto comfsm_action_4_reload_obj;

               case STATE_TRANSVR_DISCONNECTED:  /* Case 3-3: UNEXPET -> DOWN */
                   SWPS_INFO("Detect %s is removed. <case>:3-3\n",self->swp_name);
                   goto comfsm_action_4_disconnected;

               case STATE_TRANSVR_SWAPPED:       /* Case 3-4: UNEXPET -> SWAP */
                   SWPS_INFO("Detect %s is swapped. <case>:3-4\n",self->swp_name);
                   self->temp = EVENT_TRANSVR_EXCEP_SWAP;
                   goto comfsm_action_4_reload_obj;

               case STATE_TRANSVR_UNEXCEPTED:    /* Case 3-5: UNEXPET -> UNEXPET */
                   self->temp = EVENT_TRANSVR_EXCEP_EXCEP;
                   return_val = ERR_TRANSVR_UNEXCPT;
                   goto comfsm_action_4_keep_state;

               case STATE_TRANSVR_ISOLATED:      /* Case 3-6: UNEXPET -> ISOLATE */
                   SWPS_INFO("Detect %s be isolated. <case>:3-6\n",self->swp_name);
                   goto comfsm_action_4_isolate_obj;

               default:
                   break;
           }
           goto comfsm_action_4_unexpected;

        case STATE_TRANSVR_ISOLATED:
            /* Filter out re-action */
            if (_is_except_happened_4_pmode(self, new_state)) {
                goto comfsm_action_4_keep_state;
            }
            /* First action */
            switch (new_state) {
                case STATE_TRANSVR_INIT:          /* Case 4-1: ISOLATE -> INIT */
                    SWPS_INFO("Detect %s internal error. <case>:4-1\n",self->swp_name);
                    self->temp = EVENT_TRANSVR_EXCEP_INIT;
                    return_val = ERR_TRNASVR_BE_ISOLATED;
                    goto comfsm_action_4_keep_state;

                case STATE_TRANSVR_CONNECTED:     /* Case 4-2: ISOLATE -> UP */
                    SWPS_INFO("Detect %s internal error. <case>:4-2\n",self->swp_name);
                    self->temp = EVENT_TRANSVR_EXCEP_UP;
                    return_val = ERR_TRNASVR_BE_ISOLATED;
                    goto comfsm_action_4_keep_state;

                case STATE_TRANSVR_DISCONNECTED:  /* Case 4-3: ISOLATE -> DOWN */
                    SWPS_INFO("Detect %s is removed. <case>:4-3\n",self->swp_name);
                    goto comfsm_action_4_disconnected;

                case STATE_TRANSVR_SWAPPED:       /* Case 4-4: ISOLATE -> SWAP */
                    SWPS_INFO("Detect %s internal error. <case>:4-4\n",self->swp_name);
                    self->temp = EVENT_TRANSVR_EXCEP_SWAP;
                    return_val = ERR_TRNASVR_BE_ISOLATED;
                    goto comfsm_action_4_keep_state;

                case STATE_TRANSVR_UNEXCEPTED:    /* Case 4-5: ISOLATE -> UNEXPET */
                    SWPS_INFO("Detect %s internal error. <case>:4-5\n",self->swp_name);
                    self->temp = EVENT_TRANSVR_EXCEP_EXCEP;
                    return_val = ERR_TRNASVR_BE_ISOLATED;
                    goto comfsm_action_4_keep_state;

                case STATE_TRANSVR_ISOLATED:      /* Case 4-6: ISOLATE -> ISOLATE */
                    return_val = ERR_TRNASVR_BE_ISOLATED;
                    goto comfsm_action_4_keep_state;

                default:
                    break;
            }
            goto comfsm_action_4_unexpected;

       default:
           break;
    }
    goto comfsm_action_4_unexpected;


comfsm_action_4_keep_state:
    return return_val;

comfsm_action_4_reinit_obj:
    SWPS_DEBUG("FSM action: %s re-initial.\n", self->swp_name);
    return_val = _transvr_init_handler(self);
    goto comfsm_action_4_identify_event;

comfsm_action_4_reload_obj:
    SWPS_DEBUG("FSM action: %s reload.\n", self->swp_name);
    self->type = new_type;
    return_val = reload_transvr_obj(self, new_type);
    goto comfsm_action_4_identify_event;

comfsm_action_4_identify_event:
    switch (return_val) {
        case EVENT_TRANSVR_INIT_UP:
        case EVENT_TRANSVR_TASK_DONE:
            goto comfsm_action_4_connected;

        case EVENT_TRANSVR_INIT_DOWN:
            goto comfsm_action_4_disconnected;

        case EVENT_TRANSVR_INIT_REINIT:
            goto comfsm_action_4_nothing;

        case EVENT_TRANSVR_TASK_WAIT:
            self->state = STATE_TRANSVR_INIT;
            return ERR_TRANSVR_TASK_BUSY;

        case EVENT_TRANSVR_TASK_FAIL:
            SWPS_INFO("%s detect EVENT_TRANSVR_TASK_FAIL.\n", self->swp_name);
            goto comfsm_action_4_unexpected;

        case EVENT_TRANSVR_INIT_FAIL:
            SWPS_INFO("%s detect EVENT_TRANSVR_INIT_FAIL.\n", self->swp_name);
            goto comfsm_action_4_unexpected;

        case EVENT_TRANSVR_RELOAD_FAIL:
            SWPS_INFO("%s detect EVENT_TRANSVR_RELOAD_FAIL.\n", self->swp_name);
            goto comfsm_action_4_unexpected;

        case EVENT_TRANSVR_I2C_CRASH:
            goto comfsm_action_4_report_i2c_crash;

        case EVENT_TRANSVR_EXCEP_ISOLATED:
            goto comfsm_action_4_isolate_obj;

        default:
            SWPS_INFO("%s detect undefined event:%d.\n", self->swp_name, return_val);
            goto comfsm_action_4_unexpected;
    }

comfsm_action_4_nothing:
    SWPS_DEBUG("FSM action: %s do nothing.\n", self->swp_name);
    return 0;

comfsm_action_4_connected:
    SWPS_DEBUG("FSM action: %s Connected.\n", self->swp_name);
    self->state = STATE_TRANSVR_CONNECTED;
    self->type  = new_type;
    self->send_uevent(self, KOBJ_ADD);
    _transvr_clean_retry(self);
    return 0;

comfsm_action_4_disconnected:
    SWPS_DEBUG("FSM action: %s Disconnected. \n", self->swp_name);
    self->state = STATE_TRANSVR_DISCONNECTED;
    self->temp  = EVENT_TRANSVR_TASK_DONE;
    self->send_uevent(self, KOBJ_REMOVE);
    _transvr_clean_retry(self);
    _transvr_clean_handler(self);
    return ERR_TRANSVR_UNPLUGGED;

comfsm_action_4_report_i2c_crash:
    SWPS_DEBUG("FSM action: %s report I2C crash.\n", self->swp_name);
    self->state = STATE_TRANSVR_UNEXCEPTED;
    return ERR_TRANSVR_I2C_CRASH;

comfsm_action_4_isolate_obj:
    SWPS_DEBUG("FSM action: %s isolate.\n", self->swp_name);
    self->state = STATE_TRANSVR_ISOLATED;
    return ERR_TRNASVR_BE_ISOLATED;

comfsm_action_4_unexpected:
    SWPS_INFO("FSM action: %s unexpected.\n", self->swp_name);
    SWPS_INFO("Dump: <os>:%d <ot>:0x%02x <ns>:%d <nt>:0x%02x\n",
              old_state, old_type, new_state, new_type);
    self->state = STATE_TRANSVR_UNEXCEPTED;
    self->send_uevent(self, KOBJ_REMOVE);
    _transvr_clean_handler(self);
    return ERR_TRANSVR_UNEXCPT;
}


int
fake_fsm_4_direct_mode(struct transvr_obj_s* self,
                       char *caller_name){
    self->state = STATE_TRANSVR_CONNECTED;
    self->type  = TRANSVR_TYPE_FAKE;
    return 0;
}


int
fake_fsm_4_polling_mode(struct transvr_obj_s* self,
                        char *caller_name){
    self->state = STATE_TRANSVR_CONNECTED;
    self->type  = TRANSVR_TYPE_FAKE;
    return 0;
}


/* ========== Object functions for Initial procedure ==========
 */
int
transvr_init_common(struct transvr_obj_s *self){
    /* Nothing to update */
    return EVENT_TRANSVR_TASK_DONE;
}


int
transvr_init_fake(struct transvr_obj_s *self){
    return EVENT_TRANSVR_TASK_DONE;
}


int
transvr_init_sfp(struct transvr_obj_s *self){

    int  tmp_val  = DEBUG_TRANSVR_INT_VAL;
    int  err_code = DEBUG_TRANSVR_INT_VAL;
    char *err_msg = "ERR";

    self->info = sft_detect_transvr_class(self);
    /* Disable auto_config */
    if (!self->auto_config) {
        return EVENT_TRANSVR_TASK_DONE;
    }
    /* Handle multi-rate */
    err_code = initfunc_sfp_handle_multi_rate_mode(self);
    if (err_code < 0) {
        err_msg = "initfunc_sfp_handle_multi_rate_mode fail!";
        goto err_transvr_init_sfp_1;
    }
    /* Handle 1G- RJ45 */
    tmp_val  = err_code;
    err_code = initfunc_sfp_handle_1g_rj45(self);
    if (err_code < 0) {
        err_msg = "initfunc_sfp_handle_1g_rj45 fail!";
        goto err_transvr_init_sfp_1;
    }
    tmp_val = (tmp_val > err_code ? tmp_val : err_code);
    if (tmp_val > EVENT_TRANSVR_TASK_DONE) {
        return tmp_val;
    }
    return EVENT_TRANSVR_TASK_DONE;

err_transvr_init_sfp_1:
    SWPS_INFO("%s: %s <err>:%d <port>:%s\n",
              __func__, err_msg, err_code, self->swp_name);
    return EVENT_TRANSVR_INIT_FAIL;
}


int
transvr_init_qsfp(struct transvr_obj_s *self){

    int  err = EVENT_TRANSVR_EXCEP_EXCEP;
    char *emsg = "ERR";

    self->info = qsft_detect_transvr_class(self);
    if (!self->auto_config) {
        return EVENT_TRANSVR_TASK_DONE;
    }
    err = initfunc_qsfp_handle_power_mode(self);
    if (err < 0){
        emsg = "initfunc_qsfp_handle_tx_disable fail!";
        goto err_transvr_init_qsfp;
    }
    return EVENT_TRANSVR_TASK_DONE;

err_transvr_init_qsfp:
    SWPS_INFO("%s: %s <err>:%d <port>:%s\n",
              __func__, emsg, err, self->swp_name);
    return EVENT_TRANSVR_INIT_FAIL;
}


int
transvr_init_qsfp28(struct transvr_obj_s *self){

    int  tmp_val  = EVENT_TRANSVR_EXCEP_EXCEP;
    int  err_val  = EVENT_TRANSVR_EXCEP_EXCEP;
    char *err_msg = "ERR";

    /* Handle QSFP common */
    err_val = transvr_init_qsfp(self);
    if (err_val < 0){
        err_msg = "transvr_init_qsfp fail!";
        goto err_transvr_init_qsfp28_1;
    }
    /* Disable auto_config */
    if (!self->auto_config) {
        return err_val;
    }
    /* Handle CDR */
    tmp_val = err_val;
    err_val = initfunc_qsfp28_handle_cdr(self);
    if (err_val < 0){
        err_msg = "Handle CDR fail!";
        goto err_transvr_init_qsfp28_1;
    }
    tmp_val = (tmp_val > err_val ? tmp_val : err_val);
    if (tmp_val > EVENT_TRANSVR_TASK_DONE) {
        return tmp_val;
    }
    return EVENT_TRANSVR_TASK_DONE;

err_transvr_init_qsfp28_1:
    SWPS_INFO("%s: %s <err>:%d <port>:%s\n",
              __func__, err_msg, err_val, self->swp_name);
    return EVENT_TRANSVR_INIT_FAIL;
}


/* ========== Object Initial handler ==========
 */
static int
_is_transvr_valid(struct transvr_obj_s *self,
                  int type,
                  int state) {
    /* [Return]
     *   0                        : OK, inserted
     *   EVENT_TRANSVR_INIT_DOWN  : OK, removed
     *   EVENT_TRANSVR_INIT_FAIL  : Outside error, type doesn't supported
     *   EVENT_TRANSVR_EXCEP_INIT : Internal error, state undefined
     */
    switch (type) {
        case TRANSVR_TYPE_SFP:
        case TRANSVR_TYPE_QSFP:
        case TRANSVR_TYPE_QSFP_PLUS:
        case TRANSVR_TYPE_QSFP_28:
        case TRANSVR_TYPE_UNPLUGGED:
        case TRANSVR_TYPE_FAKE:
            break;
        default:
            SWPS_INFO("detect undefined type:0x%02x on %s\n",
                      type, self->swp_name);
            return EVENT_TRANSVR_INIT_FAIL;
    }
    switch (state) {
        case STATE_TRANSVR_DISCONNECTED:
            return EVENT_TRANSVR_INIT_DOWN;
        case STATE_TRANSVR_INIT:
        case STATE_TRANSVR_CONNECTED:
        case STATE_TRANSVR_SWAPPED:
            break;
        default:
            SWPS_INFO("detect undefined state:%d on %s\n",
                      state, self->swp_name);
            return EVENT_TRANSVR_EXCEP_INIT;
    }
    return 0;
}


static int
_is_transvr_hw_ready(struct transvr_obj_s *self,
                     int type){
    /* [Return]
     *   EVENT_TRANSVR_TASK_DONE : Ready
     *   EVENT_TRANSVR_TASK_WAIT : Not ready
     *   EVENT_TRANSVR_INIT_FAIL : Error
     */
    int addr   = DEBUG_TRANSVR_INT_VAL;
    int page   = DEBUG_TRANSVR_INT_VAL;
    int offs   = DEBUG_TRANSVR_INT_VAL;
    int bit    = DEBUG_TRANSVR_INT_VAL;
    int ready  = DEBUG_TRANSVR_INT_VAL;
    int err    = DEBUG_TRANSVR_INT_VAL;
    char *emsg = DEBUG_TRANSVR_STR_VAL;
    uint8_t ab_val = DEBUG_TRANSVR_HEX_VAL;

    switch (type) {
        case TRANSVR_TYPE_SFP:
            addr   = VAL_TRANSVR_8472_READY_ADDR;
            page   = VAL_TRANSVR_8472_READY_PAGE;
            offs   = VAL_TRANSVR_8472_READY_OFFSET;
            bit    = VAL_TRANSVR_8472_READY_BIT;
            ready  = VAL_TRANSVR_8472_READY_VALUE;
            ab_val = VAL_TRANSVR_8472_READY_ABNORMAL;
            break;

        case TRANSVR_TYPE_QSFP:
        case TRANSVR_TYPE_QSFP_PLUS:
        case TRANSVR_TYPE_QSFP_28:
            addr   = VAL_TRANSVR_8436_READY_ADDR;
            page   = VAL_TRANSVR_8436_READY_PAGE;
            offs   = VAL_TRANSVR_8436_READY_OFFSET;
            bit    = VAL_TRANSVR_8436_READY_BIT;
            ready  = VAL_TRANSVR_8436_READY_VALUE;
            ab_val = VAL_TRANSVR_8436_READY_ABNORMAL;
            break;

        case TRANSVR_TYPE_UNPLUGGED:
        case TRANSVR_TYPE_FAKE:
            return EVENT_TRANSVR_TASK_DONE;

        default:
            emsg = "unexpected case";
            goto err_is_transvr_hw_ready;
    }
    /* Select target page */
    err = _common_setup_page(self, addr, page, offs, 1, 0);
    if (err < 0) {
        emsg = "setup page fail";
        goto err_is_transvr_hw_ready;
    }
    /* Check feature supported
     * [Note]
     *   Some of transceiver/cables doesn't support "Status Indicators"
     *   (ex:DAC, RJ45 copper SFP ...etc). In these case, we bypass the
     *   step of checking Status Indicators, then state machine will take
     *   the following handle procedure.
     */
    err = i2c_smbus_read_byte_data(self->i2c_client_p,
                                   VAL_TRANSVR_COMID_OFFSET);
    if (err < 0) {
        emsg = "doesn't support Status Indicators";
        goto bypass_is_transvr_hw_ready;
    }
    /* Filter abnormal case */
    if (err == ab_val) {
        emsg = "detect using unusual definition.";
        goto bypass_is_transvr_hw_ready;
    }
    /* Get Status Indicators */
    err = i2c_smbus_read_byte_data(self->i2c_client_p, offs);
    if (err < 0) {
        emsg = "detect current value fail";
        goto err_is_transvr_hw_ready;
    }
    if ((err & (1<<bit)) == ready) {
        return EVENT_TRANSVR_TASK_DONE;
    }
    return EVENT_TRANSVR_TASK_WAIT;

bypass_is_transvr_hw_ready:
    SWPS_DEBUG("%s: %s <type>:%d\n", __func__, emsg, type);
    return EVENT_TRANSVR_TASK_DONE;

err_is_transvr_hw_ready:
    SWPS_DEBUG("%s: %s <type>:%d\n", __func__, emsg, type);
    return EVENT_TRANSVR_INIT_FAIL;
}


static int
_is_transvr_support_ctle(struct transvr_obj_s *self) {

    switch (self->info) {
        case TRANSVR_CLASS_OPTICAL_25G:
        case TRANSVR_CLASS_OPTICAL_25G_AOC:
        case TRANSVR_CLASS_OPTICAL_25G_SR:
        case TRANSVR_CLASS_OPTICAL_25G_LR:
        case TRANSVR_CLASS_OPTICAL_25G_ER:
        case TRANSVR_CLASS_OPTICAL_100G:
        case TRANSVR_CLASS_OPTICAL_100G_AOC:
        case TRANSVR_CLASS_OPTICAL_100G_SR4:
        case TRANSVR_CLASS_OPTICAL_100G_LR4:
        case TRANSVR_CLASS_OPTICAL_100G_ER4:
        case TRANSVR_CLASS_OPTICAL_100G_PSM4:
            return 1;
        default:
            break;
    }
    return 0;
}


static int
_transvr_init_handler(struct transvr_obj_s *self){

    int detect[2];
    int d_state   = STATE_TRANSVR_UNEXCEPTED;
    int d_type    = TRANSVR_TYPE_ERROR;
    int result    = ERR_TRANSVR_UNINIT;
    int retry     = 6;  /* (6+1) x 0.3 = 2.1s > spec:2.0s */
    int elimit    = 63;
    char emsg[64] = DEBUG_TRANSVR_STR_VAL;

    /* Clean and check callback */
    self->state = STATE_TRANSVR_INIT;
    if (self->init == NULL) {
        snprintf(emsg, elimit, "init() is null");
        goto initer_err_case_unexcept_0;
    }
    if (self->clean == NULL) {
        snprintf(emsg, elimit, "clean() is null");
        goto initer_err_case_unexcept_0;
    }
    self->clean(self);

    /* Detect transceiver information */
    result = detect_transvr_state(self, detect);
    if (result < 0) {
        snprintf(emsg, elimit, "detect_transvr_state() fail");
        switch (result) {
            case ERR_TRANSVR_I2C_CRASH:
                goto initer_err_case_i2c_ceash;
            case ERR_TRNASVR_BE_ISOLATED:
                goto initer_err_case_be_isolated;

            case ERR_TRANSVR_UNEXCPT:
            default:
                break;
        }
        goto initer_err_case_retry_1;
    }
    d_state = detect[0];
    d_type  = detect[1];

    /* Verify transceiver type and state */
    switch (_is_transvr_valid(self, d_type, d_state)) {
        case 0:
            break;
        case EVENT_TRANSVR_INIT_DOWN:
            goto initer_ok_case_down;;
        case EVENT_TRANSVR_INIT_FAIL:
            snprintf(emsg, elimit, "transceiver type doesn't support");
            goto initer_err_case_alarm_to_user;
        case EVENT_TRANSVR_EXCEP_INIT:
        default:
            goto initer_err_case_unexcept_1;
    }

    /* Handle reload case */
    if (self->type != d_type){
        /* This is the protect mechanism. Normally, This case will not happen.
         * When State machine detect swap event during initial, It will trigger
         * reload function to ensure type correct. */
        if (_reload_transvr_obj(self, d_type) < 0){
            snprintf(emsg, elimit, "reload object fail");
            goto initer_err_case_unexcept_1;
        }
    }

    /* Check transceiver HW initial ready */
    switch (_is_transvr_hw_ready(self, d_type)) {
        case EVENT_TRANSVR_TASK_DONE:
            break;
        case EVENT_TRANSVR_TASK_WAIT:
            goto initer_err_case_retry_1;
        case EVENT_TRANSVR_INIT_FAIL:
        default:
            goto initer_err_case_unexcept_1;
    }

    /* Try to update all and check */
    if (self->update_all(self, 1) < 0){
        /* For some transceiver, EEPROME has lag issues during initial stage.
         * In this case, we set status back to STATE_TRANSVR_NEW, than it will
         * be checked in next polling cycle. */
        goto initer_err_case_retry_1;
    }

    /* Execute init() call back */
    result = self->init(self);
    switch (result) {
        case EVENT_TRANSVR_TASK_DONE:
            break;
        case EVENT_TRANSVR_TASK_WAIT:
            goto initer_ok_case_wait;

        default:
            snprintf(emsg, elimit, "undefined init() return:%d\n", result);
            goto initer_err_case_unexcept_1;
    }
    goto initer_ok_case_up;


initer_ok_case_wait:
    self->dump_all(self);
    return EVENT_TRANSVR_TASK_WAIT;

initer_ok_case_up:
    self->state = STATE_TRANSVR_CONNECTED;
    self->temp  = 0;
    self->dump_all(self);
    return EVENT_TRANSVR_INIT_UP;

initer_ok_case_down:
    self->temp  = 0;
    self->state = STATE_TRANSVR_DISCONNECTED;
    return EVENT_TRANSVR_INIT_DOWN;

initer_err_case_i2c_ceash:
    SWPS_DEBUG("%s: %s <port>:%s <case>:I2C crash\n",
               __func__, emsg, self->swp_name);
    self->state = STATE_TRANSVR_UNEXCEPTED;
    return EVENT_TRANSVR_I2C_CRASH;

initer_err_case_be_isolated:
    SWPS_DEBUG("%s: %s <port>:%s <case>:isolated\n",
               __func__, emsg, self->swp_name);
    self->state = STATE_TRANSVR_ISOLATED;
    return EVENT_TRANSVR_EXCEP_ISOLATED;

initer_err_case_retry_1:
    SWPS_DEBUG("%s: %s <port>:%s <case>:retry\n",
               __func__, emsg, self->swp_name);
    if (_transvr_handle_retry(self, retry) == 0) {
        self->state = STATE_TRANSVR_NEW;
        return EVENT_TRANSVR_INIT_REINIT;
    }
    goto initer_err_case_alarm_to_user;

initer_err_case_unexcept_1:
    self->clean(self);
initer_err_case_unexcept_0:
    self->state = STATE_TRANSVR_UNEXCEPTED;
    if (_is_except_happened_4_pmode(self, d_state) &&
        (self->mode == TRANSVR_MODE_POLLING) ){
        SWPS_INFO("%s: %s <port>:%s\n", __func__, emsg, self->swp_name);
        SWPS_INFO("Dump: <os>:%d <ot>:%d <ns>:%d <nt>:%d\n",
                   self->state, self->type, d_state, d_type);
    }
    return EVENT_TRANSVR_INIT_FAIL;

initer_err_case_alarm_to_user:
    SWPS_DEBUG("%s: %s <port>:%s <case>:alarm_to_user\n",
               __func__, emsg, self->swp_name);
    self->state = STATE_TRANSVR_UNEXCEPTED;
    alarm_msg_2_user(self, "detected transceiver/cables not meet SFF standard");
    return EVENT_TRANSVR_INIT_FAIL;
}


/* ========== Object functions for Clean procedure ==========
 */
int
_transvr_clean_handler(struct transvr_obj_s *self){

    int retval = DEBUG_TRANSVR_INT_VAL;

    if (!self->clean) {
        SWPS_ERR("%s: %s clean() is NULL.\n",
                __func__, self->swp_name);
        return EVENT_TRANSVR_TASK_FAIL;
    }
    retval = self->clean(self);
    if (retval != EVENT_TRANSVR_TASK_DONE){
        SWPS_ERR("%s: %s clean() fail. [ERR]:%d\n",
                __func__, self->swp_name, retval);
        return retval;
    }
    return EVENT_TRANSVR_TASK_DONE;
}


int
common_transvr_clean(struct transvr_obj_s *self){

    transvr_task_free_all(self);
    transvr_cache_free_all(self);
    return EVENT_TRANSVR_TASK_DONE;
}


int
qsfp_transvr_clean(struct transvr_obj_s *self){

    int retval;
    int lpower_config = 1;

    retval = _taskfunc_qsfp_setup_power_mod(self, lpower_config);
    if (retval < 0){
        SWPS_ERR("%s: Set lpmod fail! <err>:%d\n",
                __func__, retval);
        return retval;
    }
    retval = common_transvr_clean(self);
    if (retval < 0){
        SWPS_ERR("%s: common_transvr_clean fail! <err>:%d\n",
                __func__, retval);
        return retval;
    }
    return EVENT_TRANSVR_TASK_DONE;
}


int
fake_transvr_clean(struct transvr_obj_s *self){

    return EVENT_TRANSVR_TASK_DONE;
}


/* ========== Object functions for check and update ==========
 */
int
common_transvr_check(struct transvr_obj_s *self){

    char fun_str[32]  = "common_transvr_check";

    if (self->mode != TRANSVR_MODE_POLLING) {
        SWPS_ERR("%s: mode:%d is not TRANSVR_MODE_POLLING\n",
                fun_str, self->mode);
        return ERR_TRANSVR_UNEXCPT;
    }
    /* Trigger delay task */
    transvr_task_run_all(self);
    /* Trigger state machine to check and update */
    return self->fsm_4_polling(self, fun_str);
}


int
fake_transvr_check(struct transvr_obj_s *self){
    return 0;
}


/* ========== Functions for Factory pattern ==========
 */
static int
setup_transvr_public_cb(struct transvr_obj_s *self,
                        int transvr_type){
    switch (transvr_type){
        case TRANSVR_TYPE_SFP:
            self->get_id              = common_get_id;
            self->get_ext_id          = common_get_ext_id;
            self->get_connector       = common_get_connector;
            self->get_vendor_name     = common_get_vendor_name;
            self->get_vendor_pn       = common_get_vendor_pn;
            self->get_vendor_rev      = common_get_vendor_rev;
            self->get_vendor_sn       = common_get_vendor_sn;
            self->get_power_cls       = unsupported_get_func;
            self->get_br              = common_get_br;
            self->get_len_sm          = sfp_get_len_sm;
            self->get_len_smf         = common_get_len_smf;
            self->get_len_om1         = common_get_len_om1;
            self->get_len_om2         = common_get_len_om2;
            self->get_len_om3         = common_get_len_om3;
            self->get_len_om4         = common_get_len_om4;
            self->get_comp_rev        = common_get_comp_rev;
            self->get_comp_eth_1      = sfp_get_comp_eth_1;
            self->get_comp_eth_10     = sfp_get_comp_eth_10;
            self->get_comp_eth_10_40  = unsupported_get_func;
            self->get_comp_extend     = common_get_comp_extended;
            self->get_cdr             = unsupported_get_func;
            self->get_rate_id         = sfp_get_rate_id;
            self->get_soft_rs0        = sfp_get_soft_rs0;
            self->get_soft_rs1        = sfp_get_soft_rs1;
            self->get_info            = common_get_info;
            self->get_if_type         = sfp_get_if_type;
            self->get_if_speed        = sfp_get_if_speed;
            self->get_if_lane         = common_get_if_lane;
            self->get_curr_temp       = sfp_get_transvr_temp;
            self->get_curr_vol        = sfp_get_transvr_voltage;
            self->get_soft_rx_los     = unsupported_get_func2;
            self->get_soft_tx_disable = unsupported_get_func2;
            self->get_soft_tx_fault   = unsupported_get_func2;
            self->get_auto_tx_disable = unsupported_get_func2;
            self->get_tx_bias         = sfp_get_transvr_tx_bias;
            self->get_tx_power        = sfp_get_transvr_tx_power;
            self->get_rx_power        = sfp_get_transvr_rx_power;
            self->get_tx_eq           = sfp_get_transvr_tx_eq;
            self->get_rx_am           = unsupported_get_func2;
            self->get_rx_em           = sfp_get_transvr_rx_em;
            self->get_wavelength      = sfp_get_wavelength;
            self->get_extphy_offset   = sfp_get_1g_rj45_extphy_offset;
            self->get_extphy_reg      = sfp_get_1g_rj45_extphy_reg;
            self->set_cdr             = unsupported_set_func;
            self->set_soft_rs0        = sfp_set_soft_rs0;
            self->set_soft_rs1        = sfp_set_soft_rs1;
            self->set_soft_tx_disable = unsupported_set_func;
            self->set_auto_tx_disable = unsupported_set_func;
            self->set_tx_eq           = sfp_set_tx_eq;
            self->set_rx_am           = unsupported_set_func;
            self->set_rx_em           = sfp_set_rx_em;
            self->set_extphy_offset   = sfp_set_1g_rj45_extphy_offset;
            self->set_extphy_reg      = sfp_set_1g_rj45_extphy_reg;
            return 0;

        case TRANSVR_TYPE_QSFP:
        case TRANSVR_TYPE_QSFP_PLUS:
            self->get_id              = common_get_id;
            self->get_ext_id          = common_get_ext_id;
            self->get_connector       = common_get_connector;
            self->get_vendor_name     = common_get_vendor_name;
            self->get_vendor_pn       = common_get_vendor_pn;
            self->get_vendor_rev      = common_get_vendor_rev;
            self->get_vendor_sn       = common_get_vendor_sn;
            self->get_power_cls       = qsfp_get_power_cls;
            self->get_br              = common_get_br;
            self->get_len_sm          = unsupported_get_func;
            self->get_len_smf         = common_get_len_smf;
            self->get_len_om1         = common_get_len_om1;
            self->get_len_om2         = common_get_len_om2;
            self->get_len_om3         = common_get_len_om3;
            self->get_len_om4         = common_get_len_om4;
            self->get_comp_rev        = common_get_comp_rev;
            self->get_comp_eth_1      = qsfp_get_comp_eth;
            self->get_comp_eth_10     = unsupported_get_func;
            self->get_comp_eth_10_40  = qsfp_get_comp_10_40;
            self->get_comp_extend     = common_get_comp_extended;
            self->get_cdr             = unsupported_get_func;
            self->get_rate_id         = unsupported_get_func;
            self->get_soft_rs0        = unsupported_get_func; /* TBD */
            self->get_soft_rs1        = unsupported_get_func; /* TBD */
            self->get_info            = common_get_info;
            self->get_if_type         = qsfp_get_if_type;
            self->get_if_speed        = qsfp_get_if_speed;
            self->get_if_lane         = common_get_if_lane;
            self->get_curr_temp       = qsfp_get_transvr_temp;
            self->get_curr_vol        = qsfp_get_transvr_voltage;
            self->get_soft_rx_los     = qsfp_get_soft_rx_los;
            self->get_soft_tx_disable = qsfp_get_soft_tx_disable;
            self->get_soft_tx_fault   = qsfp_get_soft_tx_fault;
            self->get_auto_tx_disable = qsfp_get_auto_tx_disable;
            self->get_tx_bias         = qsfp_get_transvr_tx_bias;
            self->get_tx_power        = qsfp_get_transvr_tx_power;
            self->get_rx_power        = qsfp_get_transvr_rx_power;
            self->get_tx_eq           = unsupported_get_func2;
            self->get_rx_am           = unsupported_get_func2;
            self->get_rx_em           = unsupported_get_func2;
            self->get_wavelength      = qsfp_get_wavelength;
            self->get_extphy_offset   = unsupported_get_func2;
            self->get_extphy_reg      = unsupported_get_func2;
            self->set_cdr             = unsupported_set_func;
            self->set_soft_rs0        = unsupported_set_func; /* TBD */
            self->set_soft_rs1        = unsupported_set_func; /* TBD */
            self->set_soft_tx_disable = qsfp_set_soft_tx_disable;
            self->set_auto_tx_disable = qsfp_set_auto_tx_disable;
            self->set_tx_eq           = unsupported_set_func;
            self->set_rx_am           = unsupported_set_func;
            self->set_rx_em           = unsupported_set_func;
            self->set_extphy_offset   = unsupported_set_func;
            self->set_extphy_reg      = unsupported_set_func;
            return 0;

        case TRANSVR_TYPE_QSFP_28:
            self->get_id              = common_get_id;
            self->get_ext_id          = common_get_ext_id;
            self->get_connector       = common_get_connector;
            self->get_vendor_name     = common_get_vendor_name;
            self->get_vendor_pn       = common_get_vendor_pn;
            self->get_vendor_rev      = common_get_vendor_rev;
            self->get_vendor_sn       = common_get_vendor_sn;
            self->get_power_cls       = qsfp_get_power_cls;
            self->get_br              = common_get_br;
            self->get_len_sm          = unsupported_get_func;
            self->get_len_smf         = common_get_len_smf;
            self->get_len_om1         = common_get_len_om1;
            self->get_len_om2         = common_get_len_om2;
            self->get_len_om3         = common_get_len_om3;
            self->get_len_om4         = common_get_len_om4;
            self->get_comp_rev        = common_get_comp_rev;
            self->get_comp_eth_1      = qsfp_get_comp_eth;
            self->get_comp_eth_10     = unsupported_get_func;
            self->get_comp_eth_10_40  = qsfp_get_comp_10_40;
            self->get_comp_extend     = common_get_comp_extended;
            self->get_cdr             = qsfp_get_cdr;
            self->get_rate_id         = unsupported_get_func;
            self->get_soft_rs0        = unsupported_get_func; /* TBD */
            self->get_soft_rs1        = unsupported_get_func; /* TBD */
            self->get_info            = common_get_info;
            self->get_if_type         = qsfp_get_if_type;
            self->get_if_speed        = qsfp_get_if_speed;
            self->get_if_lane         = common_get_if_lane;
            self->get_curr_temp       = qsfp_get_transvr_temp;
            self->get_curr_vol        = qsfp_get_transvr_voltage;
            self->get_soft_rx_los     = qsfp_get_soft_rx_los;
            self->get_soft_tx_disable = qsfp_get_soft_tx_disable;
            self->get_soft_tx_fault   = qsfp_get_soft_tx_fault;
            self->get_auto_tx_disable = qsfp_get_auto_tx_disable;
            self->get_tx_bias         = qsfp_get_transvr_tx_bias;
            self->get_tx_power        = qsfp_get_transvr_tx_power;
            self->get_rx_power        = qsfp_get_transvr_rx_power;
            self->get_tx_eq           = qsfp_get_transvr_tx_eq;
            self->get_rx_am           = qsfp_get_transvr_rx_am;
            self->get_rx_em           = qsfp_get_transvr_rx_em;
            self->get_wavelength      = qsfp_get_wavelength;
            self->get_extphy_offset   = unsupported_get_func2;
            self->get_extphy_reg      = unsupported_get_func2;
            self->set_cdr             = qsfp_set_cdr;
            self->set_soft_rs0        = unsupported_set_func; /* TBD */
            self->set_soft_rs1        = unsupported_set_func; /* TBD */
            self->set_soft_tx_disable = qsfp_set_soft_tx_disable;
            self->set_auto_tx_disable = qsfp_set_auto_tx_disable;
            self->set_tx_eq           = qsfp_set_tx_eq;
            self->set_rx_am           = qsfp_set_rx_am;
            self->set_rx_em           = qsfp_set_rx_em;
            self->set_extphy_offset   = unsupported_set_func;
            self->set_extphy_reg      = unsupported_set_func;
            return 0;

        case TRANSVR_TYPE_FAKE:
            self->get_id              = fake_get_hex;
            self->get_ext_id          = fake_get_hex;
            self->get_connector       = fake_get_hex;
            self->get_vendor_name     = fake_get_str;
            self->get_vendor_pn       = fake_get_str;
            self->get_vendor_rev      = fake_get_str;
            self->get_vendor_sn       = fake_get_str;
            self->get_power_cls       = fake_get_int;
            self->get_br              = fake_get_hex;
            self->get_len_sm          = fake_get_int;
            self->get_len_smf         = fake_get_int;
            self->get_len_om1         = fake_get_int;
            self->get_len_om2         = fake_get_int;
            self->get_len_om3         = fake_get_int;
            self->get_len_om4         = fake_get_int;
            self->get_comp_rev        = fake_get_hex;
            self->get_comp_eth_1      = fake_get_hex;
            self->get_comp_eth_10     = fake_get_hex;
            self->get_comp_eth_10_40  = fake_get_hex;
            self->get_comp_extend     = fake_get_hex;
            self->get_cdr             = fake_get_hex;
            self->get_rate_id         = fake_get_hex;
            self->get_soft_rs0        = fake_get_binary;
            self->get_soft_rs1        = fake_get_binary;
            self->get_info            = fake_get_int;
            self->get_if_type         = fake_get_str;
            self->get_if_speed        = fake_get_str;
            self->get_if_lane         = fake_get_str;
            self->get_curr_temp       = fake_get_str;
            self->get_curr_vol        = fake_get_str;
            self->get_soft_rx_los     = fake_get_str;
            self->get_soft_tx_disable = fake_get_str;
            self->get_soft_tx_fault   = fake_get_str;
            self->get_auto_tx_disable = fake_get_str;
            self->get_tx_bias         = fake_get_str;
            self->get_tx_power        = fake_get_str;
            self->get_rx_power        = fake_get_str;
            self->get_tx_eq           = fake_get_str;
            self->get_rx_am           = fake_get_str;
            self->get_rx_em           = fake_get_str;
            self->get_wavelength      = fake_get_str;
            self->get_extphy_offset   = fake_get_str;
            self->get_extphy_reg      = fake_get_str;
            self->set_cdr             = fake_set_hex;
            self->set_soft_rs0        = fake_set_int;
            self->set_soft_rs1        = fake_set_int;
            self->set_soft_tx_disable = fake_set_int;
            self->set_auto_tx_disable = fake_set_int;
            self->set_tx_eq           = fake_set_int;
            self->set_rx_am           = fake_set_int;
            self->set_rx_em           = fake_set_int;
            self->set_extphy_offset   = fake_set_hex;
            self->set_extphy_reg      = fake_set_hex;
            return 0;

        default:
            break;
    }
    SWPS_WARN("%s: Detect non-defined type:%d\n", __func__, transvr_type);
    return ERR_TRANSVR_UNEXCPT;
}


static int
setup_transvr_private_cb(struct transvr_obj_s *self,
                         int transvr_type){
    switch (transvr_type){
        case TRANSVR_TYPE_SFP:
            self->init  = transvr_init_sfp;
            self->clean = common_transvr_clean;
            self->check = common_transvr_check;
            self->update_all = _sfp_update_attr_all;
            self->fsm_4_direct = common_fsm_4_direct_mode;
            self->fsm_4_polling = common_fsm_4_polling_mode;
            self->send_uevent = sfp_send_uevent;
            self->dump_all = sfp_transvr_dump;
            return 0;

        case TRANSVR_TYPE_QSFP:
        case TRANSVR_TYPE_QSFP_PLUS:
            self->init  = transvr_init_qsfp;
            self->clean = qsfp_transvr_clean;
            self->check = common_transvr_check;
            self->update_all = _qsfp_update_attr_all;
            self->fsm_4_direct = common_fsm_4_direct_mode;
            self->fsm_4_polling = common_fsm_4_polling_mode;
            self->send_uevent = qsfp_send_uevent;
            self->dump_all = qsfp_transvr_dump;
            return 0;

        case TRANSVR_TYPE_QSFP_28:
            self->init  = transvr_init_qsfp28;
            self->clean = qsfp_transvr_clean;
            self->check = common_transvr_check;
            self->update_all = _qsfp_update_attr_all;
            self->fsm_4_direct = common_fsm_4_direct_mode;
            self->fsm_4_polling = common_fsm_4_polling_mode;
            self->send_uevent = qsfp_send_uevent;
            self->dump_all = qsfp_transvr_dump;
            return 0;

        case TRANSVR_TYPE_FAKE:
            self->init  = transvr_init_fake;
            self->clean = fake_transvr_clean;
            self->check = fake_transvr_check;
            self->update_all = fake_transvr_update;
            self->fsm_4_direct = fake_fsm_4_direct_mode;
            self->fsm_4_polling = fake_fsm_4_polling_mode;
            self->send_uevent = fake_send_uevent;
            self->dump_all = fake_transvr_dump;
            return 0;

        default:
            break;
    }
    SWPS_WARN("%s: Detect non-defined type:%d\n", __func__, transvr_type);
    return ERR_TRANSVR_UNEXCPT;
}


static struct eeprom_map_s *
get_eeprom_map(int transvr_type){

    switch (transvr_type){
        case TRANSVR_TYPE_SFP:
            return &eeprom_map_sfp;
        case TRANSVR_TYPE_QSFP:
        case TRANSVR_TYPE_QSFP_PLUS:
            return &eeprom_map_qsfp;
        case TRANSVR_TYPE_QSFP_28:
            return &eeprom_map_qsfp28;

        default:
            break;
    }
    SWPS_WARN("%s: Detect non-defined type:%d\n", __func__, transvr_type);
    return NULL;
}


static int
setup_transvr_ssize_attr(char *swp_name,
                         struct transvr_obj_s *self,
                         struct eeprom_map_s  *map_p,
                         struct ioexp_obj_s   *ioexp_obj_p,
                         int ioexp_virt_offset,
                         int transvr_type,
                         int chipset_type,
                         int chan_id,
                         int run_mode){
    switch (run_mode){
        case TRANSVR_MODE_DIRECT:  /* Direct access device mode */
        case TRANSVR_MODE_POLLING: /* Polling mode, read from cache */
            self->mode = run_mode;
            break;
        default:
            SWPS_ERR("%s: non-defined run_mode:%d\n",
                    __func__, run_mode);
            self->mode = DEBUG_TRANSVR_INT_VAL;
            return -1;
    }
    self->eeprom_map_p      = map_p;
    self->ioexp_obj_p       = ioexp_obj_p;
    self->ioexp_virt_offset = ioexp_virt_offset;
    self->chan_id           = chan_id;
    self->layout            = transvr_type;
    self->type              = transvr_type;
    self->chipset_type      = chipset_type;
    self->state             = STATE_TRANSVR_NEW;
    self->info              = STATE_TRANSVR_NEW;
    self->auto_tx_disable   = VAL_TRANSVR_FUNCTION_DISABLE;
    strncpy(self->swp_name, swp_name, 32);
    mutex_init(&self->lock);
    return 0;
}


static int
setup_transvr_dsize_attr(struct transvr_obj_s *self){

    char *emsg = DEBUG_TRANSVR_STR_VAL;

    self->vendor_name = kzalloc((LEN_TRANSVR_M_STR * sizeof(char)), GFP_KERNEL);
    if (!self->vendor_name){
        emsg = "vendor_name";
        goto err_setup_d_attr;
    }
    self->vendor_pn = kzalloc((LEN_TRANSVR_M_STR * sizeof(char)), GFP_KERNEL);
    if (!self->vendor_pn){
        emsg = "vendor_pn";
        goto err_setup_d_attr;
    }
    self->vendor_rev = kzalloc((LEN_TRANSVR_M_STR * sizeof(char)), GFP_KERNEL);
    if (!self->vendor_rev){
        emsg = "vendor_rev";
        goto err_setup_d_attr;
    }
    self->vendor_sn = kzalloc((LEN_TRANSVR_M_STR * sizeof(char)), GFP_KERNEL);
    if (!self->vendor_sn){
        emsg = "vendor_sn";
        goto err_setup_d_attr;
    }
    self->worker_p = NULL;
    return 0;

err_setup_d_attr:
    SWPS_ERR("%s: %s kzalloc fail!", __func__, emsg);
    return ERR_TRANSVR_UNEXCPT;
}


static int
setup_i2c_client(struct transvr_obj_s *self){

    struct i2c_adapter *adap  = NULL;
    struct i2c_client *client = NULL;
    char err_msg[64] = DEBUG_TRANSVR_STR_VAL;

    adap = i2c_get_adapter(self->chan_id);
    if(!adap){
        snprintf(err_msg, sizeof(err_msg),
                "can not get adap:%d", self->chan_id);
        goto err_setup_i2c_client;
    }
    client = kzalloc(sizeof(*client), GFP_KERNEL);
    if (!client){
        snprintf(err_msg, sizeof(err_msg),
                "can not kzalloc client:%d", self->chan_id);
        goto err_setup_i2c_client;
    }
    client->adapter = adap;
    self->i2c_client_p = client;
    self->i2c_client_p->addr = VAL_TRANSVR_COMID_ARREESS;
    return 0;

err_setup_i2c_client:
    SWPS_ERR("%s: %s\n", __func__, err_msg);
    return ERR_TRANSVR_UNEXCPT;
}


struct transvr_obj_s *
create_transvr_obj(char *swp_name,
                   int chan_id,
                   struct ioexp_obj_s *ioexp_obj_p,
                   int ioexp_virt_offset,
                   int transvr_type,
                   int chipset_type,
                   int run_mode){

    struct transvr_obj_s *result_p;
    struct eeprom_map_s  *map_p;
    char err_msg[64] = DEBUG_TRANSVR_STR_VAL;

    /* Allocate transceiver object */
    map_p = get_eeprom_map(transvr_type);
    if (!map_p){
        snprintf(err_msg, sizeof(err_msg),
                "Invalid transvr_type:%d", transvr_type);
        goto err_create_transvr_fail;
    }
    result_p = kzalloc(sizeof(*result_p), GFP_KERNEL);
    if (!result_p){
        snprintf(err_msg, sizeof(err_msg), "kzalloc fail");
        goto err_create_transvr_fail;
    }
    /* Prepare static size attributes */
    if (setup_transvr_ssize_attr(swp_name,
                                 result_p,
                                 map_p,
                                 ioexp_obj_p,
                                 ioexp_virt_offset,
                                 transvr_type,
                                 chipset_type,
                                 chan_id,
                                 run_mode) < 0){
        goto err_create_transvr_sattr_fail;
    }
    /* Prepare dynamic size attributes */
    if (setup_transvr_dsize_attr(result_p) < 0){
        goto err_create_transvr_dattr_fail;
    }
    /* Prepare call back functions of object */
    if (setup_transvr_public_cb(result_p, transvr_type) < 0){
        goto err_create_transvr_dattr_fail;
    }
    /* Prepare call back functions of object */
    if (setup_transvr_private_cb(result_p, transvr_type) < 0){
        goto err_create_transvr_dattr_fail;
    }
    /* Prepare i2c client object */
    if (setup_i2c_client(result_p) < 0){
        goto err_create_transvr_dattr_fail;
    }
    return result_p;

err_create_transvr_dattr_fail:
    kfree(result_p->vendor_sn);
    kfree(result_p->vendor_rev);
    kfree(result_p->vendor_pn);
    kfree(result_p->vendor_name);
err_create_transvr_sattr_fail:
    kfree(result_p);
err_create_transvr_fail:
    SWPS_ERR("%s: %s <chan>:%d <voff>:%d <type>:%d\n",
            __func__, err_msg, chan_id, ioexp_virt_offset, transvr_type);
    return NULL;
}
EXPORT_SYMBOL(create_transvr_obj);


static int
_reload_transvr_obj(struct transvr_obj_s *self,
                    int new_type){

    struct eeprom_map_s *new_map_p;
    struct eeprom_map_s *old_map_p = self->eeprom_map_p;
    struct i2c_client   *old_i2c_p = self->i2c_client_p;
    int old_type = self->type;

    /* Change state to STATE_TRANSVR_INIT */
    self->state = STATE_TRANSVR_INIT;
    self->type  = new_type;
    /* Replace EEPROME map */
    new_map_p = get_eeprom_map(new_type);
    if (!new_map_p){
        goto err_private_reload_func_1;
    }
    self->eeprom_map_p = new_map_p;
    /* Reload i2c client */
    if (setup_i2c_client(self) < 0){
        goto err_private_reload_func_2;
    }
    /* Replace call back functions */
    if (setup_transvr_public_cb(self, new_type) < 0){
        goto err_private_reload_func_3;
    }
    if (setup_transvr_private_cb(self, new_type) < 0){
        goto err_private_reload_func_3;
    }
    kfree(old_i2c_p);
    return 0;

err_private_reload_func_3:
    SWPS_INFO("%s: init() fail!\n", __func__);
    kfree(old_i2c_p);
    self->state = STATE_TRANSVR_UNEXCEPTED;
    self->type  = TRANSVR_TYPE_ERROR;
    return -2;

err_private_reload_func_2:
    self->eeprom_map_p = old_map_p;
    self->i2c_client_p = old_i2c_p;
err_private_reload_func_1:
    self->state = STATE_TRANSVR_UNEXCEPTED;
    self->type  = old_type;
    SWPS_INFO("%s fail! <type>:0x%02x\n", __func__, new_type);
    return -1;
}


static int
reload_transvr_obj(struct transvr_obj_s *self,
                   int new_type){

    int result_val = ERR_TRANSVR_UNEXCPT;

    /* Reload phase */
    result_val = _reload_transvr_obj(self, new_type);
    if (result_val < 0){
        SWPS_INFO("%s: reload phase fail! <err>:%d\n",
                  __func__, result_val);
        return EVENT_TRANSVR_RELOAD_FAIL;
    }
    /* Initial phase */
    result_val = _transvr_init_handler(self);
    if (result_val < 0){
        SWPS_INFO("%s: initial phase fail! <err>:%d\n",
                  __func__, result_val);
    }
    return result_val;
}


int
isolate_transvr_obj(struct transvr_obj_s *self) {

    self->state = STATE_TRANSVR_ISOLATED;
    SWPS_INFO("%s: %s be isolated\n", __func__, self->swp_name);
    return 0;
}
EXPORT_SYMBOL(isolate_transvr_obj);


int
resync_channel_tier_2(struct transvr_obj_s *self) {

    int val = TRANSVR_TYPE_ERROR;

    if (self->state == STATE_TRANSVR_ISOLATED) {
        return 0;
    }
    self->i2c_client_p->addr = VAL_TRANSVR_COMID_ARREESS;
    val = i2c_smbus_read_byte_data(self->i2c_client_p,
                                   VAL_TRANSVR_COMID_OFFSET);
    if (val < 0) {
        return -1;
    }
    return 0;
}
EXPORT_SYMBOL(resync_channel_tier_2);

/* For build single module using (Ex: ONL platform) */
MODULE_LICENSE("GPL");


/* -----------------------------------------
 *   ToDo List
 * -----------------------------------------
 * 1. _sfp_detect_class_by_feature()
 *    => Need check ACC use case.
 * 2. _sfp_detect_class_by_1g_ethernet()
 *    => Need check 0.1G use case.
 * 3. Loopback transceiver use case.
 *    => Less much data
 * 4. _qsfp_detect_class_by_extend_comp()
 *    => Verify 100G CWDM4
 *    => Verify Obsolete (assigned before 100G CWDM4 MSA required FEC)
 *    => Verify 100G CLR4
 *    => Verify 100GE-DWDM2
 *    => Verify 40G PSM4 Parallel SMF
 *    => Verify 100G ACC (Active Copper Cable) or 25GAUI C2M ACC.
 *    => Verify 100G ACC or 25GAUI C2M ACC.
 *    => Verify 25GBASE-LR
 *    => Verify 40G Active Cable (XLPPI)
 */







