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