diff -Naur /usr/src/linux/drivers/usb/storage/Makefile storage/Makefile --- /usr/src/linux/drivers/usb/storage/Makefile Fri Oct 5 21:40:47 2001 +++ storage/Makefile Tue Oct 9 23:23:48 2001 @@ -5,8 +5,21 @@ # Rewritten to use lists instead of if-statements. # +TOPDIR:=/mnt/linux/srcs/linux/linux-2.4/linux +all: usb-storage.o +clean: + -rm -f *.o .depend .*.o.flags + O_TARGET := storage.o EXTRA_CFLAGS := -I../../scsi/ +EXTRA_CFLAGS += -DCONFIG_USB_STORAGE_DEBUG=1 -DCONFIG_USB_STORAGE_HH501=1 +EXTRA_CFLAGS += -I$(TOPDIR)/include -I$(TOPDIR)/drivers/scsi +EXTRA_CFLAGS += -DMODULE -D__KERNEL__ -Wall -pipe +ARCH=i386 +CONFIG_USB_STORAGE_HH501=y +CONFIG_USB_STORAGE_DEBUG=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_DPCM=y list-multi := usb-storage.o @@ -22,6 +35,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_ISD200) += isd200.o usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB) += datafab.o usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o +usb-storage-obj-$(CONFIG_USB_STORAGE_HH501) += hh501.o usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \ initializers.o $(usb-storage-obj-y) diff -Naur /usr/src/linux/drivers/usb/storage/hh501.c storage/hh501.c --- /usr/src/linux/drivers/usb/storage/hh501.c Thu Jan 1 01:00:00 1970 +++ storage/hh501.c Tue Oct 9 23:04:25 2001 @@ -0,0 +1,974 @@ +/* + * Driver for Foxconn HH501 USB SmartMedia reader/writer + * + * $Id$ + * + * HH501 driver v0.1: + * + * First release + * + * v0.2: Luc Saillard + * Add some code to correct an error if i found a bad parity in the map transfer table. + * Add write operation !!!! + * + * Current development and maintenance by: + * (c) 2001 Luc Saillard + * + * The Foxconn HH501 USB SmartMedia reader uses the EzUSB chip from + * anchorchips. This a microcontroler which can be program. It has to a chips + * made by carry (www.carry.com.tw). To use this driver you need to upload a + * firmware into the reader. You can download the software at + * http://luc.saillard.free.fr/hh501/ or boot under Windows then reboot under + * Linux. + * Note: I use the firmware v3.x found in the GA-HH501.ZIP driver for windows. + * It is far from perfect because i have no documentation on the protocol use + * by the reader. + * + * Ok, for now, i've harcoded some values. Sector need to be 512 bytes len. So + * it won't work with old smartmedia card (5v). + * + * Each command is 8 bytes len. The action type is store in the first byte. + * Then the next 3 bytes is the block number to read (or write). Then the 2 + * bytes is the len. + * 0x33: reset the smartmedia reader. Must done before attempt to transfer some + * data. + * 0x16: is the command use to read the smartmedia transfer map. + * 0x17: is the command use to read the smartmedia memory. + * 0x15: is the command use to free one block (a group of sector) + * 0x14: is the commande use to copy a block to another location in the smartmedia card. + * The last byte seems to be the number of block (not tested) + * 0x13: is the command use to write data into the memory card. + * When you write a block in the memory card, you need to add 16 bytes, this + * the definition for the transfer map table. But i don't known how to calculate the crc. + * 0x11: is use to read the deviceID and the manufacturerID of the smartmedia + * card. + * + * When you read the status: + * bit 7: we have a card inserted + * bit 1: the card have changed we need to reload the mapping table + * + * How to write a block ? + * + * First you copy with the commande 0x14 a block a start adress (&~0xF) + * Then you write the block you can't to modify with command 0x13 or you + * use the command 0x14 which copy the block to another location. + * And finish, you delete the last block with the command 0x15. + * + * Some code is stolen from sddr09.c + * + * I've tested with this smarmedia card: + * 8Mb from Olympus + * 16Mb from Fuji and another manufacturer + * 64Mb from unknow manufacturer + * + * 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 "transport.h" +#include "protocol.h" +#include "usb.h" +#include "debug.h" +#include "hh501.h" + +#include +#include +#include + +#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) +#define LSB_of(s) ((s)&0xFF) +#define MSB_of(s) ((s)>>8) + +#define DEBUG_TRANSFER 0 + +#define PIPE_WRITE_COMMAND 0x01 +#define PIPE_READ_STATUS (0x1 | USB_DIR_IN) +#define PIPE_WRITE_DATA 0x02 +#define PIPE_READ_DATA (0x2 | USB_DIR_IN) + + +static unsigned int lba_test_parity(unsigned int lba1, unsigned int lba2); +static unsigned int lba_make_parity(unsigned int lba); + +/* It's use by 2 functions (lba_test_parity and lba_make_parity) */ +unsigned char fast_parity[16] = +{ + 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0 +}; + +/* + * Send a message to the usb device. + * + * us - the pointer to the us_data structure for the device to use + * + * endpoint - endpoint number (use | USB_DIR_IN) to read some information + * + * data - a buffer from which to get, or to which to store, any data + * that gets send or received, respectively, with the URB. Even though + * it looks like we allocate a buffer in this code for the data, xfer_data + * must contain enough allocated space. + * + * len - the number of bytes to send or receive with the URB. + * + */ +static int hh501_bulk_send(struct us_data *us, + unsigned int endpoint, + unsigned char *data, unsigned int len) +{ + + int result; + int act_len; + int pipe; + + if (endpoint & USB_DIR_IN) { + pipe = usb_rcvbulkpipe(us->pusb_dev, endpoint & 0x7F); +#if DEBUG_TRANSFER + US_DEBUGP("hh501_bulk_send_read: pipe:%x endpoint:%x\n", + pipe, endpoint); +#endif + } else { + pipe = usb_sndbulkpipe(us->pusb_dev, endpoint); +#if DEBUG_TRANSFER + US_DEBUGP("hh501_bulk_send_write: pipe:%x endpoint:%x\n", + pipe, endpoint); +#endif + } + + result = usb_stor_bulk_msg(us, data, pipe, len, &act_len); + + /* if we stall, we need to clear it before we go on */ + if (result == -EPIPE) { + US_DEBUGP("EPIPE: clearing endpoint halt for pipe 0x%x, " + "stalled at %d bytes\n", pipe, act_len); + usb_clear_halt(us->pusb_dev, pipe); + } + + if (result) { + /* NAK - that means we've retried a few times already */ + if (result == -ETIMEDOUT) { + US_DEBUGP("hh501_bulk_send(): device NAKed\n"); + return US_BULK_TRANSFER_FAILED; + } + + /* -ENOENT -- we canceled this transfer */ + if (result == -ENOENT) { + US_DEBUGP("hh501_bulk_send(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } + + if (result == -EPIPE) { + US_DEBUGP + ("hh501_bulk_send(): output pipe stalled\n"); + return USB_STOR_TRANSPORT_FAILED; + } + + /* the catch-all case */ + US_DEBUGP("hh501_bulk_send(): unknown error\n"); + return US_BULK_TRANSFER_FAILED; + } + + if (act_len != len) { + US_DEBUGP("Warning: Transferred only %d bytes\n", act_len); + return US_BULK_TRANSFER_SHORT; + } +#if DEBUG_TRANSFER + US_DEBUGP("Transfered %d of %d bytes\n", act_len, len); +#endif + + return US_BULK_TRANSFER_GOOD; +} + +/* + * + * Read a memory block in the smartmedia card. + * + * us - the pointer to the us_data structure for the device to use + * sector - the sector number we need to read + * sectors - the number of sectors + * content - some space for the transfer + * use_sg - + * + */ +int hh501_read_data(struct us_data *us, + unsigned int sector, + unsigned int sectors, + unsigned char *content, int use_sg) +{ + int result; + unsigned char cmd[8] = + { 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + struct hh501_card_info *info = + (struct hh501_card_info *) us->extra; + unsigned int lba; + unsigned int pba; + unsigned long address; + unsigned short page; + unsigned short pages; + unsigned char *buffer = NULL; + unsigned char *ptr; + struct scatterlist *sg = NULL; + int i; + int len; + int transferred; + + // If we're using scatter-gather, we have to create a new + // buffer to read all of the data in first, since a + // scatter-gather buffer could in theory start in the middle + // of a page, which would be bad. A developer who wants a + // challenge might want to write a limited-buffer + // version of this code. + + len = sectors * info->pagesize; + + if (use_sg) { + sg = (struct scatterlist *) content; + buffer = kmalloc(len, GFP_KERNEL); + if (buffer == NULL) + return USB_STOR_TRANSPORT_ERROR; + ptr = buffer; + } else + ptr = content; + + while (sectors > 0) { + /* Convert Logical Sector -> Physical sector on the smartmedia card */ + lba = sector >> info->blockshift; + page = sector & info->blockmask; + if (lba >= info->numblocks) { + US_DEBUGP ("Error: Requested LBA %04X exceeds maximum block %04X\n", + lba, info->numblocks -1 ); + return USB_STOR_TRANSPORT_ERROR; + } + pba = info->lba_to_pba[lba]; + // if pba is 0, either it's really 0, in which case + // the pba-to-lba map for pba 0 will be the lba, + // or that lba doesn't exist. + if (pba == 0 && info->pba_to_lba[0] != lba) { + US_DEBUGP + ("Error: Requested LBA %04X has no physical block mapping.\n", + lba); + return USB_STOR_TRANSPORT_ERROR; + } + // For now, we read one block per one block + pages = 1; +#if DEBUG_TRANSFER + US_DEBUGP + ("READ_10: read block %04X (LBA %04X) page %01X pages %d\n", + pba, lba, page, pages); +#endif + + address = (pba << info->blockshift) + page; + + if (info->capacity >= 0x4000000) { + cmd[3] = address >> 16; + cmd[2] = address >> 8; + cmd[1] = address & 0xFF; + } else { + cmd[3] = address >> 8; + cmd[2] = address & 0xFF; + cmd[1] = 0; + } + cmd[5] = 0x200 >> 8; + cmd[4] = 0x200 & 0xFF; + cmd[0] = 0x17; + + result = hh501_bulk_send(us, PIPE_WRITE_COMMAND, cmd, 8); +#if DEBUG_TRANSFER + US_DEBUGP("Result for send_control in read_data %d\n", + result); +#endif + + if (result != USB_STOR_TRANSPORT_GOOD) { + if (use_sg) + kfree(buffer); + return result; + } + + result = hh501_bulk_send(us, PIPE_READ_DATA, ptr, 0x200); + + if (result != USB_STOR_TRANSPORT_GOOD) { + if (use_sg) + kfree(buffer); + return result; + } + + sector++; + sectors--; + ptr += 0x200; + } + + if (use_sg) { + transferred = 0; + for (i = 0; i < use_sg && transferred < len; i++) { + memcpy(sg[i].address, buffer + transferred, + len - transferred > sg[i].length ? + sg[i].length : len - transferred); + transferred += sg[i].length; + } + kfree(buffer); + } + + return USB_STOR_TRANSPORT_GOOD; +} + + +/* + * + * Read a memory block in the smartmedia card. + * + * us - the pointer to the us_data structure for the device to use + * sector - the sector number we need to read + * sectors - the number of sectors + * content - some space for the transfer + * use_sg - + * + */ +int hh501_write_data(struct us_data *us, + unsigned int sector, + unsigned int sectors, + unsigned char *content, + int use_sg) +{ +#if 0 + int result; + unsigned char cmd[8] = + { 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + struct hh501_card_info *info = + (struct hh501_card_info *) us->extra; + unsigned int lba; + unsigned int pba; + unsigned long address; + unsigned short page; + unsigned short pages; + unsigned char *buffer = NULL; + unsigned char *ptr; + struct scatterlist *sg = NULL; + int len; + int sg_idx = 0, current_sg_offset = 0; + int transferred, totallen; + + // If we're using scatter-gather, we have to create a new + // buffer to read all of the data in first, since a + // scatter-gather buffer could in theory start in the middle + // of a page, which would be bad. A developer who wants a + // challenge might want to write a limited-buffer + // version of this code. + + totallen = sectors * info->pagesize; + +#if 1 + do { + // This device can transfer only 4k buffer + len = min(totallen, 4096); + + if (use_sg) { + sg = (struct scatterlist *) content; + buffer = kmalloc(len, GFP_KERNEL); + if (buffer == NULL) + return USB_STOR_TRANSPORT_ERROR; + ptr = buffer; + + memset(buffer, 0, len); + + // copy the data from the sg bufs into the big contiguous buf + + transferred = 0; + while (transferred < len) { + if (len - transferred >= sg[sg_idx].length - current_sg_offset) { + US_DEBUGP("hh501_write_data: getting %d bytes from %d byte sg " + "buffer\n", sg[sg_idx].length - current_sg_offset, sg[sg_idx].length); + memcpy(ptr + transferred, + sg[sg_idx].address + current_sg_offset, + sg[sg_idx].length - current_sg_offset); + transferred += sg[sg_idx].length - current_sg_offset; + current_sg_offset = 0; + // on to the next sg buffer + ++sg_idx; + } else { + US_DEBUGP("hh501_write_data: getting %d bytes from %d byte sg " + "buffer\n", len - transferred, sg[sg_idx].length); + memcpy(ptr + transferred, sg[sg_idx].address + + current_sg_offset, len - transferred); + current_sg_offset += len - transferred; + // we only copied part of this sg buffer + break; + } + } + } else { + ptr = content; + } +//TODO: cf datatab.c +#endif + while (sectors > 0) { + /* Convert Logical Sector -> Physical sector on the smartmedia card */ + lba = sector >> info->blockshift; + page = sector & info->blockmask; + if (lba >= info->numblocks) { + US_DEBUGP ("Error: Requested LBA %04X exceeds maximum block %04X\n", + lba, info->numblocks -1 ); + if (use_sg) + kfree(buffer); + return USB_STOR_TRANSPORT_ERROR; + } + pba = info->lba_to_pba[lba]; + if (pba == -1) { + // US_DEBUGP ("Error: This block is not initialized: %04X.\n", lba); + // if (use_sg) + // kfree(buffer); + // return USB_STOR_TRANSPORT_ERROR; + // Choose the first block we think who need allocation + int i; + for (i=0;inumblocks && info->pba_to_lba[i]!=-1 ;i++) + ; + US_DEBUGP ("We try to allocate a new block at pba=%4X lba=%4X\n", i,lba); + pba=i; + info->lba_to_pba[lba]=pba; + info->pba_to_lba[i]=lba; + } + // For now, we read one block per one block + pages = 1; + //#if DEBUG_TRANSFER + US_DEBUGP + ("WRITE_10: write block %04X (LBA %04X) page %01X pages %d len=%d\n", + pba, lba, page, pages,len); + //#endif + + address = (pba << info->blockshift) + page; + + if (info->capacity >= 0x4000000) { + cmd[3] = address >> 16; + cmd[2] = address >> 8; + cmd[1] = address & 0xFF; + } else { + cmd[3] = address >> 8; + cmd[2] = address & 0xFF; + cmd[1] = 0; + } + /* Yes, it is 0x210, because we need to add 16 bytes at end of the buffer, + * this 16 bytes is transfered to the map transfer table */ + cmd[5] = 0x210 >> 8; + cmd[4] = 0x210 & 0xFF; + cmd[0] = 0x13; + + result = hh501_bulk_send(us, PIPE_WRITE_COMMAND, cmd, 8); +//#if DEBUG_TRANSFER + US_DEBUGP("Result for WRITE_COMMAND: %d\n", result); +//#endif + + if (result != USB_STOR_TRANSPORT_GOOD) { + if (use_sg) + kfree(buffer); + return result; + } + + /* What can i speed this thing ? */ + memcpy(info->wbuffer, ptr, 0x200); + { + // Calculate the lba with the parity + int lba_cc = 0x1000 + (lba << 1); + lba_cc += 1024 * (lba_cc / 1000); + lba_cc = lba_make_parity(lba_cc); + info->wbuffer[0x200+5] = info->wbuffer[0x200+11]= lba_cc>>8; + info->wbuffer[0x200+6] = info->wbuffer[0x200+12]= lba_cc&0xFF; + } + result = hh501_bulk_send(us, PIPE_WRITE_DATA, info->wbuffer, 0x210); + if (result != USB_STOR_TRANSPORT_GOOD) { + if (use_sg) + kfree(buffer); + return result; + } + + result = hh501_bulk_send(us, PIPE_READ_DATA, cmd, 0x1); + + if (result != USB_STOR_TRANSPORT_GOOD) { + if (use_sg) + kfree(buffer); + return result; + } + + if (cmd[0]!=0xC0) + { + US_DEBUGP("Error while writing into the memory card at block" + " %4lX result is %2X\n", address,cmd[0]); + } + + sector++; + sectors--; + ptr += 0x200; + } + + if (use_sg) { + kfree(buffer); + } + + return USB_STOR_TRANSPORT_GOOD; +#else + return USB_STOR_TRANSPORT_ERROR; +#endif +} + +static unsigned int lba_test_parity(unsigned int lba1, unsigned int lba2) +{ + unsigned char parity; + + if (lba1 != lba2) + { + if ((lba1 & 0xF000) == 0x1000) + { + parity = 1; // the parity of 0x1000 + parity ^= fast_parity[lba1 & 0x000F]; + parity ^= fast_parity[(lba1 >> 4) & 0x000F]; + parity ^= fast_parity[(lba1 >> 8) & 0x000F]; + if (!parity) + return lba1; + } + if ((lba2 & 0xF000) == 0x1000) + { + parity = 1; // the parity of 0x1000 + parity ^= fast_parity[lba2 & 0x000F]; + parity ^= fast_parity[(lba2 >> 4) & 0x000F]; + parity ^= fast_parity[(lba2 >> 8) & 0x000F]; + if (!parity) + return lba2; + } + return 0xFFFFFFFF; /* Impossible block */ + } + else /* If lba1 == lba2, i supose that lba1 have a good parity */ + return lba1; +} + +static unsigned int lba_make_parity(unsigned int lba) +{ + unsigned char parity; + + parity = 1; // the parity of 0x1000 + parity ^= fast_parity[lba & 0x000F]; + parity ^= fast_parity[(lba >> 4) & 0x000F]; + parity ^= fast_parity[(lba >> 8) & 0x000F]; + return lba + parity; +} + +int hh501_read_map_block(struct us_data *us, + unsigned int block, unsigned char *map) +{ + + int result; + struct hh501_card_info *info = + (struct hh501_card_info *) (us->extra); + unsigned char cmd[8] = { + 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 + }; + int block_addr; + + block_addr = block * info->blocksize; + + if (info->capacity >= 0x4000000) { + cmd[3] = block_addr >> 16; + cmd[2] = block_addr >> 8; + cmd[1] = block_addr & 0xFF; + } else { + cmd[3] = block_addr >> 8; + cmd[2] = block_addr & 0xFF; + cmd[1] = 0; + } + + memset(map, 0, 0x10); + + result = hh501_bulk_send(us, PIPE_WRITE_COMMAND, cmd, 8); + result = hh501_bulk_send(us, PIPE_READ_DATA, map, 0x10); + + return result; +} + +int hh501_read_deviceID(struct us_data *us, + unsigned char *manufacturerID, + unsigned char *deviceID) +{ + + int result; + unsigned char command[8] = { + 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 + }; + unsigned char content[2]; + + result = hh501_bulk_send(us, PIPE_WRITE_COMMAND, command, 8); + + US_DEBUGP("Result of send_control for device ID is %d\n", result); + + if (result != USB_STOR_TRANSPORT_GOOD) + return result; + + result = hh501_bulk_send(us, PIPE_READ_DATA, content, 2); + + *manufacturerID = content[0]; + *deviceID = content[1]; + + return result; +} + + +unsigned long hh501_get_capacity(struct us_data *us, + unsigned int *pagesize, + unsigned int *blocksize) +{ + + unsigned char manufacturerID; + unsigned char deviceID; + int result; + + US_DEBUGP("Reading capacity...\n"); + + result = hh501_read_deviceID(us, &manufacturerID, &deviceID); + + US_DEBUGP("Result of read_deviceID is %d\n", result); + + if (result != USB_STOR_TRANSPORT_GOOD) + return 0; + + US_DEBUGP("DeviceID = %02X\n", deviceID); + US_DEBUGP("ManufacturerID = %02X\n", manufacturerID); + + *pagesize = 512; + *blocksize = 16; + + switch (deviceID) { + /* Smartmedia with a 256 bytes blocklen isn't supportted */ + case 0x6e: // 1MB + case 0xe8: + case 0xec: + case 0xea: // 2MB + case 0x64: + *pagesize = 256; + return 0x00000000; + + case 0x5d: // 2MB, 5d is a ROM card with pagesize 512. + return 0x00200000; + + case 0xe3: // 4MB + case 0xe5: + case 0x6b: + case 0xd5: + return 0x00400000; + + case 0xe6: // 8MB + case 0xd6: + return 0x00800000; + + case 0x73: // 16MB + *blocksize = 32; + return 0x01000000; + + case 0x75: // 32MB + *blocksize = 32; + return 0x02000000; + + case 0x76: // 64MB + *blocksize = 32; + return 0x04000000; + + case 0x79: // 128MB + *blocksize = 32; + return 0x08000000; + + default: // unknown + return 0; + + } +} + +int hh501_read_map(struct us_data *us) +{ + struct hh501_card_info *info = + (struct hh501_card_info *) (us->extra); + int numblocks; + int i; + unsigned char ptr[16]; + unsigned short lba, lba1, lba2; + + if (!info->capacity) + return -1; + + info->numblocks = numblocks = info->capacity >> (info->blockshift + info->pageshift); + US_DEBUGP("Numblocks = %d", numblocks); + + if (info->lba_to_pba) + kfree(info->lba_to_pba); + if (info->pba_to_lba) + kfree(info->pba_to_lba); + info->lba_to_pba = kmalloc(numblocks * sizeof(int), GFP_KERNEL); + info->pba_to_lba = kmalloc(numblocks * sizeof(int), GFP_KERNEL); + + if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) { + if (info->lba_to_pba != NULL) + kfree(info->lba_to_pba); + if (info->pba_to_lba != NULL) + kfree(info->pba_to_lba); + info->lba_to_pba = NULL; + info->pba_to_lba = NULL; + return 0; + } + + memset(info->lba_to_pba, 0, numblocks * sizeof(int)); + memset(info->pba_to_lba, 0, numblocks * sizeof(int)); + + for (i = 0; i < numblocks; i++) { + + hh501_read_map_block(us, i, ptr); + + if (ptr[0] != 0xFF || ptr[1] != 0xFF || ptr[2] != 0xFF || + ptr[3] != 0xFF || ptr[4] != 0xFF || ptr[5] != 0xFF) { + US_DEBUGP + ("PBA %04X has no logical mapping: reserved area = " + "%02X%02X%02X%02X data status %02X block status %02X\n", + i, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], + ptr[5]); + continue; + } + + lba1 = (ptr[6]<<8)+ptr[7]; + lba2 = (ptr[11]<<8)+ptr[12]; + + lba = lba_test_parity(lba1,lba2); + + if (lba == 0xFFFFFFFF) + continue; + + lba = (lba & 0x07FF) >> 1; + + /* Every 1024 physical blocks ("zone"), the LBA numbers + * go back to zero, but are within a higher + * block of LBA's. Also, there is a maximum of + * 1000 LBA's per zone. In other words, in PBA + * 1024-2047 you will find LBA 0-999 which are + * really LBA 1000-1999. Yes, this wastes 24 + * physical blocks per zone. Go figure. + */ + + lba += 1000 * (i / 0x400); + + if (lba >= numblocks) { + US_DEBUGP("Bad LBA %04X for block %04X\n", lba, i); + continue; + } + + info->pba_to_lba[i] = lba; + info->lba_to_pba[lba] = i; + } + + return 0; +} + + +void hh501_card_info_destructor(void *extra) +{ + struct hh501_card_info *info = (struct hh501_card_info *) extra; + + if (!extra) + return; + + if (info->lba_to_pba) + kfree(info->lba_to_pba); + if (info->pba_to_lba) + kfree(info->pba_to_lba); + if (info->wbuffer) + kfree(info->wbuffer); +} + +/* + * Transport for the Foxconn HH501 + */ +int hh501_transport(Scsi_Cmnd * srb, struct us_data *us) +{ + unsigned char mode_page_01[16] = { // write-protected for now + 0x03, 0x00, 0x80, 0x00, + 0x01, 0x0A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + unsigned char *ptr; + unsigned long capacity; + unsigned int page; + unsigned int pages; + int i; + struct hh501_card_info *info = + (struct hh501_card_info *) (us->extra); + + if (!us->extra) { + us->extra = + kmalloc(sizeof(struct hh501_card_info), GFP_KERNEL); + if (!us->extra) + return USB_STOR_TRANSPORT_ERROR; + memset(us->extra, 0, sizeof(struct hh501_card_info)); + us->extra_destructor = hh501_card_info_destructor; + /* Allocate a buffer to permit transfer later. This buffer is used + * for writing to the memory card. We need to add 16 bytes after the + * buffer. So we alloc this buffer in advanceA + * TODO: Fix the 0x210 number */ + info = (struct hh501_card_info *) (us->extra); + info->wbuffer = kmalloc(0x210,GFP_KERNEL); + /* If we can't alloc this place, write operation isn't allowed */ + if (info->wbuffer) + { + unsigned char *ptbl=info->wbuffer+0x200; + for (i=0;i<16;i++) + ptbl[i]=0xFF; + } + } + + ptr = (unsigned char *) srb->request_buffer; + + if (srb->cmnd[0] == READ_CAPACITY) { + + capacity = hh501_get_capacity(us, &info->pagesize, + &info->blocksize); + + if (!capacity) + return USB_STOR_TRANSPORT_FAILED; + + info->capacity = capacity; + for (info->pageshift = 1; + (info->pagesize >> info->pageshift); + info->pageshift++); + info->pageshift--; + for (info->blockshift = 1; + (info->blocksize >> info->blockshift); + info->blockshift++); + info->blockshift--; + info->blockmask = (1 << info->blockshift) - 1; + + // Last page in the card + + capacity /= info->pagesize; + capacity--; + + ptr[0] = MSB_of(capacity >> 16); + ptr[1] = LSB_of(capacity >> 16); + ptr[2] = MSB_of(capacity & 0xFFFF); + ptr[3] = LSB_of(capacity & 0xFFFF); + + // The page size + + ptr[4] = MSB_of(info->pagesize >> 16); + ptr[5] = LSB_of(info->pagesize >> 16); + ptr[6] = MSB_of(info->pagesize & 0xFFFF); + ptr[7] = LSB_of(info->pagesize & 0xFFFF); + + hh501_read_map(us); + + return USB_STOR_TRANSPORT_GOOD; + } + + if (srb->cmnd[0] == MODE_SENSE) { + + // I don't now how to protect my smartmedia card, + // if the card is protected put 0x80 in mode_page_01[2] + // and 0x0 if it's not protected + + if (info->wbuffer) // no write buffer, no write operation + mode_page_01[2]&=0x7f; + else + mode_page_01[2]|=0x80; + + if ((srb->cmnd[2] & 0x3F) == 0x01) { + + US_DEBUGP("HH501: Dummy up request for mode page 1\n"); + + if (ptr == NULL || + srb->request_bufflen < sizeof(mode_page_01)) + return USB_STOR_TRANSPORT_ERROR; + + memcpy(ptr, mode_page_01, sizeof(mode_page_01)); + return USB_STOR_TRANSPORT_GOOD; + + } else if ((srb->cmnd[2] & 0x3F) == 0x3F) { + + US_DEBUGP("HH501: Dummy up request for all mode pages\n"); + + if (ptr == NULL || + srb->request_bufflen < sizeof(mode_page_01)) + return USB_STOR_TRANSPORT_ERROR; + + memcpy(ptr, mode_page_01, sizeof(mode_page_01)); + return USB_STOR_TRANSPORT_GOOD; + } + // FIXME: sense buffer? + + return USB_STOR_TRANSPORT_ERROR; + } + + if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { + + US_DEBUGP("HH501: %s medium removal. Not that I can do" + " anything about it...\n", + (srb->cmnd[4] & 0x03) ? "Prevent" : "Allow"); + + return USB_STOR_TRANSPORT_GOOD; + } + + if (srb->cmnd[0] == READ_10) { + + page = short_pack(srb->cmnd[3], srb->cmnd[2]); + page <<= 16; + page |= short_pack(srb->cmnd[5], srb->cmnd[4]); + pages = short_pack(srb->cmnd[8], srb->cmnd[7]); + + return hh501_read_data(us, page, pages, ptr, srb->use_sg); + } + + if (srb->cmnd[0] == WRITE_10) { + + page = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | + ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); + + pages = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); + + return hh501_write_data(us, page, pages, ptr, srb->use_sg); + } + + if (srb->cmnd[0] == TEST_UNIT_READY) + { + US_DEBUGP("HH501: TEST_UNIT_READY\n"); + return USB_STOR_TRANSPORT_GOOD; + } + return USB_STOR_TRANSPORT_ERROR; +} + +int hh501_init(struct us_data *us) +{ + int result, count; + unsigned char command[8] = + { 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + unsigned char buffer[2]; + int not_initialized = 1; + + // Initialise the reader + count = 0; + US_DEBUGP + ("Attempting to init Foxconn HH501 Smartmedia Reader...\n"); + if ((result = hh501_bulk_send(us, PIPE_WRITE_COMMAND, command, 8)) + != USB_STOR_TRANSPORT_GOOD) return result; + + while (not_initialized && count < 20) { + //wait_ms(500); /* Wait 500ms */ + result = hh501_bulk_send(us, PIPE_READ_STATUS, buffer, 2); + US_DEBUGP("-- result is %d\n", result); + if ((buffer[0] & 0xF) == 0) + not_initialized = 0; + count++; + } + + if (not_initialized) + return USB_STOR_TRANSPORT_ERROR; + else + return USB_STOR_TRANSPORT_GOOD; +} diff -Naur /usr/src/linux/drivers/usb/storage/hh501.h storage/hh501.h --- /usr/src/linux/drivers/usb/storage/hh501.h Thu Jan 1 01:00:00 1970 +++ storage/hh501.h Tue Oct 9 23:04:25 2001 @@ -0,0 +1,45 @@ +/* + * Driver for Foxconn HH501 USB SmartMedia reader/writer + * + * $Id$ + * + * Current development and maintenance by: + * (c) 2001 Luc Saillard + * + * See hh501.c for more explanation + * + * 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. + */ + +#ifndef _USB_HH501_H +#define _USB_HH501_H + +extern int hh501_transport(Scsi_Cmnd * srb, struct us_data *us); +extern int hh501_init(struct us_data *us); + +struct hh501_card_info { + unsigned long capacity; /* Size of card in bytes */ + int pagesize; /* Size of page in bytes */ + int pageshift; /* log2 of pagesize */ + int blocksize; /* Size of block in pages */ + int blockshift; /* log2 of blocksize */ + int blockmask; /* 2^blockshift - 1 */ + int *lba_to_pba; /* logical to physical map */ + int *pba_to_lba; /* physical to logical map */ + int numblocks; /* Numbers of allocated block */ + unsigned char *wbuffer; /* Buffer for writing in the card */ +}; + +#endif diff -Naur /usr/src/linux/drivers/usb/storage/transport.h storage/transport.h --- /usr/src/linux/drivers/usb/storage/transport.h Fri Oct 5 22:16:51 2001 +++ storage/transport.h Tue Oct 9 23:19:59 2001 @@ -72,6 +72,10 @@ #define US_PR_JUMPSHOT 0xf3 /* Lexar Jumpshot */ #endif +#ifdef CONFIG_USB_STORAGE_HH501 +#define US_PR_HH501 0xf4 /* HH501 */ +#endif + /* * Bulk only data structures */ diff -Naur /usr/src/linux/drivers/usb/storage/unusual_devs.h storage/unusual_devs.h --- /usr/src/linux/drivers/usb/storage/unusual_devs.h Fri Oct 5 22:16:56 2001 +++ storage/unusual_devs.h Tue Oct 9 23:15:22 2001 @@ -79,6 +79,14 @@ "Nex II Digital", US_SC_SCSI, US_PR_BULK, NULL, US_FL_START_STOP), +#ifdef CONFIG_USB_STORAGE_HH501 +UNUSUAL_DEV( 0x0489, 0x0503, 0x0000, 0x9999, + "Foxconn", + "HH501", + US_SC_SCSI, US_PR_HH501, hh501_init, + US_FL_FIX_INQUIRY | US_FL_SINGLE_LUN | US_FL_START_STOP ), +#endif + /* Reported by Paul Stewart * This entry is needed because the device reports Sub=ff */ UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x0001, diff -Naur /usr/src/linux/drivers/usb/storage/usb.c storage/usb.c --- /usr/src/linux/drivers/usb/storage/usb.c Fri Oct 5 21:44:31 2001 +++ storage/usb.c Tue Oct 9 23:18:19 2001 @@ -75,6 +75,9 @@ #ifdef CONFIG_USB_STORAGE_JUMPSHOT #include "jumpshot.h" #endif +#ifdef CONFIG_USB_STORAGE_HH501 +#include "hh501.h" +#endif #include @@ -875,6 +878,15 @@ ss->transport_reset = usb_stor_Bulk_reset; ss->max_lun = 1; break; +#endif + +#ifdef CONFIG_USB_STORAGE_HH501 + case US_PR_HH501: + ss->transport_name = "HH501 Bulk-Only"; + ss->transport = hh501_transport; + ss->transport_reset = usb_stor_Bulk_reset; + ss->max_lun = 0; + break; #endif default: