summaryrefslogtreecommitdiff
path: root/packages/linux/linux-titan-sh4
diff options
context:
space:
mode:
authorJamie Lenehan <lenehan@twibble.org>2006-07-06 14:41:19 +0000
committerOpenEmbedded Project <openembedded-devel@lists.openembedded.org>2006-07-06 14:41:19 +0000
commit4777a70d6665e319ae3723b5e75f67ed0f10997d (patch)
treed3166fa743d0506deb0825d1027c22c1e48f897e /packages/linux/linux-titan-sh4
parent9bfbf27d78e0edd5f639c2eaee98f5e506ce7cc6 (diff)
linux/linux-titan-sh4: Upgrade the titan kernel from 2.6.16 to 2.6.17 now
that the sh tree has been upgraded to 2.6.17.
Diffstat (limited to 'packages/linux/linux-titan-sh4')
-rw-r--r--packages/linux/linux-titan-sh4/.mtn2git_empty0
-rw-r--r--packages/linux/linux-titan-sh4/titan-flash.patch3157
2 files changed, 3157 insertions, 0 deletions
diff --git a/packages/linux/linux-titan-sh4/.mtn2git_empty b/packages/linux/linux-titan-sh4/.mtn2git_empty
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/packages/linux/linux-titan-sh4/.mtn2git_empty
diff --git a/packages/linux/linux-titan-sh4/titan-flash.patch b/packages/linux/linux-titan-sh4/titan-flash.patch
new file mode 100644
index 0000000000..fc633f3e05
--- /dev/null
+++ b/packages/linux/linux-titan-sh4/titan-flash.patch
@@ -0,0 +1,3157 @@
+
+Add the driver for onboard flash.
+The quality of this driver means that it has not been included in the
+upstream CVS.
+This implements the block device translation layer to match what the
+onboard firmware implements.
+
+diff -duNr linux-2.6.16-orig/drivers/block/Kconfig linux-2.6.16/drivers/block/Kconfig
+--- linux-2.6.16-orig/drivers/block/Kconfig 2006-06-29 16:12:57.000000000 +1000
++++ linux-2.6.16/drivers/block/Kconfig 2006-06-29 16:13:27.000000000 +1000
+@@ -190,6 +190,13 @@
+ To compile this driver as a module, choose M here: the
+ module will be called DAC960.
+
++config BLK_SSFDC
++ tristate "SmartMedia(TM) Driver (sm)"
++ depends on SH_TITAN
++ help
++ Say Y here if you want the SmartMedia chip enabled.
++ Otherwise say N.
++
+ config BLK_DEV_UMEM
+ tristate "Micro Memory MM5415 Battery Backed RAM support (EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL
+diff -duNr linux-2.6.16-orig/drivers/block/Makefile linux-2.6.16/drivers/block/Makefile
+--- linux-2.6.16-orig/drivers/block/Makefile 2006-06-29 16:12:57.000000000 +1000
++++ linux-2.6.16/drivers/block/Makefile 2006-06-29 16:13:27.000000000 +1000
+@@ -21,6 +21,7 @@
+ obj-$(CONFIG_BLK_CPQ_DA) += cpqarray.o
+ obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o
+ obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o
++obj-$(CONFIG_BLK_SSFDC) += ssfdc.o
+ obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o
+
+ obj-$(CONFIG_BLK_DEV_UMEM) += umem.o
+diff -duNr linux-2.6.16-orig/drivers/block/ssfdc.c linux-2.6.16/drivers/block/ssfdc.c
+--- linux-2.6.16-orig/drivers/block/ssfdc.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-2.6.16/drivers/block/ssfdc.c 2006-06-29 16:13:50.000000000 +1000
+@@ -0,0 +1,2742 @@
++/* $id: $
++ssfdc.c - Solid State Flopyy Disk Card
++
++Original source curtesy of Toshiba Corporation.
++
++Modification for use by Linux provided by Nimble Microsystems Inc.
++
++TODO:
++
++Modification History:
++
++ March 2001 - Initial port of Toshiba sources by Bill Mann
++ May 2001 - Debug of staticly linked ssfdc driver, Bill Mann
++ Nov 2001 - Reimplementation using tasklets and timers.
++ May 2002 - Partition support added.
++ Oct 2003 - Port to kernel 2.6.0
++ Mar 2004 - Stabilization refinements...
++
++Overview: The kernel interfaces to the device via the "block_device_operations
++ ssfdc_fops", the device's request handling function
++ "do_ssfdc_request(request_queue_t * q)", or by the ioctl interface ssfdc_ioctl().
++
++ do_ssfdc_request() purpose is to kickstart ssfdc_thread via a wake_up call. ssfdc_thread
++ then processes requests from the queue.
++
++ Blocks are mapped logically. So a sector read/write results in the determination
++ of the logical block address of the block containing the desired sector and the
++ corresponding physical block being accessed. Note the use of ReadBlock, WriteBlock,
++ and PhyBlock, Log2Phy[] etc.
++
++ This driver implements a wear leveling strategy where sector writes to the
++ SmartMedia causes the block which is the target of the write to be copied into a
++ new block, the new data written and the old block erased. This makes the driver
++ more complicated than a straightforward sector read/write.
++
++*/
++
++/* Section device headers */
++#define DEBUG_SSFDC 0
++#define DEBUG_SSFDC_STRUCT 0
++#define DEBUG_SSFDC_REQUEST 0
++#define DEBUG_SSFDC_READREDT 0
++#define DEBUG_SSFDC_WRITE 0
++#define DEBUG_SSFDC_WRITESECT 0
++#define DEBUG_SSFDC_WRITEBLKS 0
++#define DEBUG_SSFDC_READ 0
++#define DEBUG_SSFDC_ADDR 0
++#define DEBUG_SSFDC_ASSIGNRELEASE 0
++#define SSFDC_READINGTASKLET 0
++/* Edition Compilation Mode */
++
++#include <linux/module.h>
++
++#include <asm/delay.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++
++#include <linux/fs.h>
++#include <linux/hdreg.h>
++#include <linux/file.h>
++#include <linux/stat.h>
++#include <linux/time.h>
++#include <linux/errno.h>
++#include <linux/major.h>
++#include <linux/init.h>
++#include <linux/devfs_fs_kernel.h>
++#include <asm/uaccess.h>
++#include <asm/hardirq.h>
++#include <linux/bio.h>
++#include <linux/blkdev.h>
++#include <linux/slab.h>
++#include <linux/highmem.h>
++
++#include "ssfdc.h"
++
++#define SSFDC_MAJOR 240
++
++static int static_ssfdc_debug = 0;
++
++static DECLARE_WAIT_QUEUE_HEAD(ssfdc_wait);
++
++static struct gendisk *disks[MAX_SSFDC];
++static ssfdc_dev *ssfdc[MAX_SSFDC];
++
++static int ssfdc_open(struct inode *i_node, struct file *fptr);
++static int ssfdc_getgeo(struct block_device *bdev, struct hd_geometry *geo);
++static int ssfdc_release(struct inode *i_node, struct file *fptr);
++static int ssfdc_ioctl(struct inode *i_node, struct file *fptr, unsigned cmd, unsigned long arg);
++static int ssfdc_revalidate(struct gendisk *disk);
++void do_ssfdc_request(request_queue_t * q);
++
++static struct block_device_operations ssfdc_fops = {
++ .owner = THIS_MODULE,
++ .open = ssfdc_open,
++ .getgeo = ssfdc_getgeo,
++ .release = ssfdc_release,
++ .ioctl = ssfdc_ioctl,
++ // bjm out .revalidate_disk = ssfdc_revalidate,
++};
++
++
++/***************************************************************************
++ BIT Control Macro
++ ***************************************************************************/
++static char BitData[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 };
++#define SetBit(a,b) (a[(unsigned char)((b)/8)]|= BitData[(b)%8])
++#define ClrBit(a,b) (a[(unsigned char)((b)/8)]&=~BitData[(b)%8])
++#define ChkBit(a,b) (a[(unsigned char)((b)/8)] & BitData[(b)%8])
++
++/***************************************************************************/
++static int MediaReadSector(ssfdc_dev *, struct request *, char *, long,int);
++static int MediaWriteSector(ssfdc_dev *, struct request *, char *, long,int);
++
++/***************************************************************************/
++static int CheckLogCHS(ssfdc_dev *,unsigned int *,unsigned char *,unsigned char *);
++static int CheckMediaWP(ssfdc_dev *);
++static int ConvMediaAddr(ssfdc_dev *,long);
++static int IncMediaAddr(ssfdc_dev *);
++static int WriteReqInCurrBlk(ssfdc_dev *, long, int *);
++/******************************************/
++/******************************************/
++static int AssignWriteBlock(ssfdc_dev *, int);
++/******************************************/
++/******************************************/
++static int SetPhyFmtValue(ssfdc_dev *);
++static int SearchCIS(ssfdc_dev *,unsigned int *);
++static int MakeLogTable(ssfdc_dev *,unsigned int);
++/******************************************/
++static int MarkFailPhyOneBlock(ssfdc_dev *);
++
++static void _ReadSsfdcBuf(ssfdc_dev *, unsigned char *databuf,unsigned char *redundant);
++static void _WriteSsfdcBuf(ssfdc_dev *,unsigned char *,unsigned char *);
++static void _ReadSsfdcWord(ssfdc_dev *,unsigned int *);
++static void _ReadRedtSsfdcBuf(ssfdc_dev *, unsigned char *redundant);
++static void _WriteRedtSsfdcBuf(ssfdc_dev*, unsigned char *redundant);
++
++/***************************************************************************/
++static void _SetSsfdcCmd(ssfdc_dev *, unsigned char);
++static void _SetSsfdcAddr(ssfdc_dev *, unsigned char);
++static void _SetSsfdcBlock(ssfdc_dev *);
++static void _SetSsfdcChip(ssfdc_dev *);
++static void _SetSsfdcStandby(ssfdc_dev *);
++static int _CheckSsfdcBusy(ssfdc_dev *, unsigned int);
++static int _CheckSsfdcStatus(ssfdc_dev *);
++static void _ResetSsfdcErr(ssfdc_dev *psm);
++static unsigned char _CheckDevCode(unsigned char);
++void SsfdcReset(ssfdc_dev *);
++void CntReset(ssfdc_dev *);
++
++static char BitCount(unsigned char);
++static char BitCountWord(unsigned int);
++
++static void _WaitTimer(long int);
++typedef void (*timeout_fn)(unsigned long);
++static void ssfdc_rw_request(ssfdc_dev *psm, struct request *req);
++static int ssfdc_end_request(ssfdc_dev *psm, struct request *req, int status);
++static void ssfdc_terminate_request(ssfdc_dev *psm, struct request *req);
++static struct request *ssfdc_get_request(ssfdc_dev *psm);
++
++/* debugging utils etc. */
++
++#if DEBUG_SSFDC
++static void dump_ssfdc_state(ssfdc_dev * psm);
++#endif
++
++/* end of debugging utils etc. */
++
++/* our tasklets */
++/* top level R/W initiation tasklet */
++static void initxfer(unsigned long);
++#if 0 // use thread and not a tasklet
++DECLARE_TASKLET(initxfer_tasklet0, initxfer, 0);
++#ifdef CONFIG_SH_NIMBLE_MINI
++DECLARE_TASKLET(initxfer_tasklet1, initxfer, 1);
++#endif
++#endif
++
++/* Sector Write Tasklets, This group includes a readcopy tasklet for block copies...*/
++
++/* Tasklet to read a sector into a temporary buffer for later write */
++
++/* power is turned on, and then left on for TIMER_ON_TIMEOUT */
++// bjm debug struct timer_list mediachange_timer;
++// bjm debug static void mediachangetest(unsigned long);
++
++// bjm out
++// bjm out struct timer_list waiting_timer;
++static void waiting_timeout(unsigned long);
++
++/******************************************************************************/
++static void trans_result \
++ (unsigned char,unsigned char,unsigned char *,unsigned char *);
++static void calculate_ecc \
++ (unsigned char *,unsigned char *,unsigned char *,unsigned char *,unsigned char *);
++static unsigned char correct_data \
++ (unsigned char *,unsigned char *,unsigned char,unsigned char,unsigned char);
++
++ /* CP0-CP5 code table */
++static unsigned char ecctable[256] = {
++ 0x00,0x55,0x56,0x03,0x59,0x0C,0x0F,0x5A,0x5A,0x0F,0x0C,0x59,0x03,0x56,0x55,0x00,
++ 0x65,0x30,0x33,0x66,0x3C,0x69,0x6A,0x3F,0x3F,0x6A,0x69,0x3C,0x66,0x33,0x30,0x65,
++ 0x66,0x33,0x30,0x65,0x3F,0x6A,0x69,0x3C,0x3C,0x69,0x6A,0x3F,0x65,0x30,0x33,0x66,
++ 0x03,0x56,0x55,0x00,0x5A,0x0F,0x0C,0x59,0x59,0x0C,0x0F,0x5A,0x00,0x55,0x56,0x03,
++ 0x69,0x3C,0x3F,0x6A,0x30,0x65,0x66,0x33,0x33,0x66,0x65,0x30,0x6A,0x3F,0x3C,0x69,
++ 0x0C,0x59,0x5A,0x0F,0x55,0x00,0x03,0x56,0x56,0x03,0x00,0x55,0x0F,0x5A,0x59,0x0C,
++ 0x0F,0x5A,0x59,0x0C,0x56,0x03,0x00,0x55,0x55,0x00,0x03,0x56,0x0C,0x59,0x5A,0x0F,
++ 0x6A,0x3F,0x3C,0x69,0x33,0x66,0x65,0x30,0x30,0x65,0x66,0x33,0x69,0x3C,0x3F,0x6A,
++ 0x6A,0x3F,0x3C,0x69,0x33,0x66,0x65,0x30,0x30,0x65,0x66,0x33,0x69,0x3C,0x3F,0x6A,
++ 0x0F,0x5A,0x59,0x0C,0x56,0x03,0x00,0x55,0x55,0x00,0x03,0x56,0x0C,0x59,0x5A,0x0F,
++ 0x0C,0x59,0x5A,0x0F,0x55,0x00,0x03,0x56,0x56,0x03,0x00,0x55,0x0F,0x5A,0x59,0x0C,
++ 0x69,0x3C,0x3F,0x6A,0x30,0x65,0x66,0x33,0x33,0x66,0x65,0x30,0x6A,0x3F,0x3C,0x69,
++ 0x03,0x56,0x55,0x00,0x5A,0x0F,0x0C,0x59,0x59,0x0C,0x0F,0x5A,0x00,0x55,0x56,0x03,
++ 0x66,0x33,0x30,0x65,0x3F,0x6A,0x69,0x3C,0x3C,0x69,0x6A,0x3F,0x65,0x30,0x33,0x66,
++ 0x65,0x30,0x33,0x66,0x3C,0x69,0x6A,0x3F,0x3F,0x6A,0x69,0x3C,0x66,0x33,0x30,0x65,
++ 0x00,0x55,0x56,0x03,0x59,0x0C,0x0F,0x5A,0x5A,0x0F,0x0C,0x59,0x03,0x56,0x55,0x00
++};
++
++#define BIT7 0x80
++#define BIT6 0x40
++#define BIT5 0x20
++#define BIT4 0x10
++#define BIT3 0x08
++#define BIT2 0x04
++#define BIT1 0x02
++#define BIT0 0x01
++
++#define BIT1BIT0 0x03
++#define BIT23 0x00800000L
++#define MASK_CPS 0x3f
++#define CORRECTABLE 0x00555554L
++
++/*
++ Transfer result
++ LP14,12,10,... & LP15,13,11,... -> LP15,14,13,... & LP7,6,5,..
++*/
++static void trans_result(reg2,reg3,ecc1,ecc2)
++unsigned char reg2; /* LP14,LP12,LP10,... */
++unsigned char reg3; /* LP15,LP13,LP11,... */
++unsigned char *ecc1; /* LP15,LP14,LP13,... */
++unsigned char *ecc2; /* LP07,LP06,LP05,... */
++{
++ unsigned char a; /* Working for reg2,reg3 */
++ unsigned char b; /* Working for ecc1,ecc2 */
++ unsigned char i; /* For counting */
++
++ a=BIT7; b=BIT7; /* 80h=10000000b */
++ *ecc1=*ecc2=0; /* Clear ecc1,ecc2 */
++ for(i=0; i<4; ++i) {
++ if ((reg3&a)!=0) *ecc1|=b; /* LP15,13,11,9 -> ecc1 */
++ b=b>>1; /* Right shift */
++ if ((reg2&a)!=0) *ecc1|=b; /* LP14,12,10,8 -> ecc1 */
++ b=b>>1; /* Right shift */
++ a=a>>1; /* Right shift */
++ }
++ b=BIT7; /* 80h=10000000b */
++ for(i=0; i<4; ++i) {
++ if ((reg3&a)!=0) *ecc2|=b; /* LP7,5,3,1 -> ecc2 */
++ b=b>>1; /* Right shift */
++ if ((reg2&a)!=0) *ecc2|=b; /* LP6,4,2,0 -> ecc2 */
++ b=b>>1; /* Right shift */
++ a=a>>1; /* Right shift */
++ }
++}
++
++
++/*
++ Calculating ECC
++ data[0-255] -> ecc1,ecc2,ecc3 using CP0-CP5 code table[0-255]
++*/
++static void calculate_ecc(table,data,ecc1,ecc2,ecc3)
++unsigned char *table; /* CP0-CP5 code table */
++unsigned char *data; /* DATA */
++unsigned char *ecc1; /* LP15,LP14,LP13,... */
++unsigned char *ecc2; /* LP07,LP06,LP05,... */
++unsigned char *ecc3; /* CP5,CP4,CP3,...,"1","1" */
++{
++ unsigned int i; /* For counting */
++ unsigned char a; /* Working for table */
++ unsigned char reg1; /* D-all,CP5,CP4,CP3,... */
++ unsigned char reg2; /* LP14,LP12,L10,... */
++ unsigned char reg3; /* LP15,LP13,L11,... */
++
++ reg1=reg2=reg3=0; /* Clear parameter */
++
++ for(i=0; i<256; ++i) {
++ a=table[data[i]]; /* Get CP0-CP5 code from table */
++ reg1^=(a&MASK_CPS); /* XOR with a */
++ if ((a&BIT6)!=0) { /* If D_all(all bit XOR) = 1 */
++ reg3^=(unsigned char)i; /* XOR with counter */
++ reg2^=~((unsigned char)i); /* XOR with inv. of counter */
++ }
++ }
++
++ /* Trans LP14,12,10,... & LP15,13,11,... -> LP15,14,13,... & LP7,6,5,.. */
++ trans_result(reg2,reg3,ecc1,ecc2);
++
++ *ecc1=~(*ecc1); *ecc2=~(*ecc2); /* Inv. ecc2 & ecc3 */
++ *ecc3=((~reg1)<<2)|BIT1BIT0; /* Make TEL format */
++}
++
++static unsigned char correct_data(data,eccdata,ecc1,ecc2,ecc3)
++unsigned char *data; /* DATA */
++unsigned char *eccdata; /* ECC DATA */
++unsigned char ecc1; /* LP15,LP14,LP13,... */
++unsigned char ecc2; /* LP07,LP06,LP05,... */
++unsigned char ecc3; /* CP5,CP4,CP3,...,"1","1" */
++{
++ unsigned long l; /* Working to check d */
++ unsigned long d; /* Result of comparison */
++ unsigned int i; /* For counting */
++ unsigned char d1,d2,d3; /* Result of comparison */
++ unsigned char a; /* Working for add */
++ unsigned char add; /* Byte address of cor. DATA */
++ unsigned char b; /* Working for bit */
++ unsigned char bit; /* Bit address of cor. DATA */
++
++ d1=ecc1^eccdata[1]; d2=ecc2^eccdata[0]; /* Compare LP's */
++ d3=ecc3^eccdata[2]; /* Comapre CP's */
++ d=((unsigned long)d1<<16) /* Result of comparison */
++ +((unsigned long)d2<<8)
++ +(unsigned long)d3;
++
++ if (d==0) return(0); /* If No error, return */
++ if (((d^(d>>1))&CORRECTABLE)==CORRECTABLE) { /* If correctable */
++ l=BIT23;
++ add=0; /* Clear parameter */
++ a=BIT7;
++ for(i=0; i<8; ++i) { /* Checking 8 bit */
++ if ((d&l)!=0) add|=a; /* Make byte address from LP's */
++ l>>=2; a>>=1; /* Right Shift */
++ }
++ bit=0; /* Clear parameter */
++ b=BIT2;
++ for(i=0; i<3; ++i) { /* Checking 3 bit */
++ if ((d&l)!=0) bit|=b; /* Make bit address from CP's */
++ l>>=2; b>>=1; /* Right shift */
++ }
++ b=BIT0;
++ data[add]^=(b<<bit); /* Put corrected data */
++ return(1);
++ }
++ i=0; /* Clear count */
++ d&=0x00ffffffL; /* Masking */
++ while(d) { /* If d=0 finish counting */
++ if (d&BIT0) ++i; /* Count number of 1 bit */
++ d>>=1; /* Right shift */
++ }
++ if (i==1) { /* If ECC error */
++ eccdata[1]=ecc1; eccdata[0]=ecc2; /* Put right ECC code */
++ eccdata[2]=ecc3;
++ return(2);
++ }
++ return(3); /* Uncorrectable error */
++}
++/***************************************************************************
++ Common Subroutine
++ ***************************************************************************/
++char BitCount(unsigned char cdata)
++{
++ char bitcount=0;
++ while(cdata) {
++ bitcount+=(cdata &0x01);
++ cdata /=2;
++ }
++ return(bitcount);
++}
++
++char BitCountWord(unsigned int cdata)
++{
++ char bitcount=0;
++ while(cdata) {
++ bitcount+=(cdata &0x01);
++ cdata /=2;
++ }
++ return(bitcount);
++}
++
++/***************************************************************************/
++void StringCopy(char *stringA, char *stringB, int count)
++{
++ int i;
++ for(i=0; i<count; i++)
++ *stringA++ = *stringB++;
++}
++
++int StringCmp(char *stringA, char *stringB, int count)
++{
++ int i;
++ for (i=0;i<count;i++)
++ if (*stringA++ != *stringB++) return(ERROR);
++ return(SUCCESS);
++}
++/***************************************************************************/
++int CheckDataBlank(unsigned char *redundant)
++{
++ char i;
++ for(i=0; i<REDTSIZE; i++)
++ if(*redundant++!=0xFF) return(ERROR);
++ return(SUCCESS);
++}
++
++int CheckFailBlock(unsigned char *redundant)
++{
++ redundant+=REDT_BLOCK;
++ if(*redundant==0xFF) return(SUCCESS);
++ if(! *redundant) return(ERROR);
++ if(BitCount(*redundant)<7) return(ERROR);
++ return(SUCCESS);
++}
++
++int CheckCisBlock(unsigned char *redundant)
++{
++ if(! (*(redundant+REDT_ADDR1H)|*(redundant+REDT_ADDR1L)))
++ return(SUCCESS);
++ if(! (*(redundant+REDT_ADDR2H)|*(redundant+REDT_ADDR2L)))
++ return(SUCCESS);
++ return(ERROR);
++}
++
++int CheckDataStatus(unsigned char *redundant)
++{
++ redundant+=REDT_DATA;
++ if(*redundant==0xFF) return(SUCCESS);
++ if(! *redundant) return(ERROR);
++ if(BitCount(*redundant)<5) return(ERROR);
++ return(SUCCESS);
++}
++
++int LoadLogBlockAddr(ssfdc_dev *psm)
++{
++ unsigned int addr1,addr2;
++ addr1=*(psm->Redundant+REDT_ADDR1H)*0x100+*(psm->Redundant+REDT_ADDR1L);
++ addr2=*(psm->Redundant+REDT_ADDR2H)*0x100+*(psm->Redundant+REDT_ADDR2L);
++ if(addr1==addr2)
++ if((addr1 &0xF000)==0x1000)
++ { psm->LogBlock=(addr1 &0x0FFF)/2; return(SUCCESS); }
++ if(BitCountWord(addr1^addr2)>1) return(ERROR);
++ if((addr1 &0xF000)==0x1000)
++ if(! (BitCountWord(addr1) &0x0001))
++ { psm->LogBlock=(addr1 &0x0FFF)/2; return(SUCCESS); }
++ if((addr2 &0xF000)==0x1000)
++ if(! (BitCountWord(addr2) &0x0001))
++ { psm->LogBlock=(addr2 &0x0FFF)/2; return(SUCCESS); }
++ return(ERROR);
++}
++/***************************************************************************/
++void ClrRedundantData(unsigned char *redundant)
++{
++ char i;
++ for(i=0; i<REDTSIZE; i++) *(redundant+i)=0xFF;
++}
++
++/***************************************************************************/
++void SetLogBlockAddr(ssfdc_dev *psm, unsigned char *redundant)
++{
++ unsigned int addr;
++ *(redundant+REDT_BLOCK)=0xFF;
++ *(redundant+REDT_DATA) =0xFF;
++ addr=psm->LogBlock*2+0x1000;
++ if((BitCountWord(addr)%2)) addr++;
++ *(redundant+REDT_ADDR1H)=*(redundant+REDT_ADDR2H)=addr/0x100;
++ *(redundant+REDT_ADDR1L)=*(redundant+REDT_ADDR2L)=(unsigned char)addr;
++}
++
++void SetFailBlock(unsigned char *redundant)
++{
++ char i;
++ for(i=0; i<REDTSIZE; i++)
++ *redundant++=((i==REDT_BLOCK)?0xF0:0xFF);
++}
++
++void SetDataStatus(unsigned char *redundant)
++{
++ redundant+=REDT_DATA;
++ *redundant=0x00;
++}
++
++
++/***************************************************************************
++ NAND Memory (SmartMedia) Control Subroutine
++ ***************************************************************************/
++static void _SetSsfdcCmd(ssfdc_dev *psm, unsigned char cmd)
++{
++ _HwSetCmd(psm);
++ _HwOutData(psm,cmd);
++ _HwSetData(psm);
++}
++
++static void _SetSsfdcAddr(ssfdc_dev *psm, unsigned char add)
++{
++ unsigned int addr;
++
++#if DEBUG_SSFDC_ADDR
++ printk(KERN_DEBUG "_SetSsfdcAddr() Zone %d LogBlock %d PhyBlock %d Sector %d\n",
++ psm->Zone,psm->LogBlock,psm->PhyBlock,psm->Sector);
++#endif
++ addr=(unsigned int)psm->Zone*psm->MaxBlocks+psm->PhyBlock;
++ addr=addr*(unsigned int)psm->MaxSectors+psm->Sector;
++ if((psm->Attribute &MPS)==PS256) /* for 256byte/page */
++ addr=addr*2+(unsigned int)add;
++/*-----------------------------------------------*/
++ _HwSetAddr(psm);
++ _HwOutData(psm,0x00);
++ _HwOutData(psm,(unsigned char)addr);
++ _HwOutData(psm,(unsigned char)(addr/0x0100));
++ if((psm->Attribute &MADC)==AD4CYC)
++ _HwOutData(psm,(unsigned char)(psm->Zone/2)); /* Patch */
++ _HwSetData(psm);
++}
++
++static void _SetSsfdcBlock(ssfdc_dev *psm)
++{
++ unsigned int addr;
++#if DEBUG_SSFDC_ASSIGNRELEASE
++ printk(KERN_DEBUG "_SetSsfdcBlock() set card addr to PhyBlock %d\n", psm->PhyBlock);
++#endif
++ addr=(unsigned int)psm->Zone*psm->MaxBlocks+psm->PhyBlock;
++ addr=addr*(unsigned int)psm->MaxSectors;
++ if((psm->Attribute &MPS)==PS256) /* for 256byte/page */
++ addr=addr*2;
++/*-----------------------------------------------*/
++ _HwSetAddr(psm);
++ _HwOutData(psm,(unsigned char)addr);
++ _HwOutData(psm,(unsigned char)(addr/0x0100));
++ if((psm->Attribute &MADC)==AD4CYC)
++ _HwOutData(psm,(unsigned char)(psm->Zone/2)); /* Patch */
++ _HwSetData(psm);
++}
++
++static inline void _SetSsfdcStandby(ssfdc_dev *psm)
++{
++ _HwSetStandby(psm);
++}
++
++static int _CheckSsfdcStatus(ssfdc_dev *psm)
++{
++ int status;
++ if((status=_HwInData(psm)) & WR_FAIL) {
++ printk(KERN_DEBUG "_CheckSsfdcStatus() error %x\n", status);
++ return(ERROR);
++ }
++ return(SUCCESS);
++}
++
++static void _ResetSsfdcErr(ssfdc_dev *psm)
++{
++ _HwSetCmd(psm);
++ _HwOutData(psm,SSFDC_RST_CHIP);
++ _HwSetData(psm);
++ while(1) {
++ udelay(30);
++ if(! _HwChkBusy(psm)) break;
++ }
++ _HwSetStandby(psm);
++}
++
++static void waiting_timeout(unsigned long psm)
++{
++ // enable the wakeup signal!
++ wake_up(&((ssfdc_dev *)psm)->thread_wq);
++}
++
++/*
++ _CheckSsfdcBusy()
++
++ set a timer in jiffies from int time x .1ms
++*/
++
++static int _CheckSsfdcBusy(ssfdc_dev *psm, unsigned int time)
++{
++ unsigned long incr_div = 4;
++ unsigned long incr_us = time / incr_div,
++ jticks=time/(MSEC * JIFFY_TICK_MS);
++ unsigned long tick_retried=0, wrap_flag, expires;
++
++ if (!jticks) {
++ // small delay first to test completion
++ do {
++ udelay(incr_us);
++ if (!_HwChkBusy(psm))
++ return(SUCCESS);
++ } while (incr_div--);
++ return(ERROR);
++ }
++
++ // Block the wakeup signal?
++
++one_more_time:
++ expires = jiffies + jticks;
++ wrap_flag = ( expires < jiffies);
++
++ do {
++ wait_event_interruptible_timeout(psm->thread_wq, 0, jticks);
++ if (!_HwChkBusy(psm)) {
++ return(SUCCESS);
++ }
++ } while (wrap_flag ? expires <= jiffies : expires >= jiffies);
++
++#if 1
++ // Is the chip not busy? If so its an ERROR
++ if (!_HwChkBusy(psm)) {
++ return(SUCCESS);
++ }
++ else {
++ // if we came back, give us one more tick/time
++ if (! tick_retried ) {
++ tick_retried = 1;
++ jticks = 0;
++ printk(".");
++ goto one_more_time;
++ }
++ return(ERROR);
++ }
++#endif
++}
++
++static void _SetSsfdcChip(ssfdc_dev *psm)
++{
++ _HwSetAddr(psm);
++ _HwOutData(psm,0x00);
++ _HwSetData(psm);
++}
++/***************************************************************************
++ NAND Memory (SmartMedia) Buffer Data Xfer Subroutine
++ ***************************************************************************/
++static void _ReadSsfdcBuf(ssfdc_dev *psm,unsigned char *databuf,unsigned char *redundant)
++{
++ int i;
++ for(i=0x00;i<(((psm->Attribute &MPS)==PS256)?0x100:0x200);i++)
++ *databuf++ =_HwInData(psm);
++ for(i=0x00;i<(((psm->Attribute &MPS)==PS256)?0x08:0x10);i++)
++ *redundant++ =_HwInData(psm);
++}
++
++static void _WriteSsfdcBuf(ssfdc_dev *psm, unsigned char *databuf,unsigned char *redundant)
++{
++ int i;
++ for(i=0x00;i<(((psm->Attribute &MPS)==PS256)?0x100:0x200);i++)
++ _HwOutData(psm,*databuf++);
++ for(i=0x00;i<(((psm->Attribute &MPS)==PS256)?0x08:0x10);i++)
++ _HwOutData(psm,*redundant++);
++}
++
++static void _ReadSsfdcWord(ssfdc_dev *psm, unsigned int *pdata)
++{
++ *pdata =_HwInData(psm)*0x100;
++ *pdata|=(unsigned char)_HwInData(psm);
++}
++
++static void _ReadRedtSsfdcBuf(ssfdc_dev *psm,unsigned char *redundant)
++{
++ int i;
++ for(i=0x00;i<(((psm->Attribute &MPS)==PS256)?0x08:0x10);i++)
++ redundant[i] =_HwInData(psm);
++}
++
++static void _WriteRedtSsfdcBuf(ssfdc_dev *psm, unsigned char *redundant)
++{
++ char i;
++ for(i=0x00;i<(((psm->Attribute &MPS)==PS256)?0x08:0x10);i++)
++ _HwOutData(psm,*redundant++);
++}
++
++/***************************************************************************
++ Timer Control Subroutine
++ ***************************************************************************/
++#define SHORT_DELAY 1
++
++
++
++
++void _GetDateTime(char *date)
++{
++}
++
++/*
++_WaitTimer(long time) time is in ticks.
++*/
++
++static inline void _WaitTimer(long time)
++{
++}
++
++/***************************************************************************
++ SmartMedia Function Command Subroutine
++ ***************************************************************************/
++void SsfdcReset(ssfdc_dev *psm)
++{
++ _SetSsfdcCmd(psm, SSFDC_RST_CHIP);
++ _CheckSsfdcBusy(psm,BUSY_RESET);
++ _SetSsfdcCmd(psm,SSFDC_READ);
++ _CheckSsfdcBusy(psm,BUSY_READ);
++ _SetSsfdcStandby(psm);
++}
++
++void SsfdcWriteRedtMode(ssfdc_dev *psm)
++{
++ _SetSsfdcCmd(psm,SSFDC_RST_CHIP);
++ _CheckSsfdcBusy(psm,BUSY_RESET);
++ _SetSsfdcCmd(psm,SSFDC_READ_REDT);
++ _CheckSsfdcBusy(psm,BUSY_READ);
++ _SetSsfdcStandby(psm);
++}
++
++void SsfdcReadID(ssfdc_dev *psm, unsigned int *pid)
++{
++ _SetSsfdcCmd(psm,SSFDC_READ_ID);
++ _SetSsfdcChip(psm);
++ _ReadSsfdcWord(psm,pid);
++ _SetSsfdcStandby(psm);
++}
++
++int SsfdcCheckStatus(ssfdc_dev *psm)
++{
++ _SetSsfdcCmd(psm,SSFDC_RDSTATUS);
++ if(_CheckSsfdcStatus(psm))
++ { _SetSsfdcStandby(psm); return(ERROR); }
++ _SetSsfdcStandby(psm);
++ return(SUCCESS);
++}
++
++int SsfdcReadSect(ssfdc_dev *psm, unsigned char *buf,unsigned char *redundant)
++{
++#if DEBUG_SSFDC_READ
++ printk(KERN_DEBUG "SsfdcReadSect() - Zone %d LogBlock %d, PhyBlock %d, Sector %d\n",
++ psm->Zone, psm->LogBlock, psm->PhyBlock, psm->Sector);
++#endif
++ _SetSsfdcCmd(psm,SSFDC_READ);
++ _SetSsfdcAddr(psm, EVEN);
++ if(_CheckSsfdcBusy(psm,BUSY_READ))
++ { _ResetSsfdcErr(psm); return(ERROR); }
++ _ReadSsfdcBuf(psm,buf,redundant);
++ if(_CheckSsfdcBusy(psm,BUSY_READ))
++ { _ResetSsfdcErr(psm); return(ERROR); }
++ if((psm->Attribute &MPS)==PS256) {
++ _SetSsfdcCmd(psm,SSFDC_READ);
++ _SetSsfdcAddr(psm, ODD);
++ if(_CheckSsfdcBusy(psm,BUSY_READ))
++ { _ResetSsfdcErr(psm); return(ERROR); }
++ _ReadSsfdcBuf(psm,buf+0x100,redundant+0x08);
++ if(_CheckSsfdcBusy(psm,BUSY_READ))
++ { _ResetSsfdcErr(psm); return(ERROR); }
++ }
++ _SetSsfdcStandby(psm);
++ return(SUCCESS);
++}
++
++int SsfdcWriteSect(ssfdc_dev *psm, unsigned char *buf, unsigned char *redundant)
++{
++#if DEBUG_SSFDC_WRITESECT
++ printk(KERN_DEBUG "SsfdcWriteSect() - Zone %d LogBlock %d, PhyBlock %d, Sector %d\n", \
++ psm->Zone, psm->LogBlock, psm->PhyBlock, psm->Sector);
++#endif
++ _SetSsfdcCmd(psm,SSFDC_WRDATA);
++ _SetSsfdcAddr(psm,EVEN);
++ _WriteSsfdcBuf(psm,buf,redundant);
++ _SetSsfdcCmd(psm,SSFDC_WRITE);
++ if(_CheckSsfdcBusy(psm,BUSY_PROG))
++ { _ResetSsfdcErr(psm);
++#if DEBUG_SSFDC_WRITESECT
++ printk(KERN_DEBUG "SsfdcWriteSect() e 1\n");
++#endif
++ return(ERROR); }
++ if((psm->Attribute &MPS)==PS256) {
++ _SetSsfdcCmd(psm,SSFDC_RDSTATUS);
++ if(_CheckSsfdcStatus(psm))
++ { _SetSsfdcStandby(psm); return(SUCCESS); }
++ _SetSsfdcCmd(psm,SSFDC_WRDATA);
++ _SetSsfdcAddr(psm,ODD);
++ _WriteSsfdcBuf(psm,buf+0x100,redundant+0x08);
++ _SetSsfdcCmd(psm,SSFDC_WRITE);
++ if(_CheckSsfdcBusy(psm,BUSY_PROG))
++ { _ResetSsfdcErr(psm);
++#if DEBUG_SSFDC_WRITESECT
++ printk(KERN_DEBUG "SsfdcWriteSect() e 2\n");
++#endif
++ return(ERROR); }
++ }
++ _SetSsfdcStandby(psm);
++ return(SUCCESS);
++}
++
++int SsfdcEraseBlock(ssfdc_dev *psm)
++{
++ _SetSsfdcCmd(psm,SSFDC_ERASE1);
++ _SetSsfdcBlock(psm);
++ _SetSsfdcCmd(psm,SSFDC_ERASE2);
++ if(_CheckSsfdcBusy(psm,BUSY_ERASE) || SsfdcCheckStatus(psm)) {
++ _ResetSsfdcErr(psm);
++ return(ERROR);
++ }
++ _SetSsfdcStandby(psm);
++ return(SUCCESS);
++}
++
++int SsfdcReadRedtData(ssfdc_dev *psm, unsigned char *redundant)
++{
++#if DEBUG_SSFDC_READREDT
++ printk(KERN_DEBUG " +");
++#endif
++ _SetSsfdcCmd(psm,SSFDC_READ_REDT);
++ _SetSsfdcAddr(psm,EVEN);
++ if(_CheckSsfdcBusy(psm,BUSY_READ))
++ { _ResetSsfdcErr(psm);
++#if DEBUG_SSFDC_READREDT
++ printk(KERN_DEBUG " e 1\n");
++#endif
++ return(ERROR); }
++ _ReadRedtSsfdcBuf(psm, redundant);
++ if(_CheckSsfdcBusy(psm,BUSY_READ))
++ { _ResetSsfdcErr(psm);
++#if DEBUG_SSFDC_READREDT
++ printk(KERN_DEBUG " e 2\n");
++#endif
++ return(ERROR); }
++ if((psm->Attribute &MPS)==PS256) {
++ _SetSsfdcCmd(psm,SSFDC_READ_REDT);
++ _SetSsfdcAddr(psm,ODD);
++ if(_CheckSsfdcBusy(psm,BUSY_READ))
++ { _ResetSsfdcErr(psm);
++#if DEBUG_SSFDC_READREDT
++ printk(KERN_DEBUG " e 3\n");
++#endif
++
++ return(ERROR); }
++ _ReadRedtSsfdcBuf(psm, redundant+0x08);
++ if(_CheckSsfdcBusy(psm,BUSY_READ))
++ { _ResetSsfdcErr(psm);
++#if DEBUG_SSFDC_READREDT
++ printk(KERN_DEBUG " e 4\n");
++#endif
++ return(ERROR); }
++ }
++ _SetSsfdcStandby(psm);
++#if DEBUG_SSFDC_READREDT
++ printk(KERN_DEBUG " -\n");
++#endif
++ return(SUCCESS);
++}
++
++int SsfdcWriteRedtData(ssfdc_dev *psm, unsigned char *redundant)
++{
++ _SetSsfdcCmd(psm,SSFDC_WRDATA);
++ _SetSsfdcAddr(psm,EVEN);
++ _WriteRedtSsfdcBuf(psm,redundant);
++ _SetSsfdcCmd(psm,SSFDC_WRITE);
++ if(_CheckSsfdcBusy(psm,BUSY_PROG))
++ { _ResetSsfdcErr(psm); return(ERROR); }
++ if((psm->Attribute &MPS)==PS256) {
++ _SetSsfdcCmd(psm,SSFDC_RDSTATUS);
++ if(_CheckSsfdcStatus(psm))
++ { _SetSsfdcStandby(psm); return(SUCCESS); }
++ _SetSsfdcCmd(psm,SSFDC_WRDATA);
++ _SetSsfdcAddr(psm,ODD);
++ _WriteRedtSsfdcBuf(psm,redundant+0x08);
++ _SetSsfdcCmd(psm,SSFDC_WRITE);
++ if(_CheckSsfdcBusy(psm,BUSY_PROG))
++ { _ResetSsfdcErr(psm); return(ERROR); }
++ }
++ _SetSsfdcStandby(psm);
++ return(SUCCESS);
++}
++
++/***************************************************************************
++ SmartMedia ID Code Check & Mode Set Subroutine
++ ***************************************************************************/
++int SetSsfdcModel(ssfdc_dev *psm, unsigned char dcode)
++{
++ switch(_CheckDevCode(dcode)) {
++ case SSFDC1MB:
++ psm->Model = SSFDC1MB;
++ psm->Attribute = FLASH | AD3CYC | BS16 | PS256;
++ psm->MaxZones = 1;
++ psm->MaxBlocks = 256;
++ psm->MaxLogBlocks = 250;
++ psm->MaxSectors = 8;
++ break;
++ case SSFDC2MB:
++ psm->Model = SSFDC2MB;
++ psm->Attribute = FLASH | AD3CYC | BS16 | PS256;
++ psm->MaxZones = 1;
++ psm->MaxBlocks = 512;
++ psm->MaxLogBlocks = 500;
++ psm->MaxSectors = 8;
++ break;
++ case SSFDC4MB:
++ psm->Model = SSFDC4MB;
++ psm->Attribute = FLASH | AD3CYC | BS16 | PS512;
++ psm->MaxZones = 1;
++ psm->MaxBlocks = 512;
++ psm->MaxLogBlocks = 500;
++ psm->MaxSectors = 16;
++ break;
++ case SSFDC8MB:
++ psm->Model = SSFDC8MB;
++ psm->Attribute = FLASH | AD3CYC | BS16 | PS512;
++ psm->MaxZones = 1;
++ psm->MaxBlocks = 1024;
++ psm->MaxLogBlocks = 1000;
++ psm->MaxSectors = 16;
++ break;
++ case SSFDC16MB:
++ psm->Model = SSFDC16MB;
++ psm->Attribute = FLASH | AD3CYC | BS32 | PS512;
++ psm->MaxZones = 1;
++ psm->MaxBlocks = 1024;
++ psm->MaxLogBlocks = 1000;
++ psm->MaxSectors = 32;
++ break;
++ case SSFDC32MB:
++ psm->Model = SSFDC32MB;
++ psm->Attribute = FLASH | AD3CYC | BS32 | PS512;
++ psm->MaxZones = 2;
++ psm->MaxBlocks = 1024;
++ psm->MaxLogBlocks = 1000;
++ psm->MaxSectors = 32;
++ break;
++ case SSFDC64MB:
++ psm->Model = SSFDC64MB;