/*
* Driver for Alauda-based card readers
*
* Current development and maintenance by:
* (c) 2005 Daniel Drake <dsd@gentoo.org>
*
* The 'Alauda' is a chip manufacturered by RATOC for OEM use.
*
* Alauda implements a vendor-specific command set to access two media reader
* ports (XD, SmartMedia). This driver converts SCSI commands to the commands
* which are accepted by these devices.
*
* The driver was developed through reverse-engineering, with the help of the
* sddr09 driver which has many similarities, and with some help from the
* (very old) vendor-supplied GPL sma03 driver.
*
* For protocol info, see http://alauda.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include "usb.h"
#include "transport.h"
#include "protocol.h"
#include "debug.h"
#include "alauda.h"
#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
#define LSB_of(s) ((s)&0xFF)
#define MSB_of(s) ((s)>>8)
#define MEDIA_PORT(us) us->srb->device->lun
#define MEDIA_INFO(us) ((struct alauda_info *)us->extra)->port[MEDIA_PORT(us)]
#define PBA_LO(pba) ((pba & 0xF) << 5)
#define PBA_HI(pba) (pba >> 3)
#define PBA_ZONE(pba) (pba >> 11)
/*
* Media handling
*/
struct alauda_card_info {
unsigned char id; /* id byte */
unsigned char chipshift; /* 1<<cs bytes total capacity */
unsigned char pageshift; /* 1<<ps bytes in a page */
unsigned char blockshift; /* 1<<bs pages per block */
unsigned char zoneshift; /* 1<<zs blocks per zone */
};
static struct alauda_card_info alauda_card_ids[] = {
/* NAND flash */
{ 0x6e, 20, 8, 4, 8}, /* 1 MB */
{ 0xe8, 20, 8, 4, 8}, /* 1 MB */
{ 0xec, 20, 8, 4, 8}, /* 1 MB */
{ 0x64, 21, 8, 4, 9}, /* 2 MB */
{ 0xea, 21, 8, 4, 9}, /* 2 MB */
{ 0x6b, 22, 9, 4, 9}, /* 4 MB */
{ 0xe3, 22, 9, 4, 9}, /* 4 MB */
{ 0xe5, 22, 9, 4, 9}, /* 4 MB */
{ 0xe6, 23, 9, 4, 10}, /* 8 MB */
{ 0x73, 24, 9, 5, 10}, /* 16 MB */
{ 0x75, 25, 9, 5, 10}, /* 32 MB */
{ 0x76, 26, 9, 5, 10}, /* 64 MB */
{ 0x79, 27, 9, 5, 10}, /* 128 MB */
{ 0x71, 28, 9, 5, 10}, /* 256 MB */
/* MASK ROM */
{ 0x5d, 21, 9, 4, 8}, /* 2 MB */
{ 0xd5, 22, 9, 4, 9}, /* 4 MB */
{ 0xd6, 23, 9, 4, 10}, /* 8 MB */
{ 0x57, 24, 9, 4, 11}, /* 16 MB */
{ 0x58, 25, 9, 4, 12}, /* 32 MB */
{ 0,}
};
static struct alauda_card_info *alauda_card_find_id(unsigned char id) {
int i;
for (i = 0; alauda_card_ids[i].id != 0; i++)
if (alauda_card_ids[i].id == id)
return &(alauda_card_ids[i]);
return NULL;
}
/*
* ECC computation.
*/
static unsigned char parity[256];
static unsigned char ecc2[256];
static void nand_init_ecc(void) {
int i, j, a;
parity[0] = 0;
for (i = 1; i < 256;