LCOV - code coverage report
Current view: top level - dev/ic - acx111.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 103 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: acx111.c,v 1.23 2015/11/24 13:45:06 mpi Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : /*
      20             :  * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
      21             :  *
      22             :  * This code is derived from software contributed to The DragonFly Project
      23             :  * by Sepherosa Ziehau <sepherosa@gmail.com>
      24             :  *
      25             :  * Redistribution and use in source and binary forms, with or without
      26             :  * modification, are permitted provided that the following conditions
      27             :  * are met:
      28             :  *
      29             :  * 1. Redistributions of source code must retain the above copyright
      30             :  *    notice, this list of conditions and the following disclaimer.
      31             :  * 2. Redistributions in binary form must reproduce the above copyright
      32             :  *    notice, this list of conditions and the following disclaimer in
      33             :  *    the documentation and/or other materials provided with the
      34             :  *    distribution.
      35             :  * 3. Neither the name of The DragonFly Project nor the names of its
      36             :  *    contributors may be used to endorse or promote products derived
      37             :  *    from this software without specific, prior written permission.
      38             :  *
      39             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      40             :  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      41             :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
      42             :  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
      43             :  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
      44             :  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
      45             :  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
      46             :  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
      47             :  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
      48             :  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
      49             :  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      50             :  * SUCH DAMAGE.
      51             :  */
      52             : 
      53             : #include "bpfilter.h"
      54             : 
      55             : #include <sys/param.h>
      56             : #include <sys/endian.h>
      57             : #include <sys/socket.h>
      58             : #include <sys/systm.h>
      59             : #include <sys/device.h>
      60             : 
      61             : #include <machine/bus.h>
      62             : 
      63             : #include <net/if.h>
      64             : #include <net/if_media.h>
      65             : 
      66             : #include <netinet/in.h>
      67             : #include <netinet/if_ether.h>
      68             : 
      69             : #include <net80211/ieee80211_var.h>
      70             : #include <net80211/ieee80211_amrr.h>
      71             : #include <net80211/ieee80211_radiotap.h>
      72             : 
      73             : #include <dev/pci/pcireg.h>
      74             : 
      75             : #include <dev/ic/acxvar.h>
      76             : #include <dev/ic/acxreg.h>
      77             : 
      78             : #define ACX111_CONF_MEM         0x0003
      79             : #define ACX111_CONF_MEMINFO     0x0005
      80             : 
      81             : #define ACX111_INTR_ENABLE      (ACXRV_INTR_TX_FINI | ACXRV_INTR_RX_FINI)
      82             : /*
      83             :  * XXX do we really care about fowlling interrupts?
      84             :  *
      85             :  * ACXRV_INTR_IV_ICV_FAILURE | ACXRV_INTR_INFO |
      86             :  * ACXRV_INTR_SCAN_FINI | ACXRV_INTR_FCS_THRESHOLD
      87             :  */
      88             : 
      89             : #define ACX111_INTR_DISABLE     (uint16_t)~(ACXRV_INTR_CMD_FINI)
      90             : 
      91             : #define ACX111_RATE_2           0x0001
      92             : #define ACX111_RATE_4           0x0002
      93             : #define ACX111_RATE_11          0x0004
      94             : #define ACX111_RATE_12          0x0008
      95             : #define ACX111_RATE_18          0x0010
      96             : #define ACX111_RATE_22          0x0020
      97             : #define ACX111_RATE_24          0x0040
      98             : #define ACX111_RATE_36          0x0080
      99             : #define ACX111_RATE_44          0x0100
     100             : #define ACX111_RATE_48          0x0200
     101             : #define ACX111_RATE_72          0x0400
     102             : #define ACX111_RATE_96          0x0800
     103             : #define ACX111_RATE_108         0x1000
     104             : 
     105             : /* XXX skip ACX111_RATE_44 */
     106             : #define ACX111_RATE_ALL         0x1eff
     107             : 
     108             : #define ACX111_TXPOWER          15
     109             : #define ACX111_GPIO_POWER_LED   0x0040
     110             : #define ACX111_EE_EADDR_OFS     0x21
     111             : 
     112             : #define ACX111_FW_TXDESC_SIZE   (sizeof(struct acx_fw_txdesc) + 4)
     113             : 
     114             : #if ACX111_TXPOWER <= 12
     115             : #define ACX111_TXPOWER_VAL      1
     116             : #else
     117             : #define ACX111_TXPOWER_VAL      2
     118             : #endif
     119             : 
     120             : int     acx111_init(struct acx_softc *);
     121             : int     acx111_init_memory(struct acx_softc *);
     122             : void    acx111_init_fw_txring(struct acx_softc *, uint32_t);
     123             : int     acx111_write_config(struct acx_softc *, struct acx_config *);
     124             : void    acx111_set_fw_txdesc_rate(struct acx_softc *,
     125             :             struct acx_txbuf *, int);
     126             : void    acx111_set_bss_join_param(struct acx_softc *, void *, int);
     127             : 
     128             : /*
     129             :  * NOTE:
     130             :  * Following structs' fields are little endian
     131             :  */
     132             : struct acx111_bss_join {
     133             :         uint16_t        basic_rates;
     134             :         uint8_t         dtim_intvl;
     135             : } __packed;
     136             : 
     137             : struct acx111_conf_mem {
     138             :         struct acx_conf confcom;
     139             : 
     140             :         uint16_t        sta_max;        /* max num of sta, ACX111_STA_MAX */
     141             :         uint16_t        memblk_size;    /* mem block size */
     142             :         uint8_t         rx_memblk_perc; /* percent of RX mem block, unit: 5% */
     143             :         uint8_t         fw_rxring_num;  /* num of RX ring */
     144             :         uint8_t         fw_txring_num;  /* num of TX ring */
     145             :         uint8_t         opt;            /* see ACX111_MEMOPT_ */
     146             :         uint8_t         xfer_perc;      /* frag/xfer proportion, unit: 5% */
     147             :         uint16_t        reserved0;
     148             :         uint8_t         reserved1;
     149             : 
     150             :         uint8_t         fw_rxdesc_num;  /* num of fw rx desc */
     151             :         uint8_t         fw_rxring_reserved1;
     152             :         uint8_t         fw_rxring_type; /* see ACX111_RXRING_TYPE_ */
     153             :         uint8_t         fw_rxring_prio; /* see ACX111_RXRING_PRIO_ */
     154             : 
     155             :         uint32_t        h_rxring_paddr; /* host rx desc start phyaddr */
     156             : 
     157             :         uint8_t         fw_txdesc_num;  /* num of fw tx desc */
     158             :         uint8_t         fw_txring_reserved1;
     159             :         uint8_t         fw_txring_reserved2;
     160             :         uint8_t         fw_txring_attr; /* see ACX111_TXRING_ATTR_ */
     161             : } __packed;
     162             : 
     163             : #define ACX111_STA_MAX                  32
     164             : #define ACX111_RX_MEMBLK_PERCENT        10      /* 50% */
     165             : #define ACX111_XFER_PERCENT             15      /* 75% */
     166             : #define ACX111_RXRING_TYPE_DEFAULT      7
     167             : #define ACX111_RXRING_PRIO_DEFAULT      0
     168             : #define ACX111_TXRING_ATTR_DEFAULT      0
     169             : #define ACX111_MEMOPT_DEFAULT           0
     170             : 
     171             : struct acx111_conf_meminfo {
     172             :         struct acx_conf confcom;
     173             :         uint32_t        tx_memblk_addr; /* start addr of tx mem blocks */
     174             :         uint32_t        rx_memblk_addr; /* start addr of rx mem blocks */
     175             :         uint32_t        fw_rxring_start; /* start phyaddr of fw rx ring */
     176             :         uint32_t        reserved0;
     177             :         uint32_t        fw_txring_start; /* start phyaddr of fw tx ring */
     178             :         uint8_t         fw_txring_attr; /* XXX see ACX111_TXRING_ATTR_ */
     179             :         uint16_t        reserved1;
     180             :         uint8_t         reserved2;
     181             : } __packed;
     182             : 
     183             : struct acx111_conf_txpower {
     184             :         struct acx_conf confcom;
     185             :         uint8_t         txpower;
     186             : } __packed;
     187             : 
     188             : struct acx111_conf_option {
     189             :         struct acx_conf confcom;
     190             :         uint32_t        feature;
     191             :         uint32_t        dataflow;       /* see ACX111_DF_ */
     192             : } __packed;
     193             : 
     194             : #define ACX111_DF_NO_RXDECRYPT  0x00000080
     195             : #define ACX111_DF_NO_TXENCRYPT  0x00000001
     196             : 
     197             : struct acx111_wepkey {
     198             :         uint8_t         mac_addr[IEEE80211_ADDR_LEN];
     199             :         uint16_t        action;         /* see ACX111_WEPKEY_ACT_ */
     200             :         uint16_t        reserved;
     201             :         uint8_t         key_len;
     202             :         uint8_t         key_type;       /* see ACX111_WEPKEY_TYPE_ */
     203             :         uint8_t         index;          /* XXX ?? */
     204             :         uint8_t         key_idx;
     205             :         uint8_t         counter[6];
     206             : #define ACX111_WEPKEY_LEN       32
     207             :         uint8_t         key[ACX111_WEPKEY_LEN];
     208             : } __packed;
     209             : 
     210             : #define ACX111_WEPKEY_ACT_ADD           1
     211             : #define ACX111_WEPKEY_TYPE_DEFAULT      0
     212             : 
     213             : static const uint16_t acx111_reg[ACXREG_MAX] = {
     214             :         ACXREG(SOFT_RESET,              0x0000),
     215             : 
     216             :         ACXREG(FWMEM_ADDR,              0x0014),
     217             :         ACXREG(FWMEM_DATA,              0x0018),
     218             :         ACXREG(FWMEM_CTRL,              0x001c),
     219             :         ACXREG(FWMEM_START,             0x0020),
     220             : 
     221             :         ACXREG(EVENT_MASK,              0x0034),
     222             : 
     223             :         ACXREG(INTR_TRIG,               0x00b4),
     224             :         ACXREG(INTR_MASK,               0x00d4),
     225             :         ACXREG(INTR_STATUS,             0x00f0),
     226             :         ACXREG(INTR_STATUS_CLR,         0x00e4),
     227             :         ACXREG(INTR_ACK,                0x00e8),
     228             : 
     229             :         ACXREG(HINTR_TRIG,              0x00ec),
     230             :         ACXREG(RADIO_ENABLE,            0x01d0),
     231             : 
     232             :         ACXREG(EEPROM_INIT,             0x0100),
     233             :         ACXREG(EEPROM_CTRL,             0x0338),
     234             :         ACXREG(EEPROM_ADDR,             0x033c),
     235             :         ACXREG(EEPROM_DATA,             0x0340),
     236             :         ACXREG(EEPROM_CONF,             0x0344),
     237             :         ACXREG(EEPROM_INFO,             0x0390),
     238             : 
     239             :         ACXREG(PHY_ADDR,                0x0350),
     240             :         ACXREG(PHY_DATA,                0x0354),
     241             :         ACXREG(PHY_CTRL,                0x0358),
     242             : 
     243             :         ACXREG(GPIO_OUT_ENABLE,         0x0374),
     244             :         ACXREG(GPIO_OUT,                0x037c),
     245             : 
     246             :         ACXREG(CMD_REG_OFFSET,          0x0388),
     247             :         ACXREG(INFO_REG_OFFSET,         0x038c),
     248             : 
     249             :         ACXREG(RESET_SENSE,             0x0104),
     250             :         ACXREG(ECPU_CTRL,               0x0108)
     251             : };
     252             : 
     253             : /* XXX */
     254             : static uint16_t acx111_rate_map[109] = {
     255             :         ACX111_RATE_2,
     256             :         ACX111_RATE_4,
     257             :         ACX111_RATE_11,
     258             :         ACX111_RATE_22,
     259             :         ACX111_RATE_12,
     260             :         ACX111_RATE_18,
     261             :         ACX111_RATE_24,
     262             :         ACX111_RATE_36,
     263             :         ACX111_RATE_48,
     264             :         ACX111_RATE_72,
     265             :         ACX111_RATE_96,
     266             :         ACX111_RATE_108
     267             : };
     268             : 
     269             : void
     270           0 : acx111_set_param(struct acx_softc *sc)
     271             : {
     272           0 :         sc->chip_mem1_rid = PCIR_BAR(0);
     273           0 :         sc->chip_mem2_rid = PCIR_BAR(1);
     274           0 :         sc->chip_ioreg = acx111_reg;
     275           0 :         sc->chip_intr_enable = ACX111_INTR_ENABLE;
     276             : #ifndef IEEE80211_STA_ONLY
     277           0 :         sc->chip_intr_enable |= ACXRV_INTR_DTIM;
     278             : #endif
     279           0 :         sc->chip_intr_disable = ACX111_INTR_DISABLE;
     280           0 :         sc->chip_gpio_pled = ACX111_GPIO_POWER_LED;
     281           0 :         sc->chip_ee_eaddr_ofs = ACX111_EE_EADDR_OFS;
     282             : 
     283           0 :         sc->chip_phymode = IEEE80211_MODE_11G;
     284           0 :         sc->chip_chan_flags = IEEE80211_CHAN_CCK |
     285             :             IEEE80211_CHAN_OFDM |
     286             :             IEEE80211_CHAN_DYN |
     287             :             IEEE80211_CHAN_2GHZ;
     288           0 :         sc->sc_ic.ic_caps = IEEE80211_C_WEP | IEEE80211_C_SHSLOT;
     289           0 :         sc->sc_ic.ic_phytype = IEEE80211_T_OFDM;
     290           0 :         sc->sc_ic.ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
     291           0 :         sc->sc_ic.ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
     292             : 
     293           0 :         sc->chip_init = acx111_init;
     294           0 :         sc->chip_write_config = acx111_write_config;
     295           0 :         sc->chip_set_fw_txdesc_rate = acx111_set_fw_txdesc_rate;
     296           0 :         sc->chip_set_bss_join_param = acx111_set_bss_join_param;
     297           0 :         sc->sc_flags |= ACX_FLAG_ACX111;
     298           0 : }
     299             : 
     300             : int
     301           0 : acx111_init(struct acx_softc *sc)
     302             : {
     303           0 :         struct ifnet *ifp = &sc->sc_ic.ic_if;
     304             : 
     305             :         /*
     306             :          * NOTE:
     307             :          * Order of initialization:
     308             :          * 1) Templates
     309             :          * 2) Hardware memory
     310             :          * Above order is critical to get a correct memory map
     311             :          */
     312           0 :         if (acx_init_tmplt_ordered(sc) != 0) {
     313           0 :                 printf("%s: %s can't initialize templates\n",
     314           0 :                     ifp->if_xname, __func__);
     315           0 :                 return (ENXIO);
     316             :         }
     317             : 
     318           0 :         if (acx111_init_memory(sc) != 0) {
     319           0 :                 printf("%s: %s can't initialize hw memory\n",
     320           0 :                     ifp->if_xname, __func__);
     321           0 :                 return (ENXIO);
     322             :         }
     323             : 
     324           0 :         return (0);
     325           0 : }
     326             : 
     327             : int
     328           0 : acx111_init_memory(struct acx_softc *sc)
     329             : {
     330           0 :         struct acx111_conf_mem mem;
     331           0 :         struct acx111_conf_meminfo mem_info;
     332           0 :         struct ifnet *ifp = &sc->sc_ic.ic_if;
     333             : 
     334             :         /* Set memory configuration */
     335           0 :         bzero(&mem, sizeof(mem));
     336             : 
     337           0 :         mem.sta_max = htole16(ACX111_STA_MAX);
     338           0 :         mem.memblk_size = htole16(ACX_MEMBLOCK_SIZE);
     339           0 :         mem.rx_memblk_perc = ACX111_RX_MEMBLK_PERCENT;
     340           0 :         mem.opt = ACX111_MEMOPT_DEFAULT;
     341           0 :         mem.xfer_perc = ACX111_XFER_PERCENT;
     342             : 
     343           0 :         mem.fw_rxring_num = 1;
     344           0 :         mem.fw_rxring_type = ACX111_RXRING_TYPE_DEFAULT;
     345           0 :         mem.fw_rxring_prio = ACX111_RXRING_PRIO_DEFAULT;
     346           0 :         mem.fw_rxdesc_num = ACX_RX_DESC_CNT;
     347           0 :         mem.h_rxring_paddr = htole32(sc->sc_ring_data.rx_ring_paddr);
     348             : 
     349           0 :         mem.fw_txring_num = 1;
     350           0 :         mem.fw_txring_attr = ACX111_TXRING_ATTR_DEFAULT;
     351           0 :         mem.fw_txdesc_num = ACX_TX_DESC_CNT;
     352             : 
     353           0 :         if (acx_set_conf(sc, ACX111_CONF_MEM, &mem, sizeof(mem)) != 0) {
     354           0 :                 printf("%s: can't set mem\n", ifp->if_xname);
     355           0 :                 return (1);
     356             :         }
     357             : 
     358             :         /* Get memory configuration */
     359           0 :         if (acx_get_conf(sc, ACX111_CONF_MEMINFO, &mem_info,
     360           0 :             sizeof(mem_info)) != 0) {
     361           0 :                 printf("%s: can't get meminfo\n", ifp->if_xname);
     362           0 :                 return (1);
     363             :         }
     364             : 
     365             :         /* Setup firmware TX descriptor ring */
     366           0 :         acx111_init_fw_txring(sc, letoh32(mem_info.fw_txring_start));
     367             : 
     368             :         /*
     369             :          * There is no need to setup firmware RX descriptor ring,
     370             :          * it is automaticly setup by hardware.
     371             :          */
     372             : 
     373           0 :         return (0);
     374           0 : }
     375             : 
     376             : void
     377           0 : acx111_init_fw_txring(struct acx_softc *sc, uint32_t fw_txdesc_start)
     378             : {
     379             :         struct acx_txbuf *tx_buf;
     380             :         uint32_t desc_paddr;
     381             :         int i;
     382             : 
     383           0 :         tx_buf = sc->sc_buf_data.tx_buf;
     384           0 :         desc_paddr = sc->sc_ring_data.tx_ring_paddr;
     385             : 
     386           0 :         for (i = 0; i < ACX_TX_DESC_CNT; ++i) {
     387           0 :                 tx_buf[i].tb_fwdesc_ofs = fw_txdesc_start +
     388           0 :                     (i * ACX111_FW_TXDESC_SIZE);
     389             : 
     390             :                 /*
     391             :                  * Except for the following fields, rest of the fields
     392             :                  * are setup by hardware.
     393             :                  */
     394           0 :                 FW_TXDESC_SETFIELD_4(sc, &tx_buf[i], f_tx_host_desc,
     395             :                     desc_paddr);
     396           0 :                 FW_TXDESC_SETFIELD_1(sc, &tx_buf[i], f_tx_ctrl,
     397             :                     DESC_CTRL_HOSTOWN);
     398             : 
     399           0 :                 desc_paddr += (2 * sizeof(struct acx_host_desc));
     400             :         }
     401           0 : }
     402             : 
     403             : int
     404           0 : acx111_write_config(struct acx_softc *sc, struct acx_config *conf)
     405             : {
     406           0 :         struct acx111_conf_txpower tx_power;
     407           0 :         struct acx111_conf_option opt;
     408           0 :         struct ifnet *ifp = &sc->sc_ic.ic_if;
     409             :         uint32_t dataflow;
     410             : 
     411             :         /* Set TX power */
     412           0 :         tx_power.txpower = ACX111_TXPOWER_VAL;
     413           0 :         if (acx_set_conf(sc, ACX_CONF_TXPOWER, &tx_power,
     414           0 :             sizeof(tx_power)) != 0) {
     415           0 :                 printf("%s: %s can't set TX power\n",
     416           0 :                     ifp->if_xname, __func__);
     417           0 :                 return (ENXIO);
     418             :         }
     419             : 
     420             :         /*
     421             :          * Turn off hardware WEP
     422             :          */
     423           0 :         if (acx_get_conf(sc, ACX_CONF_OPTION, &opt, sizeof(opt)) != 0) {
     424           0 :                 printf("%s: %s can't get option\n", ifp->if_xname, __func__);
     425           0 :                 return (ENXIO);
     426             :         }
     427             : 
     428           0 :         dataflow = letoh32(opt.dataflow) |
     429           0 :             ACX111_DF_NO_TXENCRYPT |
     430             :             ACX111_DF_NO_RXDECRYPT;
     431           0 :         opt.dataflow = htole32(dataflow);
     432             : 
     433           0 :         if (acx_set_conf(sc, ACX_CONF_OPTION, &opt, sizeof(opt)) != 0) {
     434           0 :                 printf("%s: %s can't set option\n", ifp->if_xname, __func__);
     435           0 :                 return (ENXIO);
     436             :         }
     437             : 
     438           0 :         return (0);
     439           0 : }
     440             : 
     441             : void
     442           0 : acx111_set_fw_txdesc_rate(struct acx_softc *sc, struct acx_txbuf *tx_buf,
     443             :     int rate0)
     444             : {
     445             :         uint16_t rate;
     446             : 
     447           0 :         rate = acx111_rate_map[rate0];
     448           0 :         if (rate == 0)
     449             :                 /* set rate to 1Mbit/s if rate was zero */
     450           0 :                 rate = acx111_rate_map[2];
     451             : 
     452           0 :         FW_TXDESC_SETFIELD_2(sc, tx_buf, u.r2.rate111, rate);
     453           0 : }
     454             : 
     455             : void
     456           0 : acx111_set_bss_join_param(struct acx_softc *sc, void *param, int dtim_intvl)
     457             : {
     458           0 :         struct acx111_bss_join *bj = param;
     459             : 
     460           0 :         bj->basic_rates = htole16(ACX111_RATE_ALL);
     461           0 :         bj->dtim_intvl = dtim_intvl;
     462           0 : }

Generated by: LCOV version 1.13