cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ppc6lnx.c (14693B)


      1/*
      2	ppc6lnx.c (c) 2001 Micro Solutions Inc.
      3		Released under the terms of the GNU General Public license
      4
      5	ppc6lnx.c  is a par of the protocol driver for the Micro Solutions
      6		"BACKPACK" parallel port IDE adapter
      7		(Works on Series 6 drives)
      8
      9*/
     10
     11//***************************************************************************
     12
     13// PPC 6 Code in C sanitized for LINUX
     14// Original x86 ASM by Ron, Converted to C by Clive
     15
     16//***************************************************************************
     17
     18
     19#define port_stb					1
     20#define port_afd					2
     21#define cmd_stb						port_afd
     22#define port_init					4
     23#define data_stb					port_init
     24#define port_sel					8
     25#define port_int					16
     26#define port_dir					0x20
     27
     28#define ECR_EPP	0x80
     29#define ECR_BI	0x20
     30
     31//***************************************************************************
     32
     33//  60772 Commands
     34
     35#define ACCESS_REG				0x00
     36#define ACCESS_PORT				0x40
     37
     38#define ACCESS_READ				0x00
     39#define ACCESS_WRITE			0x20
     40
     41//  60772 Command Prefix
     42
     43#define CMD_PREFIX_SET		0xe0		// Special command that modifies the next command's operation
     44#define CMD_PREFIX_RESET	0xc0		// Resets current cmd modifier reg bits
     45 #define PREFIX_IO16			0x01		// perform 16-bit wide I/O
     46 #define PREFIX_FASTWR		0x04		// enable PPC mode fast-write
     47 #define PREFIX_BLK				0x08		// enable block transfer mode
     48
     49// 60772 Registers
     50
     51#define REG_STATUS				0x00		// status register
     52 #define STATUS_IRQA			0x01		// Peripheral IRQA line
     53 #define STATUS_EEPROM_DO	0x40		// Serial EEPROM data bit
     54#define REG_VERSION				0x01		// PPC version register (read)
     55#define REG_HWCFG					0x02		// Hardware Config register
     56#define REG_RAMSIZE				0x03		// Size of RAM Buffer
     57 #define RAMSIZE_128K			0x02
     58#define REG_EEPROM				0x06		// EEPROM control register
     59 #define EEPROM_SK				0x01		// eeprom SK bit
     60 #define EEPROM_DI				0x02		// eeprom DI bit
     61 #define EEPROM_CS				0x04		// eeprom CS bit
     62 #define EEPROM_EN				0x08		// eeprom output enable
     63#define REG_BLKSIZE				0x08		// Block transfer len (24 bit)
     64
     65//***************************************************************************
     66
     67typedef struct ppc_storage {
     68	u16	lpt_addr;				// LPT base address
     69	u8	ppc_id;
     70	u8	mode;						// operating mode
     71					// 0 = PPC Uni SW
     72					// 1 = PPC Uni FW
     73					// 2 = PPC Bi SW
     74					// 3 = PPC Bi FW
     75					// 4 = EPP Byte
     76					// 5 = EPP Word
     77					// 6 = EPP Dword
     78	u8	ppc_flags;
     79	u8	org_data;				// original LPT data port contents
     80	u8	org_ctrl;				// original LPT control port contents
     81	u8	cur_ctrl;				// current control port contents
     82} Interface;
     83
     84//***************************************************************************
     85
     86// ppc_flags
     87
     88#define fifo_wait					0x10
     89
     90//***************************************************************************
     91
     92// DONT CHANGE THESE LEST YOU BREAK EVERYTHING - BIT FIELD DEPENDENCIES
     93
     94#define PPCMODE_UNI_SW		0
     95#define PPCMODE_UNI_FW		1
     96#define PPCMODE_BI_SW			2
     97#define PPCMODE_BI_FW			3
     98#define PPCMODE_EPP_BYTE	4
     99#define PPCMODE_EPP_WORD	5
    100#define PPCMODE_EPP_DWORD	6
    101
    102//***************************************************************************
    103
    104static int ppc6_select(Interface *ppc);
    105static void ppc6_deselect(Interface *ppc);
    106static void ppc6_send_cmd(Interface *ppc, u8 cmd);
    107static void ppc6_wr_data_byte(Interface *ppc, u8 data);
    108static u8 ppc6_rd_data_byte(Interface *ppc);
    109static u8 ppc6_rd_port(Interface *ppc, u8 port);
    110static void ppc6_wr_port(Interface *ppc, u8 port, u8 data);
    111static void ppc6_rd_data_blk(Interface *ppc, u8 *data, long count);
    112static void ppc6_wait_for_fifo(Interface *ppc);
    113static void ppc6_wr_data_blk(Interface *ppc, u8 *data, long count);
    114static void ppc6_rd_port16_blk(Interface *ppc, u8 port, u8 *data, long length);
    115static void ppc6_wr_port16_blk(Interface *ppc, u8 port, u8 *data, long length);
    116static void ppc6_wr_extout(Interface *ppc, u8 regdata);
    117static int ppc6_open(Interface *ppc);
    118static void ppc6_close(Interface *ppc);
    119
    120//***************************************************************************
    121
    122static int ppc6_select(Interface *ppc)
    123{
    124	u8 i, j, k;
    125
    126	i = inb(ppc->lpt_addr + 1);
    127
    128	if (i & 1)
    129		outb(i, ppc->lpt_addr + 1);
    130
    131	ppc->org_data = inb(ppc->lpt_addr);
    132
    133	ppc->org_ctrl = inb(ppc->lpt_addr + 2) & 0x5F; // readback ctrl
    134
    135	ppc->cur_ctrl = ppc->org_ctrl;
    136
    137	ppc->cur_ctrl |= port_sel;
    138
    139	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    140
    141	if (ppc->org_data == 'b')
    142		outb('x', ppc->lpt_addr);
    143
    144	outb('b', ppc->lpt_addr);
    145	outb('p', ppc->lpt_addr);
    146	outb(ppc->ppc_id, ppc->lpt_addr);
    147	outb(~ppc->ppc_id,ppc->lpt_addr);
    148
    149	ppc->cur_ctrl &= ~port_sel;
    150
    151	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    152
    153	ppc->cur_ctrl = (ppc->cur_ctrl & port_int) | port_init;
    154
    155	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    156
    157	i = ppc->mode & 0x0C;
    158
    159	if (i == 0)
    160		i = (ppc->mode & 2) | 1;
    161
    162	outb(i, ppc->lpt_addr);
    163
    164	ppc->cur_ctrl |= port_sel;
    165
    166	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    167
    168	// DELAY
    169
    170	ppc->cur_ctrl |= port_afd;
    171
    172	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    173
    174	j = ((i & 0x08) << 4) | ((i & 0x07) << 3);
    175
    176	k = inb(ppc->lpt_addr + 1) & 0xB8;
    177
    178	if (j == k)
    179	{
    180		ppc->cur_ctrl &= ~port_afd;
    181
    182		outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    183
    184		k = (inb(ppc->lpt_addr + 1) & 0xB8) ^ 0xB8;
    185
    186		if (j == k)
    187		{
    188			if (i & 4)	// EPP
    189				ppc->cur_ctrl &= ~(port_sel | port_init);
    190			else				// PPC/ECP
    191				ppc->cur_ctrl &= ~port_sel;
    192
    193			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    194
    195			return(1);
    196		}
    197	}
    198
    199	outb(ppc->org_ctrl, ppc->lpt_addr + 2);
    200
    201	outb(ppc->org_data, ppc->lpt_addr);
    202
    203	return(0); // FAIL
    204}
    205
    206//***************************************************************************
    207
    208static void ppc6_deselect(Interface *ppc)
    209{
    210	if (ppc->mode & 4)	// EPP
    211		ppc->cur_ctrl |= port_init;
    212	else								// PPC/ECP
    213		ppc->cur_ctrl |= port_sel;
    214
    215	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    216
    217	outb(ppc->org_data, ppc->lpt_addr);
    218
    219	outb((ppc->org_ctrl | port_sel), ppc->lpt_addr + 2);
    220
    221	outb(ppc->org_ctrl, ppc->lpt_addr + 2);
    222}
    223
    224//***************************************************************************
    225
    226static void ppc6_send_cmd(Interface *ppc, u8 cmd)
    227{
    228	switch(ppc->mode)
    229	{
    230		case PPCMODE_UNI_SW :
    231		case PPCMODE_UNI_FW :
    232		case PPCMODE_BI_SW :
    233		case PPCMODE_BI_FW :
    234		{
    235			outb(cmd, ppc->lpt_addr);
    236
    237			ppc->cur_ctrl ^= cmd_stb;
    238
    239			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    240
    241			break;
    242		}
    243
    244		case PPCMODE_EPP_BYTE :
    245		case PPCMODE_EPP_WORD :
    246		case PPCMODE_EPP_DWORD :
    247		{
    248			outb(cmd, ppc->lpt_addr + 3);
    249
    250			break;
    251		}
    252	}
    253}
    254
    255//***************************************************************************
    256
    257static void ppc6_wr_data_byte(Interface *ppc, u8 data)
    258{
    259	switch(ppc->mode)
    260	{
    261		case PPCMODE_UNI_SW :
    262		case PPCMODE_UNI_FW :
    263		case PPCMODE_BI_SW :
    264		case PPCMODE_BI_FW :
    265		{
    266			outb(data, ppc->lpt_addr);
    267
    268			ppc->cur_ctrl ^= data_stb;
    269
    270			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    271
    272			break;
    273		}
    274
    275		case PPCMODE_EPP_BYTE :
    276		case PPCMODE_EPP_WORD :
    277		case PPCMODE_EPP_DWORD :
    278		{
    279			outb(data, ppc->lpt_addr + 4);
    280
    281			break;
    282		}
    283	}
    284}
    285
    286//***************************************************************************
    287
    288static u8 ppc6_rd_data_byte(Interface *ppc)
    289{
    290	u8 data = 0;
    291
    292	switch(ppc->mode)
    293	{
    294		case PPCMODE_UNI_SW :
    295		case PPCMODE_UNI_FW :
    296		{
    297			ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb;
    298
    299			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    300
    301			// DELAY
    302
    303			data = inb(ppc->lpt_addr + 1);
    304
    305			data = ((data & 0x80) >> 1) | ((data & 0x38) >> 3);
    306
    307			ppc->cur_ctrl |= port_stb;
    308
    309			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    310
    311			// DELAY
    312
    313			data |= inb(ppc->lpt_addr + 1) & 0xB8;
    314
    315			break;
    316		}
    317
    318		case PPCMODE_BI_SW :
    319		case PPCMODE_BI_FW :
    320		{
    321			ppc->cur_ctrl |= port_dir;
    322
    323			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    324
    325			ppc->cur_ctrl = (ppc->cur_ctrl | port_stb) ^ data_stb;
    326
    327			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    328
    329			data = inb(ppc->lpt_addr);
    330
    331			ppc->cur_ctrl &= ~port_stb;
    332
    333			outb(ppc->cur_ctrl,ppc->lpt_addr + 2);
    334
    335			ppc->cur_ctrl &= ~port_dir;
    336
    337			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    338
    339			break;
    340		}
    341
    342		case PPCMODE_EPP_BYTE :
    343		case PPCMODE_EPP_WORD :
    344		case PPCMODE_EPP_DWORD :
    345		{
    346			outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2);
    347
    348			data = inb(ppc->lpt_addr + 4);
    349
    350			outb(ppc->cur_ctrl,ppc->lpt_addr + 2);
    351
    352			break;
    353		}
    354	}
    355
    356	return(data);
    357}
    358
    359//***************************************************************************
    360
    361static u8 ppc6_rd_port(Interface *ppc, u8 port)
    362{
    363	ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_READ));
    364
    365	return(ppc6_rd_data_byte(ppc));
    366}
    367
    368//***************************************************************************
    369
    370static void ppc6_wr_port(Interface *ppc, u8 port, u8 data)
    371{
    372	ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_WRITE));
    373
    374	ppc6_wr_data_byte(ppc, data);
    375}
    376
    377//***************************************************************************
    378
    379static void ppc6_rd_data_blk(Interface *ppc, u8 *data, long count)
    380{
    381	switch(ppc->mode)
    382	{
    383		case PPCMODE_UNI_SW :
    384		case PPCMODE_UNI_FW :
    385		{
    386			while(count)
    387			{
    388				u8 d;
    389
    390				ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb;
    391
    392				outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    393
    394				// DELAY
    395
    396				d = inb(ppc->lpt_addr + 1);
    397
    398				d = ((d & 0x80) >> 1) | ((d & 0x38) >> 3);
    399
    400				ppc->cur_ctrl |= port_stb;
    401
    402				outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    403
    404				// DELAY
    405
    406				d |= inb(ppc->lpt_addr + 1) & 0xB8;
    407
    408				*data++ = d;
    409				count--;
    410			}
    411
    412			break;
    413		}
    414
    415		case PPCMODE_BI_SW :
    416		case PPCMODE_BI_FW :
    417		{
    418			ppc->cur_ctrl |= port_dir;
    419
    420			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    421
    422			ppc->cur_ctrl |= port_stb;
    423
    424			while(count)
    425			{
    426				ppc->cur_ctrl ^= data_stb;
    427
    428				outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    429
    430				*data++ = inb(ppc->lpt_addr);
    431				count--;
    432			}
    433
    434			ppc->cur_ctrl &= ~port_stb;
    435
    436			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    437
    438			ppc->cur_ctrl &= ~port_dir;
    439
    440			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    441
    442			break;
    443		}
    444
    445		case PPCMODE_EPP_BYTE :
    446		{
    447			outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2);
    448
    449			// DELAY
    450
    451			while(count)
    452			{
    453				*data++ = inb(ppc->lpt_addr + 4);
    454				count--;
    455			}
    456
    457			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    458
    459			break;
    460		}
    461
    462		case PPCMODE_EPP_WORD :
    463		{
    464			outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2);
    465
    466			// DELAY
    467
    468			while(count > 1)
    469			{
    470				*((u16 *)data) = inw(ppc->lpt_addr + 4);
    471				data  += 2;
    472				count -= 2;
    473			}
    474
    475			while(count)
    476			{
    477				*data++ = inb(ppc->lpt_addr + 4);
    478				count--;
    479			}
    480
    481			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    482
    483			break;
    484		}
    485
    486		case PPCMODE_EPP_DWORD :
    487		{
    488			outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2);
    489
    490			// DELAY
    491
    492			while(count > 3)
    493			{
    494				*((u32 *)data) = inl(ppc->lpt_addr + 4);
    495				data  += 4;
    496				count -= 4;
    497			}
    498
    499			while(count)
    500			{
    501				*data++ = inb(ppc->lpt_addr + 4);
    502				count--;
    503			}
    504
    505			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    506
    507			break;
    508		}
    509	}
    510
    511}
    512
    513//***************************************************************************
    514
    515static void ppc6_wait_for_fifo(Interface *ppc)
    516{
    517	int i;
    518
    519	if (ppc->ppc_flags & fifo_wait)
    520	{
    521		for(i=0; i<20; i++)
    522			inb(ppc->lpt_addr + 1);
    523	}
    524}
    525
    526//***************************************************************************
    527
    528static void ppc6_wr_data_blk(Interface *ppc, u8 *data, long count)
    529{
    530	switch(ppc->mode)
    531	{
    532		case PPCMODE_UNI_SW :
    533		case PPCMODE_BI_SW :
    534		{
    535			while(count--)
    536			{
    537				outb(*data++, ppc->lpt_addr);
    538
    539				ppc->cur_ctrl ^= data_stb;
    540
    541				outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    542			}
    543
    544			break;
    545		}
    546
    547		case PPCMODE_UNI_FW :
    548		case PPCMODE_BI_FW :
    549		{
    550			u8 this, last;
    551
    552			ppc6_send_cmd(ppc,(CMD_PREFIX_SET | PREFIX_FASTWR));
    553
    554			ppc->cur_ctrl |= port_stb;
    555
    556			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    557
    558			last = *data;
    559
    560			outb(last, ppc->lpt_addr);
    561
    562			while(count)
    563			{
    564				this = *data++;
    565				count--;
    566
    567				if (this == last)
    568				{
    569					ppc->cur_ctrl ^= data_stb;
    570
    571					outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    572				}
    573				else
    574				{
    575					outb(this, ppc->lpt_addr);
    576
    577					last = this;
    578				}
    579			}
    580
    581			ppc->cur_ctrl &= ~port_stb;
    582
    583			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
    584
    585			ppc6_send_cmd(ppc,(CMD_PREFIX_RESET | PREFIX_FASTWR));
    586
    587			break;
    588		}
    589
    590		case PPCMODE_EPP_BYTE :
    591		{
    592			while(count)
    593			{
    594				outb(*data++,ppc->lpt_addr + 4);
    595				count--;
    596			}
    597
    598			ppc6_wait_for_fifo(ppc);
    599
    600			break;
    601		}
    602
    603		case PPCMODE_EPP_WORD :
    604		{
    605			while(count > 1)
    606			{
    607				outw(*((u16 *)data),ppc->lpt_addr + 4);
    608				data  += 2;
    609				count -= 2;
    610			}
    611
    612			while(count)
    613			{
    614				outb(*data++,ppc->lpt_addr + 4);
    615				count--;
    616			}
    617
    618			ppc6_wait_for_fifo(ppc);
    619
    620			break;
    621		}
    622
    623		case PPCMODE_EPP_DWORD :
    624		{
    625			while(count > 3)
    626			{
    627				outl(*((u32 *)data),ppc->lpt_addr + 4);
    628				data  += 4;
    629				count -= 4;
    630			}
    631
    632			while(count)
    633			{
    634				outb(*data++,ppc->lpt_addr + 4);
    635				count--;
    636			}
    637
    638			ppc6_wait_for_fifo(ppc);
    639
    640			break;
    641		}
    642	}
    643}
    644
    645//***************************************************************************
    646
    647static void ppc6_rd_port16_blk(Interface *ppc, u8 port, u8 *data, long length)
    648{
    649	length = length << 1;
    650
    651	ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE));
    652	ppc6_wr_data_byte(ppc,(u8)length);
    653	ppc6_wr_data_byte(ppc,(u8)(length >> 8));
    654	ppc6_wr_data_byte(ppc,0);
    655
    656	ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK));
    657
    658	ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_READ));
    659
    660	ppc6_rd_data_blk(ppc, data, length);
    661
    662	ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK));
    663}
    664
    665//***************************************************************************
    666
    667static void ppc6_wr_port16_blk(Interface *ppc, u8 port, u8 *data, long length)
    668{
    669	length = length << 1;
    670
    671	ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE));
    672	ppc6_wr_data_byte(ppc,(u8)length);
    673	ppc6_wr_data_byte(ppc,(u8)(length >> 8));
    674	ppc6_wr_data_byte(ppc,0);
    675
    676	ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK));
    677
    678	ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_WRITE));
    679
    680	ppc6_wr_data_blk(ppc, data, length);
    681
    682	ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK));
    683}
    684
    685//***************************************************************************
    686
    687static void ppc6_wr_extout(Interface *ppc, u8 regdata)
    688{
    689	ppc6_send_cmd(ppc,(REG_VERSION | ACCESS_REG | ACCESS_WRITE));
    690
    691	ppc6_wr_data_byte(ppc, (u8)((regdata & 0x03) << 6));
    692}
    693
    694//***************************************************************************
    695
    696static int ppc6_open(Interface *ppc)
    697{
    698	int ret;
    699
    700	ret = ppc6_select(ppc);
    701
    702	if (ret == 0)
    703		return(ret);
    704
    705	ppc->ppc_flags &= ~fifo_wait;
    706
    707	ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_WRITE | REG_RAMSIZE));
    708	ppc6_wr_data_byte(ppc, RAMSIZE_128K);
    709
    710	ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_READ | REG_VERSION));
    711
    712	if ((ppc6_rd_data_byte(ppc) & 0x3F) == 0x0C)
    713		ppc->ppc_flags |= fifo_wait;
    714
    715	return(ret);
    716}
    717
    718//***************************************************************************
    719
    720static void ppc6_close(Interface *ppc)
    721{
    722	ppc6_deselect(ppc);
    723}
    724
    725//***************************************************************************
    726