18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci	backpack.c (c) 2001 Micro Solutions Inc.
38c2ecf20Sopenharmony_ci		Released under the terms of the GNU General Public license
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci	backpack.c is a low-level protocol driver for the Micro Solutions
68c2ecf20Sopenharmony_ci		"BACKPACK" parallel port IDE adapter
78c2ecf20Sopenharmony_ci		(Works on Series 6 drives)
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci	Written by: Ken Hahn     (linux-dev@micro-solutions.com)
108c2ecf20Sopenharmony_ci	            Clive Turvey (linux-dev@micro-solutions.com)
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci*/
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/*
158c2ecf20Sopenharmony_ci   This is Ken's linux wrapper for the PPC library
168c2ecf20Sopenharmony_ci   Version 1.0.0 is the backpack driver for which source is not available
178c2ecf20Sopenharmony_ci   Version 2.0.0 is the first to have source released
188c2ecf20Sopenharmony_ci   Version 2.0.1 is the "Cox-ified" source code
198c2ecf20Sopenharmony_ci   Version 2.0.2 - fixed version string usage, and made ppc functions static
208c2ecf20Sopenharmony_ci*/
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define BACKPACK_VERSION "2.0.2"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <linux/module.h>
268c2ecf20Sopenharmony_ci#include <linux/init.h>
278c2ecf20Sopenharmony_ci#include <linux/kernel.h>
288c2ecf20Sopenharmony_ci#include <linux/slab.h>
298c2ecf20Sopenharmony_ci#include <linux/types.h>
308c2ecf20Sopenharmony_ci#include <asm/io.h>
318c2ecf20Sopenharmony_ci#include <linux/parport.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include "ppc6lnx.c"
348c2ecf20Sopenharmony_ci#include "paride.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* PARAMETERS */
378c2ecf20Sopenharmony_cistatic bool verbose; /* set this to 1 to see debugging messages and whatnot */
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define PPCSTRUCT(pi) ((Interface *)(pi->private))
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/****************************************************************/
438c2ecf20Sopenharmony_ci/*
448c2ecf20Sopenharmony_ci ATAPI CDROM DRIVE REGISTERS
458c2ecf20Sopenharmony_ci*/
468c2ecf20Sopenharmony_ci#define ATAPI_DATA       0      /* data port                  */
478c2ecf20Sopenharmony_ci#define ATAPI_ERROR      1      /* error register (read)      */
488c2ecf20Sopenharmony_ci#define ATAPI_FEATURES   1      /* feature register (write)   */
498c2ecf20Sopenharmony_ci#define ATAPI_INT_REASON 2      /* interrupt reason register  */
508c2ecf20Sopenharmony_ci#define ATAPI_COUNT_LOW  4      /* byte count register (low)  */
518c2ecf20Sopenharmony_ci#define ATAPI_COUNT_HIGH 5      /* byte count register (high) */
528c2ecf20Sopenharmony_ci#define ATAPI_DRIVE_SEL  6      /* drive select register      */
538c2ecf20Sopenharmony_ci#define ATAPI_STATUS     7      /* status port (read)         */
548c2ecf20Sopenharmony_ci#define ATAPI_COMMAND    7      /* command port (write)       */
558c2ecf20Sopenharmony_ci#define ATAPI_ALT_STATUS 0x0e /* alternate status reg (read) */
568c2ecf20Sopenharmony_ci#define ATAPI_DEVICE_CONTROL 0x0e /* device control (write)   */
578c2ecf20Sopenharmony_ci/****************************************************************/
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic int bpck6_read_regr(PIA *pi, int cont, int reg)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	unsigned int out;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/* check for bad settings */
648c2ecf20Sopenharmony_ci	if (reg<0 || reg>7 || cont<0 || cont>2)
658c2ecf20Sopenharmony_ci	{
668c2ecf20Sopenharmony_ci		return(-1);
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci	out=ppc6_rd_port(PPCSTRUCT(pi),cont?reg|8:reg);
698c2ecf20Sopenharmony_ci	return(out);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic void bpck6_write_regr(PIA *pi, int cont, int reg, int val)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	/* check for bad settings */
758c2ecf20Sopenharmony_ci	if (reg>=0 && reg<=7 && cont>=0 && cont<=1)
768c2ecf20Sopenharmony_ci	{
778c2ecf20Sopenharmony_ci		ppc6_wr_port(PPCSTRUCT(pi),cont?reg|8:reg,(u8)val);
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic void bpck6_write_block( PIA *pi, char * buf, int len )
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	ppc6_wr_port16_blk(PPCSTRUCT(pi),ATAPI_DATA,buf,(u32)len>>1);
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic void bpck6_read_block( PIA *pi, char * buf, int len )
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	ppc6_rd_port16_blk(PPCSTRUCT(pi),ATAPI_DATA,buf,(u32)len>>1);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic void bpck6_connect ( PIA *pi  )
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	if(verbose)
948c2ecf20Sopenharmony_ci	{
958c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "connect\n");
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if(pi->mode >=2)
998c2ecf20Sopenharmony_ci  	{
1008c2ecf20Sopenharmony_ci		PPCSTRUCT(pi)->mode=4+pi->mode-2;
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci	else if(pi->mode==1)
1038c2ecf20Sopenharmony_ci	{
1048c2ecf20Sopenharmony_ci		PPCSTRUCT(pi)->mode=3;
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci	else
1078c2ecf20Sopenharmony_ci	{
1088c2ecf20Sopenharmony_ci		PPCSTRUCT(pi)->mode=1;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	ppc6_open(PPCSTRUCT(pi));
1128c2ecf20Sopenharmony_ci	ppc6_wr_extout(PPCSTRUCT(pi),0x3);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic void bpck6_disconnect ( PIA *pi )
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	if(verbose)
1188c2ecf20Sopenharmony_ci	{
1198c2ecf20Sopenharmony_ci		printk("disconnect\n");
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci	ppc6_wr_extout(PPCSTRUCT(pi),0x0);
1228c2ecf20Sopenharmony_ci	ppc6_close(PPCSTRUCT(pi));
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic int bpck6_test_port ( PIA *pi )   /* check for 8-bit port */
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	if(verbose)
1288c2ecf20Sopenharmony_ci	{
1298c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "PARPORT indicates modes=%x for lp=0x%lx\n",
1308c2ecf20Sopenharmony_ci               		((struct pardevice*)(pi->pardev))->port->modes,
1318c2ecf20Sopenharmony_ci			((struct pardevice *)(pi->pardev))->port->base);
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	/*copy over duplicate stuff.. initialize state info*/
1358c2ecf20Sopenharmony_ci	PPCSTRUCT(pi)->ppc_id=pi->unit;
1368c2ecf20Sopenharmony_ci	PPCSTRUCT(pi)->lpt_addr=pi->port;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	/* look at the parport device to see if what modes we can use */
1398c2ecf20Sopenharmony_ci	if(((struct pardevice *)(pi->pardev))->port->modes &
1408c2ecf20Sopenharmony_ci		(PARPORT_MODE_EPP)
1418c2ecf20Sopenharmony_ci          )
1428c2ecf20Sopenharmony_ci	{
1438c2ecf20Sopenharmony_ci		return 5; /* Can do EPP*/
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci	else if(((struct pardevice *)(pi->pardev))->port->modes &
1468c2ecf20Sopenharmony_ci			(PARPORT_MODE_TRISTATE)
1478c2ecf20Sopenharmony_ci               )
1488c2ecf20Sopenharmony_ci	{
1498c2ecf20Sopenharmony_ci		return 2;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci	else /*Just flat SPP*/
1528c2ecf20Sopenharmony_ci	{
1538c2ecf20Sopenharmony_ci		return 1;
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic int bpck6_probe_unit ( PIA *pi )
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	int out;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	if(verbose)
1628c2ecf20Sopenharmony_ci	{
1638c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "PROBE UNIT %x on port:%x\n",pi->unit,pi->port);
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/*SET PPC UNIT NUMBER*/
1678c2ecf20Sopenharmony_ci	PPCSTRUCT(pi)->ppc_id=pi->unit;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	/*LOWER DOWN TO UNIDIRECTIONAL*/
1708c2ecf20Sopenharmony_ci	PPCSTRUCT(pi)->mode=1;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	out=ppc6_open(PPCSTRUCT(pi));
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	if(verbose)
1758c2ecf20Sopenharmony_ci	{
1768c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "ppc_open returned %2x\n",out);
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci  	if(out)
1808c2ecf20Sopenharmony_ci 	{
1818c2ecf20Sopenharmony_ci		ppc6_close(PPCSTRUCT(pi));
1828c2ecf20Sopenharmony_ci		if(verbose)
1838c2ecf20Sopenharmony_ci		{
1848c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "leaving probe\n");
1858c2ecf20Sopenharmony_ci		}
1868c2ecf20Sopenharmony_ci               return(1);
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci  	else
1898c2ecf20Sopenharmony_ci  	{
1908c2ecf20Sopenharmony_ci		if(verbose)
1918c2ecf20Sopenharmony_ci		{
1928c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "Failed open\n");
1938c2ecf20Sopenharmony_ci		}
1948c2ecf20Sopenharmony_ci    		return(0);
1958c2ecf20Sopenharmony_ci  	}
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic void bpck6_log_adapter( PIA *pi, char * scratch, int verbose )
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	char *mode_string[5]=
2018c2ecf20Sopenharmony_ci		{"4-bit","8-bit","EPP-8","EPP-16","EPP-32"};
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	printk("%s: BACKPACK Protocol Driver V"BACKPACK_VERSION"\n",pi->device);
2048c2ecf20Sopenharmony_ci	printk("%s: Copyright 2001 by Micro Solutions, Inc., DeKalb IL.\n",pi->device);
2058c2ecf20Sopenharmony_ci	printk("%s: BACKPACK %s, Micro Solutions BACKPACK Drive at 0x%x\n",
2068c2ecf20Sopenharmony_ci		pi->device,BACKPACK_VERSION,pi->port);
2078c2ecf20Sopenharmony_ci	printk("%s: Unit: %d Mode:%d (%s) Delay %d\n",pi->device,
2088c2ecf20Sopenharmony_ci		pi->unit,pi->mode,mode_string[pi->mode],pi->delay);
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic int bpck6_init_proto(PIA *pi)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	Interface *p = kzalloc(sizeof(Interface), GFP_KERNEL);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	if (p) {
2168c2ecf20Sopenharmony_ci		pi->private = (unsigned long)p;
2178c2ecf20Sopenharmony_ci		return 0;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	printk(KERN_ERR "%s: ERROR COULDN'T ALLOCATE MEMORY\n", pi->device);
2218c2ecf20Sopenharmony_ci	return -1;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cistatic void bpck6_release_proto(PIA *pi)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	kfree((void *)(pi->private));
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic struct pi_protocol bpck6 = {
2308c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
2318c2ecf20Sopenharmony_ci	.name		= "bpck6",
2328c2ecf20Sopenharmony_ci	.max_mode	= 5,
2338c2ecf20Sopenharmony_ci	.epp_first	= 2, /* 2-5 use epp (need 8 ports) */
2348c2ecf20Sopenharmony_ci	.max_units	= 255,
2358c2ecf20Sopenharmony_ci	.write_regr	= bpck6_write_regr,
2368c2ecf20Sopenharmony_ci	.read_regr	= bpck6_read_regr,
2378c2ecf20Sopenharmony_ci	.write_block	= bpck6_write_block,
2388c2ecf20Sopenharmony_ci	.read_block	= bpck6_read_block,
2398c2ecf20Sopenharmony_ci	.connect	= bpck6_connect,
2408c2ecf20Sopenharmony_ci	.disconnect	= bpck6_disconnect,
2418c2ecf20Sopenharmony_ci	.test_port	= bpck6_test_port,
2428c2ecf20Sopenharmony_ci	.probe_unit	= bpck6_probe_unit,
2438c2ecf20Sopenharmony_ci	.log_adapter	= bpck6_log_adapter,
2448c2ecf20Sopenharmony_ci	.init_proto	= bpck6_init_proto,
2458c2ecf20Sopenharmony_ci	.release_proto	= bpck6_release_proto,
2468c2ecf20Sopenharmony_ci};
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic int __init bpck6_init(void)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	printk(KERN_INFO "bpck6: BACKPACK Protocol Driver V"BACKPACK_VERSION"\n");
2518c2ecf20Sopenharmony_ci	printk(KERN_INFO "bpck6: Copyright 2001 by Micro Solutions, Inc., DeKalb IL. USA\n");
2528c2ecf20Sopenharmony_ci	if(verbose)
2538c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "bpck6: verbose debug enabled.\n");
2548c2ecf20Sopenharmony_ci	return paride_register(&bpck6);
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic void __exit bpck6_exit(void)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	paride_unregister(&bpck6);
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
2638c2ecf20Sopenharmony_ciMODULE_AUTHOR("Micro Solutions Inc.");
2648c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("BACKPACK Protocol module, compatible with PARIDE");
2658c2ecf20Sopenharmony_cimodule_param(verbose, bool, 0644);
2668c2ecf20Sopenharmony_cimodule_init(bpck6_init)
2678c2ecf20Sopenharmony_cimodule_exit(bpck6_exit)
268