18fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang/*
28fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang   This files contains card eeprom (93c46 or 93c56) programming routines,
38fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang   memory is addressed by 16 bits words.
48fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
58fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang   This is part of rtl8180 OpenSource driver.
68fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang   Copyright (C) Andrea Merello 2004  <andreamrl@tiscali.it>
78fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang   Released under the terms of GPL (General Public Licence)
88fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
98fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang   Parts of this driver are based on the GPL part of the
108fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang   official realtek driver.
118fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
128fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang   Parts of this driver are based on the rtl8180 driver skeleton
138fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang   from Patric Schenke & Andres Salomon.
148fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
158fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang   Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
168fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
178fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang   We want to tanks the Authors of those projects and the Ndiswrapper
188fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang   project Authors.
198fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang*/
208fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
218fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#include "r8180_93cx6.h"
228fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
238fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangvoid eprom_cs(struct net_device *dev, short bit)
248fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
258fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if(bit)
268fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		write_nic_byte_E(dev, EPROM_CMD,
278fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			       (1<<EPROM_CS_SHIFT) | \
288fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			       read_nic_byte_E(dev, EPROM_CMD)); //enable EPROM
298fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	else
308fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		write_nic_byte_E(dev, EPROM_CMD, read_nic_byte_E(dev, EPROM_CMD)\
318fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			       &~(1<<EPROM_CS_SHIFT)); //disable EPROM
328fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
338fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	force_pci_posting(dev);
348fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	udelay(EPROM_DELAY);
358fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
368fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
378fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
388fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangvoid eprom_ck_cycle(struct net_device *dev)
398fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
408fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	write_nic_byte_E(dev, EPROM_CMD,
418fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		       (1<<EPROM_CK_SHIFT) | read_nic_byte_E(dev,EPROM_CMD));
428fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	force_pci_posting(dev);
438fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	udelay(EPROM_DELAY);
448fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	write_nic_byte_E(dev, EPROM_CMD,
458fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		       read_nic_byte_E(dev, EPROM_CMD) &~ (1<<EPROM_CK_SHIFT));
468fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	force_pci_posting(dev);
478fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	udelay(EPROM_DELAY);
488fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
498fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
508fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
518fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangvoid eprom_w(struct net_device *dev,short bit)
528fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
538fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if(bit)
548fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		write_nic_byte_E(dev, EPROM_CMD, (1<<EPROM_W_SHIFT) | \
558fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			       read_nic_byte_E(dev,EPROM_CMD));
568fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	else
578fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		write_nic_byte_E(dev, EPROM_CMD, read_nic_byte_E(dev,EPROM_CMD)\
588fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			       &~(1<<EPROM_W_SHIFT));
598fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
608fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	force_pci_posting(dev);
618fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	udelay(EPROM_DELAY);
628fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
638fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
648fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
658fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangshort eprom_r(struct net_device *dev)
668fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
678fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	short bit;
688fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
698fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	bit=(read_nic_byte_E(dev, EPROM_CMD) & (1<<EPROM_R_SHIFT) );
708fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	udelay(EPROM_DELAY);
718fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
728fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if(bit) return 1;
738fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return 0;
748fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
758fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
768fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
778fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangvoid eprom_send_bits_string(struct net_device *dev, short b[], int len)
788fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
798fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	int i;
808fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
818fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	for(i=0; i<len; i++){
828fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		eprom_w(dev, b[i]);
838fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		eprom_ck_cycle(dev);
848fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
858fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
868fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
878fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
888fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangu32 eprom_read(struct net_device *dev, u32 addr)
898fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
908fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct r8192_priv *priv = ieee80211_priv(dev);
918fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	short read_cmd[]={1,1,0};
928fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	short addr_str[8];
938fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	int i;
948fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	int addr_len;
958fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u32 ret;
968fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
978fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	ret=0;
988fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang        //enable EPROM programming
998fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	write_nic_byte_E(dev, EPROM_CMD,
1008fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		       (EPROM_CMD_PROGRAM<<EPROM_CMD_OPERATING_MODE_SHIFT));
1018fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	force_pci_posting(dev);
1028fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	udelay(EPROM_DELAY);
1038fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1048fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (priv->epromtype==EPROM_93c56){
1058fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		addr_str[7]=addr & 1;
1068fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		addr_str[6]=addr & (1<<1);
1078fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		addr_str[5]=addr & (1<<2);
1088fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		addr_str[4]=addr & (1<<3);
1098fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		addr_str[3]=addr & (1<<4);
1108fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		addr_str[2]=addr & (1<<5);
1118fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		addr_str[1]=addr & (1<<6);
1128fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		addr_str[0]=addr & (1<<7);
1138fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		addr_len=8;
1148fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}else{
1158fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		addr_str[5]=addr & 1;
1168fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		addr_str[4]=addr & (1<<1);
1178fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		addr_str[3]=addr & (1<<2);
1188fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		addr_str[2]=addr & (1<<3);
1198fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		addr_str[1]=addr & (1<<4);
1208fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		addr_str[0]=addr & (1<<5);
1218fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		addr_len=6;
1228fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
1238fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	eprom_cs(dev, 1);
1248fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	eprom_ck_cycle(dev);
1258fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	eprom_send_bits_string(dev, read_cmd, 3);
1268fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	eprom_send_bits_string(dev, addr_str, addr_len);
1278fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1288fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	//keep chip pin D to low state while reading.
1298fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	//I'm unsure if it is necessary, but anyway shouldn't hurt
1308fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	eprom_w(dev, 0);
1318fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1328fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	for(i=0;i<16;i++){
1338fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		//eeprom needs a clk cycle between writing opcode&adr
1348fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		//and reading data. (eeprom outs a dummy 0)
1358fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		eprom_ck_cycle(dev);
1368fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		ret |= (eprom_r(dev)<<(15-i));
1378fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
1388fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1398fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	eprom_cs(dev, 0);
1408fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	eprom_ck_cycle(dev);
1418fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1428fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	//disable EPROM programming
1438fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	write_nic_byte_E(dev, EPROM_CMD,
1448fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		       (EPROM_CMD_NORMAL<<EPROM_CMD_OPERATING_MODE_SHIFT));
1458fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return ret;
1468fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
147