| /* |
| * This files contains card eeprom (93c46 or 93c56) programming routines, |
| * memory is addressed by 16 bits words. |
| * |
| * This is part of rtl8180 OpenSource driver. |
| * Copyright (C) Andrea Merello 2004 <andrea.merello@gmail.com> |
| * Released under the terms of GPL (General Public Licence) |
| * |
| * Parts of this driver are based on the GPL part of the |
| * official realtek driver. |
| * |
| * Parts of this driver are based on the rtl8180 driver skeleton |
| * from Patric Schenke & Andres Salomon. |
| * |
| * Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. |
| * |
| * We want to thank the Authors of those projects and the Ndiswrapper |
| * project Authors. |
| */ |
| |
| #include "r8180_93cx6.h" |
| |
| static void eprom_cs(struct net_device *dev, short bit) |
| { |
| u8 cmdreg; |
| int err; |
| |
| err = read_nic_byte_E(dev, EPROM_CMD, &cmdreg); |
| if (err) |
| return; |
| if (bit) |
| /* enable EPROM */ |
| write_nic_byte_E(dev, EPROM_CMD, cmdreg | EPROM_CS_BIT); |
| else |
| /* disable EPROM */ |
| write_nic_byte_E(dev, EPROM_CMD, cmdreg & ~EPROM_CS_BIT); |
| |
| force_pci_posting(dev); |
| udelay(EPROM_DELAY); |
| } |
| |
| |
| static void eprom_ck_cycle(struct net_device *dev) |
| { |
| u8 cmdreg; |
| int err; |
| |
| err = read_nic_byte_E(dev, EPROM_CMD, &cmdreg); |
| if (err) |
| return; |
| write_nic_byte_E(dev, EPROM_CMD, cmdreg | EPROM_CK_BIT); |
| force_pci_posting(dev); |
| udelay(EPROM_DELAY); |
| |
| read_nic_byte_E(dev, EPROM_CMD, &cmdreg); |
| write_nic_byte_E(dev, EPROM_CMD, cmdreg & ~EPROM_CK_BIT); |
| force_pci_posting(dev); |
| udelay(EPROM_DELAY); |
| } |
| |
| |
| static void eprom_w(struct net_device *dev, short bit) |
| { |
| u8 cmdreg; |
| int err; |
| |
| err = read_nic_byte_E(dev, EPROM_CMD, &cmdreg); |
| if (err) |
| return; |
| if (bit) |
| write_nic_byte_E(dev, EPROM_CMD, cmdreg | EPROM_W_BIT); |
| else |
| write_nic_byte_E(dev, EPROM_CMD, cmdreg & ~EPROM_W_BIT); |
| |
| force_pci_posting(dev); |
| udelay(EPROM_DELAY); |
| } |
| |
| |
| static short eprom_r(struct net_device *dev) |
| { |
| u8 bit; |
| int err; |
| |
| err = read_nic_byte_E(dev, EPROM_CMD, &bit); |
| if (err) |
| return err; |
| |
| udelay(EPROM_DELAY); |
| |
| if (bit & EPROM_R_BIT) |
| return 1; |
| |
| return 0; |
| } |
| |
| |
| static void eprom_send_bits_string(struct net_device *dev, short b[], int len) |
| { |
| int i; |
| |
| for (i = 0; i < len; i++) { |
| eprom_w(dev, b[i]); |
| eprom_ck_cycle(dev); |
| } |
| } |
| |
| |
| int eprom_read(struct net_device *dev, u32 addr) |
| { |
| struct r8192_priv *priv = ieee80211_priv(dev); |
| short read_cmd[] = {1, 1, 0}; |
| short addr_str[8]; |
| int i; |
| int addr_len; |
| u32 ret; |
| int err; |
| |
| ret = 0; |
| /* enable EPROM programming */ |
| write_nic_byte_E(dev, EPROM_CMD, |
| (EPROM_CMD_PROGRAM<<EPROM_CMD_OPERATING_MODE_SHIFT)); |
| force_pci_posting(dev); |
| udelay(EPROM_DELAY); |
| |
| if (priv->epromtype == EPROM_93c56) { |
| addr_str[7] = addr & 1; |
| addr_str[6] = addr & (1<<1); |
| addr_str[5] = addr & (1<<2); |
| addr_str[4] = addr & (1<<3); |
| addr_str[3] = addr & (1<<4); |
| addr_str[2] = addr & (1<<5); |
| addr_str[1] = addr & (1<<6); |
| addr_str[0] = addr & (1<<7); |
| addr_len = 8; |
| } else { |
| addr_str[5] = addr & 1; |
| addr_str[4] = addr & (1<<1); |
| addr_str[3] = addr & (1<<2); |
| addr_str[2] = addr & (1<<3); |
| addr_str[1] = addr & (1<<4); |
| addr_str[0] = addr & (1<<5); |
| addr_len = 6; |
| } |
| eprom_cs(dev, 1); |
| eprom_ck_cycle(dev); |
| eprom_send_bits_string(dev, read_cmd, 3); |
| eprom_send_bits_string(dev, addr_str, addr_len); |
| |
| /* |
| * keep chip pin D to low state while reading. |
| * I'm unsure if it is necessary, but anyway shouldn't hurt |
| */ |
| eprom_w(dev, 0); |
| |
| for (i = 0; i < 16; i++) { |
| /* eeprom needs a clk cycle between writing opcode&adr |
| * and reading data. (eeprom outs a dummy 0) |
| */ |
| eprom_ck_cycle(dev); |
| err = eprom_r(dev); |
| if (err < 0) |
| return err; |
| |
| ret |= err<<(15-i); |
| } |
| |
| eprom_cs(dev, 0); |
| eprom_ck_cycle(dev); |
| |
| /* disable EPROM programming */ |
| write_nic_byte_E(dev, EPROM_CMD, |
| (EPROM_CMD_NORMAL<<EPROM_CMD_OPERATING_MODE_SHIFT)); |
| return ret; |
| } |