| /****************************************************************************** |
| * |
| * Copyright(c) 2007 - 2017 Realtek Corporation. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of version 2 of the GNU General Public License as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| *****************************************************************************/ |
| |
| #include <drv_types.h> |
| |
| #ifdef CONFIG_IOL |
| struct xmit_frame *rtw_IOL_accquire_xmit_frame(ADAPTER *adapter) |
| { |
| struct xmit_frame *xmit_frame; |
| struct xmit_buf *xmitbuf; |
| struct pkt_attrib *pattrib; |
| struct xmit_priv *pxmitpriv = &(adapter->xmitpriv); |
| |
| #if 1 |
| xmit_frame = rtw_alloc_xmitframe(pxmitpriv); |
| if (xmit_frame == NULL) { |
| RTW_INFO("%s rtw_alloc_xmitframe return null\n", __FUNCTION__); |
| goto exit; |
| } |
| |
| xmitbuf = rtw_alloc_xmitbuf(pxmitpriv); |
| if (xmitbuf == NULL) { |
| RTW_INFO("%s rtw_alloc_xmitbuf return null\n", __FUNCTION__); |
| rtw_free_xmitframe(pxmitpriv, xmit_frame); |
| xmit_frame = NULL; |
| goto exit; |
| } |
| |
| xmit_frame->frame_tag = MGNT_FRAMETAG; |
| xmit_frame->pxmitbuf = xmitbuf; |
| xmit_frame->buf_addr = xmitbuf->pbuf; |
| xmitbuf->priv_data = xmit_frame; |
| |
| pattrib = &xmit_frame->attrib; |
| update_mgntframe_attrib(adapter, pattrib); |
| pattrib->qsel = QSLT_BEACON;/* Beacon */ |
| pattrib->subtype = WIFI_BEACON; |
| pattrib->pktlen = pattrib->last_txcmdsz = 0; |
| |
| #else |
| xmit_frame = alloc_mgtxmitframe(pxmitpriv); |
| if (xmit_frame == NULL) |
| RTW_INFO("%s alloc_mgtxmitframe return null\n", __FUNCTION__); |
| else { |
| pattrib = &xmit_frame->attrib; |
| update_mgntframe_attrib(adapter, pattrib); |
| pattrib->qsel = QSLT_BEACON; |
| pattrib->pktlen = pattrib->last_txcmdsz = 0; |
| } |
| #endif |
| |
| exit: |
| return xmit_frame; |
| } |
| |
| |
| int rtw_IOL_append_cmds(struct xmit_frame *xmit_frame, u8 *IOL_cmds, u32 cmd_len) |
| { |
| struct pkt_attrib *pattrib = &xmit_frame->attrib; |
| u16 buf_offset; |
| u32 ori_len; |
| |
| buf_offset = TXDESC_OFFSET; |
| ori_len = buf_offset + pattrib->pktlen; |
| |
| /* check if the io_buf can accommodate new cmds */ |
| if (ori_len + cmd_len + 8 > MAX_XMITBUF_SZ) { |
| RTW_INFO("%s %u is large than MAX_XMITBUF_SZ:%u, can't accommodate new cmds\n", __FUNCTION__ |
| , ori_len + cmd_len + 8, MAX_XMITBUF_SZ); |
| return _FAIL; |
| } |
| |
| _rtw_memcpy(xmit_frame->buf_addr + buf_offset + pattrib->pktlen, IOL_cmds, cmd_len); |
| pattrib->pktlen += cmd_len; |
| pattrib->last_txcmdsz += cmd_len; |
| |
| /* RTW_INFO("%s ori:%u + cmd_len:%u = %u\n", __FUNCTION__, ori_len, cmd_len, buf_offset+pattrib->pktlen); */ |
| |
| return _SUCCESS; |
| } |
| |
| bool rtw_IOL_applied(ADAPTER *adapter) |
| { |
| if (1 == adapter->registrypriv.fw_iol) |
| return _TRUE; |
| |
| #ifdef CONFIG_USB_HCI |
| if ((2 == adapter->registrypriv.fw_iol) && (IS_FULL_SPEED_USB(adapter))) |
| return _TRUE; |
| #endif |
| |
| return _FALSE; |
| } |
| |
| int rtw_IOL_exec_cmds_sync(ADAPTER *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt) |
| { |
| return rtw_hal_iol_cmd(adapter, xmit_frame, max_wating_ms, bndy_cnt); |
| } |
| |
| #ifdef CONFIG_IOL_NEW_GENERATION |
| int rtw_IOL_append_LLT_cmd(struct xmit_frame *xmit_frame, u8 page_boundary) |
| { |
| return _SUCCESS; |
| } |
| int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, u8 mask) |
| { |
| struct ioreg_cfg cmd = {8, IOREG_CMD_WB_REG, 0x0, 0x0, 0x0}; |
| |
| /* RTW_PUT_LE16((u8*)&cmd.address, addr); */ |
| /* RTW_PUT_LE32((u8*)&cmd.value, (u32)value); */ |
| cmd.address = cpu_to_le16(addr); |
| cmd.data = cpu_to_le32(value); |
| |
| if (mask != 0xFF) { |
| cmd.length = 12; |
| /* RTW_PUT_LE32((u8*)&cmd.mask, (u32)mask); */ |
| cmd.mask = cpu_to_le32(mask); |
| } |
| |
| /* RTW_INFO("%s addr:0x%04x,value:0x%08x,mask:0x%08x\n", __FUNCTION__, addr,value,mask); */ |
| |
| return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); |
| |
| } |
| int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, u16 mask) |
| { |
| struct ioreg_cfg cmd = {8, IOREG_CMD_WW_REG, 0x0, 0x0, 0x0}; |
| |
| /* RTW_PUT_LE16((u8*)&cmd.address, addr); */ |
| /* RTW_PUT_LE32((u8*)&cmd.value, (u32)value); */ |
| cmd.address = cpu_to_le16(addr); |
| cmd.data = cpu_to_le32(value); |
| |
| if (mask != 0xFFFF) { |
| cmd.length = 12; |
| /* RTW_PUT_LE32((u8*)&cmd.mask, (u32)mask); */ |
| cmd.mask = cpu_to_le32(mask); |
| } |
| |
| /* RTW_INFO("%s addr:0x%04x,value:0x%08x,mask:0x%08x\n", __FUNCTION__, addr,value,mask); */ |
| |
| return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); |
| |
| } |
| int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, u32 mask) |
| { |
| struct ioreg_cfg cmd = {8, IOREG_CMD_WD_REG, 0x0, 0x0, 0x0}; |
| |
| /* RTW_PUT_LE16((u8*)&cmd.address, addr); */ |
| /* RTW_PUT_LE32((u8*)&cmd.value, (u32)value); */ |
| cmd.address = cpu_to_le16(addr); |
| cmd.data = cpu_to_le32(value); |
| |
| if (mask != 0xFFFFFFFF) { |
| cmd.length = 12; |
| /* RTW_PUT_LE32((u8*)&cmd.mask, (u32)mask); */ |
| cmd.mask = cpu_to_le32(mask); |
| } |
| |
| /* RTW_INFO("%s addr:0x%04x,value:0x%08x,mask:0x%08x\n", __FU2NCTION__, addr,value,mask); */ |
| |
| return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); |
| |
| } |
| |
| int _rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path, u16 addr, u32 value, u32 mask) |
| { |
| struct ioreg_cfg cmd = {8, IOREG_CMD_W_RF, 0x0, 0x0, 0x0}; |
| |
| /* RTW_PUT_LE16((u8*)&cmd.address, addr); */ |
| /* RTW_PUT_LE32((u8*)&cmd.value, (u32)value); */ |
| cmd.address = (rf_path << 8) | ((addr) & 0xFF); |
| cmd.data = cpu_to_le32(value); |
| |
| if (mask != 0x000FFFFF) { |
| cmd.length = 12; |
| /* RTW_PUT_LE32((u8*)&cmd.mask, (u32)mask); */ |
| cmd.mask = cpu_to_le32(mask); |
| } |
| |
| /* RTW_INFO("%s rf_path:0x%02x addr:0x%04x,value:0x%08x,mask:0x%08x\n", __FU2NCTION__,rf_path, addr,value,mask); */ |
| |
| return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); |
| |
| } |
| |
| |
| |
| int rtw_IOL_append_DELAY_US_cmd(struct xmit_frame *xmit_frame, u16 us) |
| { |
| struct ioreg_cfg cmd = {4, IOREG_CMD_DELAY_US, 0x0, 0x0, 0x0}; |
| /* RTW_PUT_LE16((u8*)&cmd.address, us); */ |
| cmd.address = cpu_to_le16(us); |
| |
| /* RTW_INFO("%s %u\n", __FUNCTION__, us); */ |
| return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4); |
| } |
| |
| int rtw_IOL_append_DELAY_MS_cmd(struct xmit_frame *xmit_frame, u16 ms) |
| { |
| struct ioreg_cfg cmd = {4, IOREG_CMD_DELAY_US, 0x0, 0x0, 0x0}; |
| |
| /* RTW_PUT_LE16((u8*)&cmd.address, ms); */ |
| cmd.address = cpu_to_le16(ms); |
| |
| /* RTW_INFO("%s %u\n", __FUNCTION__, ms); */ |
| return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4); |
| } |
| int rtw_IOL_append_END_cmd(struct xmit_frame *xmit_frame) |
| { |
| struct ioreg_cfg cmd = {4, IOREG_CMD_END, 0xFFFF, 0xFF, 0x0}; |
| return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4); |
| |
| } |
| |
| u8 rtw_IOL_cmd_boundary_handle(struct xmit_frame *pxmit_frame) |
| { |
| u8 is_cmd_bndy = _FALSE; |
| if (((pxmit_frame->attrib.pktlen + 32) % 256) + 8 >= 256) { |
| rtw_IOL_append_END_cmd(pxmit_frame); |
| pxmit_frame->attrib.pktlen = ((((pxmit_frame->attrib.pktlen + 32) / 256) + 1) * 256); |
| |
| /* printk("==> %s, pktlen(%d)\n",__FUNCTION__,pxmit_frame->attrib.pktlen); */ |
| pxmit_frame->attrib.last_txcmdsz = pxmit_frame->attrib.pktlen; |
| is_cmd_bndy = _TRUE; |
| } |
| return is_cmd_bndy; |
| } |
| |
| void rtw_IOL_cmd_buf_dump(ADAPTER *Adapter, int buf_len, u8 *pbuf) |
| { |
| int i; |
| int j = 1; |
| |
| printk("###### %s ######\n", __FUNCTION__); |
| for (i = 0; i < buf_len; i++) { |
| printk("%02x-", *(pbuf + i)); |
| |
| if (j % 32 == 0) |
| printk("\n"); |
| j++; |
| } |
| printk("\n"); |
| printk("============= ioreg_cmd len = %d ===============\n", buf_len); |
| } |
| |
| |
| #else /* CONFIG_IOL_NEW_GENERATION */ |
| int rtw_IOL_append_LLT_cmd(struct xmit_frame *xmit_frame, u8 page_boundary) |
| { |
| IOL_CMD cmd = {0x0, IOL_CMD_LLT, 0x0, 0x0}; |
| |
| RTW_PUT_BE32((u8 *)&cmd.value, (u32)page_boundary); |
| |
| return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 8); |
| } |
| |
| int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value) |
| { |
| IOL_CMD cmd = {0x0, IOL_CMD_WB_REG, 0x0, 0x0}; |
| |
| RTW_PUT_BE16((u8 *)&cmd.address, (u16)addr); |
| RTW_PUT_BE32((u8 *)&cmd.value, (u32)value); |
| |
| return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 8); |
| } |
| |
| int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value) |
| { |
| IOL_CMD cmd = {0x0, IOL_CMD_WW_REG, 0x0, 0x0}; |
| |
| RTW_PUT_BE16((u8 *)&cmd.address, (u16)addr); |
| RTW_PUT_BE32((u8 *)&cmd.value, (u32)value); |
| |
| return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 8); |
| } |
| |
| int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value) |
| { |
| IOL_CMD cmd = {0x0, IOL_CMD_WD_REG, 0x0, 0x0}; |
| u8 *pos = (u8 *)&cmd; |
| |
| RTW_PUT_BE16((u8 *)&cmd.address, (u16)addr); |
| RTW_PUT_BE32((u8 *)&cmd.value, (u32)value); |
| |
| return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 8); |
| } |
| |
| #ifdef DBG_IO |
| int dbg_rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, const char *caller, const int line) |
| { |
| if (match_write_sniff_ranges(addr, 1)) |
| RTW_INFO("DBG_IO %s:%d IOL_WB(0x%04x, 0x%02x)\n", caller, line, addr, value); |
| |
| return _rtw_IOL_append_WB_cmd(xmit_frame, addr, value); |
| } |
| |
| int dbg_rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, const char *caller, const int line) |
| { |
| if (match_write_sniff_ranges(addr, 2)) |
| RTW_INFO("DBG_IO %s:%d IOL_WW(0x%04x, 0x%04x)\n", caller, line, addr, value); |
| |
| return _rtw_IOL_append_WW_cmd(xmit_frame, addr, value); |
| } |
| |
| int dbg_rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, const char *caller, const int line) |
| { |
| if (match_write_sniff_ranges(addr, 4)) |
| RTW_INFO("DBG_IO %s:%d IOL_WD(0x%04x, 0x%08x)\n", caller, line, addr, value); |
| |
| return _rtw_IOL_append_WD_cmd(xmit_frame, addr, value); |
| } |
| #endif |
| |
| int rtw_IOL_append_DELAY_US_cmd(struct xmit_frame *xmit_frame, u16 us) |
| { |
| IOL_CMD cmd = {0x0, IOL_CMD_DELAY_US, 0x0, 0x0}; |
| |
| RTW_PUT_BE32((u8 *)&cmd.value, (u32)us); |
| |
| /* RTW_INFO("%s %u\n", __FUNCTION__, us); */ |
| |
| return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 8); |
| } |
| |
| int rtw_IOL_append_DELAY_MS_cmd(struct xmit_frame *xmit_frame, u16 ms) |
| { |
| IOL_CMD cmd = {0x0, IOL_CMD_DELAY_MS, 0x0, 0x0}; |
| |
| RTW_PUT_BE32((u8 *)&cmd.value, (u32)ms); |
| |
| /* RTW_INFO("%s %u\n", __FUNCTION__, ms); */ |
| |
| return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 8); |
| } |
| |
| int rtw_IOL_append_END_cmd(struct xmit_frame *xmit_frame) |
| { |
| IOL_CMD end_cmd = {0x0, IOL_CMD_END, 0x0, 0x0}; |
| |
| |
| return rtw_IOL_append_cmds(xmit_frame, (u8 *)&end_cmd, 8); |
| |
| } |
| |
| int rtw_IOL_exec_cmd_array_sync(PADAPTER adapter, u8 *IOL_cmds, u32 cmd_num, u32 max_wating_ms) |
| { |
| struct xmit_frame *xmit_frame; |
| |
| xmit_frame = rtw_IOL_accquire_xmit_frame(adapter); |
| if (xmit_frame == NULL) |
| return _FAIL; |
| |
| if (rtw_IOL_append_cmds(xmit_frame, IOL_cmds, cmd_num << 3) == _FAIL) |
| return _FAIL; |
| |
| return rtw_IOL_exec_cmds_sync(adapter, xmit_frame, max_wating_ms, 0); |
| } |
| |
| int rtw_IOL_exec_empty_cmds_sync(ADAPTER *adapter, u32 max_wating_ms) |
| { |
| IOL_CMD end_cmd = {0x0, IOL_CMD_END, 0x0, 0x0}; |
| return rtw_IOL_exec_cmd_array_sync(adapter, (u8 *)&end_cmd, 1, max_wating_ms); |
| } |
| #endif /* CONFIG_IOL_NEW_GENERATION */ |
| |
| |
| |
| |
| #endif /* CONFIG_IOL */ |