Recently I have written three drivers for USB SmartMedia readers.
One reached 2.5.13. One is visible on ftp.XX.kernel.org.
The third was this evening.

Such drivers share a lot of code, and instead of having N copies
of the code (as is already today visible in usb/storage) I separated
out all that was common. Let me show you here some fragments of code.
Note, Matt, Greg: this is not a code submission, it is just a request
for comments. This may not even compile. Sooner or later I'll submit
some version of this.

The first fragment is smartmedia.c.
It knows about the structure of a smartmedia card, but not about the
commands the various drivers use to read and write.

----- smartmedia.h -----

#ifndef _SMARTMEDIA_H_
#define _SMARTMEDIA_H_

#include "usb.h"

extern unsigned char nand_parity[256];
extern void nand_compute_ecc(unsigned char *data, unsigned char *ecc);
extern void nand_store_ecc  (unsigned char *data, unsigned char *ecc);
extern int  nand_compare_ecc(unsigned char *data, unsigned char *ecc);

struct sm_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             controlshift;   /* log2 of extra bytes/page */
        int             lbact;          /* number of available pages */
        int             flags;
#define SMARTMEDIA_WP   1               /* write protected */
#define SMARTMEDIA_RO   2               /* set to read-only */
};

struct sm_ops {
        int (*sm_init)(struct us_data *us);
        int (*sm_read_deviceID)(struct us_data *us, unsigned char *id4);
        int (*sm_read_map)(struct us_data *us);
        int (*sm_read_control)(struct us_data *us,
                               unsigned long address, unsigned int sectorct,
                               unsigned char *buf, int use_sg);
        int (*sm_read_data)(struct us_data *us,
                            unsigned long address, unsigned int sectorct,
                            unsigned char *buf, int use_sg);
        int (*sm_write_lba)(struct us_data *us, unsigned int lba,
                             unsigned int page, unsigned int pagect,
                             unsigned char *buf);
        int (*sm_test_unit_ready)(struct us_data *us,
                                  Scsi_Cmnd *srb, int cmdlen);
        int (*sm_request_sense)(struct us_data *us,
                                Scsi_Cmnd *srb, int cmdlen);
};

extern int smartmedia_raw;

extern int
smartmedia_transport(Scsi_Cmnd *srb, struct us_data *us, struct sm_ops *sm);

extern int
smartmedia_allocate_map(struct sm_card_info *info);

extern unsigned int
smartmedia_find_unused_pba(struct sm_card_info *info, unsigned int lba);

/*
 * LBA and PBA are unsigned ints. Special values.
 */
#define UNDEF    0xffffffff
#define SPARE    0xfffffffe
#define UNUSABLE 0xfffffffd

#endif

----- smartmedia.c -----

/*
 * SmartMedia driver, aeb, koninginnedag 2002
 *
 * (c) 2000, 2001 Robert Baruch ([EMAIL PROTECTED])
 * (c) 2002 Andries Brouwer ([EMAIL PROTECTED])
 */

#include <linux/config.h>
#include <linux/module.h>

#include "transport.h"
#include "smartmedia.h"
#include "debug.h"

/* #define US_DEBUGP    printk */

#define short_pack(lsb,msb) (((u16)(lsb)) | (((u16)(msb))<<8))
#define LSB_of(s) ((s)&0xFF)
#define MSB_of(s) ((s)>>8)

/*
 * The below two parameters are meant for debugging use only.
 * They work globally, not per device.
 */

/* direct access to card */
int smartmedia_raw = 0;
MODULE_PARM(smartmedia_raw, "i");
MODULE_PARM_DESC(smartmedia_raw, "make PBA=LBA");

/* each 512-byte sector has 64 bytes control */
/* the control is given in PBA order */
static int smartmedia_control = 0;
MODULE_PARM(smartmedia_control, "i");
MODULE_PARM_DESC(smartmedia_control, "read control");

/*
 * First some stuff that does not belong here:
 * data on SmartMedia and other cards, unrelated to USB.
 * Similar stuff occurs in <linux/mtd/nand_ids.h>.
 */

struct nand_flash_dev {
        int model_id;
        int chipshift;          /* 1<<cs bytes total capacity */
        char pageshift;         /* 1<<ps bytes in a page */
        char blockshift;        /* 1<<bs pages in an erase block */
        char zoneshift;         /* 1<<zs blocks in a zone */
                                /* # of logical blocks is 125/128 of this */
        char pageadrlen;        /* length of an address in bytes - 1 */
};

/*
 * NAND Flash Manufacturer ID Codes
 */
#define NAND_MFR_AMD            0x01
#define NAND_MFR_TOSHIBA        0x98
#define NAND_MFR_SAMSUNG        0xec

static inline char *
nand_flash_manufacturer(int manuf_id) {
        switch(manuf_id) {
        case NAND_MFR_AMD:
                return "AMD";
        case NAND_MFR_TOSHIBA:
                return "Toshiba";
        case NAND_MFR_SAMSUNG:
                return "Samsung";
        default:
                return "unknown";
        }
}

/*
 * It looks like it is unnecessary to attach manufacturer to the
 * remaining data: SSFDC prescribes manufacturer-independent id codes.
 */
static struct nand_flash_dev nand_flash_ids[] = {
        /* NAND flash - these I verified */
        { 0x6e, 20, 8, 4, 8, 2},        /* 1 MB, 5V */
        { 0xe8, 20, 8, 4, 8, 2},        /* 1 MB */
        { 0xec, 20, 8, 4, 8, 2},        /* 1 MB */
        { 0x64, 21, 8, 4, 9, 2},        /* 2 MB, 5V */
        { 0xea, 21, 8, 4, 9, 2},        /* 2 MB */
        { 0x6b, 22, 9, 4, 9, 2},        /* 4 MB, 5V */
        { 0xe3, 22, 9, 4, 9, 2},        /* 4 MB */
        { 0xe5, 22, 9, 4, 9, 2},        /* 4 MB, 3.3V or 5V */
        { 0xe6, 23, 9, 4, 10, 2},       /* 8 MB */
        { 0x73, 24, 9, 5, 10, 2},       /* 16 MB */
        { 0x75, 25, 9, 5, 10, 2},       /* 32 MB */
        { 0x76, 26, 9, 5, 10, 3},       /* 64 MB */
        { 0x79, 27, 9, 5, 10, 3},       /* 128 MB */
        /* Maybe also 48 MB, 96 MB and 256 MB cards do exist */

        /* MASK ROM - from unknown source */
        { 0x5d, 21, 9, 4, 8, 2},        /* 2 MB */
        { 0xd5, 22, 9, 4, 9, 2},        /* 4 MB */
        { 0xd6, 23, 9, 4, 10, 2},       /* 8 MB */
        { 0,}
};

#define SIZE(a) (sizeof(a)/sizeof((a)[0]))

static struct nand_flash_dev *
nand_find_id(unsigned char id) {
        int i;

        for (i = 0; i < SIZE(nand_flash_ids); i++)
                if (nand_flash_ids[i].model_id == id)
                        return &(nand_flash_ids[i]);
        return NULL;
}

/*
 * ECC computation.
 */
unsigned char nand_parity[256];
static unsigned char nand_ecc2[256];

static void
nand_init_ecc(void) {
        static int nand_inited = 0;
        int i, j, a;

        if (nand_inited)
                return;
        nand_inited = 1;

        nand_parity[0] = 0;
        for (i = 1; i < 256; i++)
                nand_parity[i] = (nand_parity[i&(i-1)] ^ 1);

        for (i = 0; i < 256; i++) {
                a = 0;
                for (j = 0; j < 8; j++) {
                        if (i & (1<<j)) {
                                if ((j & 1) == 0)
                                        a ^= 0x04;
                                if ((j & 2) == 0)
                                        a ^= 0x10;
                                if ((j & 4) == 0)
                                        a ^= 0x40;
                        }
                }
                nand_ecc2[i] = ~(a ^ (a<<1) ^ (nand_parity[i] ? 0xa8 : 0));
        }
}

/* compute 3-byte ecc on 256 bytes */
void
nand_compute_ecc(unsigned char *data, unsigned char *ecc) {
        int i, j, a;
        unsigned char par, bit, bits[8];

        par = 0;
        for (j = 0; j < 8; j++)
                bits[j] = 0;

        /* collect 16 checksum bits */
        for (i = 0; i < 256; i++) {
                par ^= data[i];
                bit = nand_parity[data[i]];
                for (j = 0; j < 8; j++)
                        if ((i & (1<<j)) == 0)
                                bits[j] ^= bit;
        }

        /* put 4+4+4 = 12 bits in the ecc */
        a = (bits[3] << 6) + (bits[2] << 4) + (bits[1] << 2) + bits[0];
        ecc[0] = ~(a ^ (a<<1) ^ (nand_parity[par] ? 0xaa : 0));

        a = (bits[7] << 6) + (bits[6] << 4) + (bits[5] << 2) + bits[4];
        ecc[1] = ~(a ^ (a<<1) ^ (nand_parity[par] ? 0xaa : 0));

        ecc[2] = nand_ecc2[par];
}

int
nand_compare_ecc(unsigned char *data, unsigned char *ecc) {
        return (data[0] == ecc[0] && data[1] == ecc[1] && data[2] == ecc[2]);
}

void
nand_store_ecc(unsigned char *data, unsigned char *ecc) {
        memcpy(data, ecc, 3);
}

/*
 * The actual driver starts here.
 */

static inline void *
kcmalloc(size_t len, int prio) {
        void *ptr;

        ptr = kmalloc(len, prio);
        if (ptr)
                memset(ptr, 0, len);
        return ptr;
}

#if 0
static void
sm_card_info_destructor(void *extra) {
        struct sm_card_info *info;

        info = (struct sm_card_info *) extra;
        if (!info)
                return;

        kfree(info->lba_to_pba);
        kfree(info->pba_to_lba);
}
#endif

static void
sm_init_card_info(struct sm_card_info **infop) {
        if (!*infop)
                *infop = kcmalloc(sizeof(struct sm_card_info), GFP_NOIO);
        /* set destructor */
}

static struct nand_flash_dev *
sm_get_cardinfo(struct us_data *us, unsigned char flags, struct sm_ops *sm) {
        struct nand_flash_dev *cardinfo;
        unsigned char deviceID[4];
        char blurbtxt[256];
        int result;

        US_DEBUGP("Reading deviceID...\n");

        result = sm->sm_read_deviceID(us, deviceID);

        if (result != USB_STOR_TRANSPORT_GOOD) {
                US_DEBUGP("Result of read_deviceID is %d\n", result);
                return NULL;
        }

        sprintf(blurbtxt, "Found SmartMedia card, ID = %02X %02X %02X %02X",
                deviceID[0], deviceID[1], deviceID[2], deviceID[3]);

        /* Byte 0 is the manufacturer */
        sprintf(blurbtxt + strlen(blurbtxt),
                ": Manuf. %s",
                nand_flash_manufacturer(deviceID[0]));

        /* Byte 1 is the device type */
        cardinfo = nand_find_id(deviceID[1]);
        if (cardinfo) {
                /* MB or MiB? It is neither. A 16 MB card has
                   17301504 raw bytes, of which 16384000 are
                   usable for user data. */
                sprintf(blurbtxt + strlen(blurbtxt),
                        ", %d MB", 1<<(cardinfo->chipshift - 20));
        } else {
                sprintf(blurbtxt + strlen(blurbtxt),
                        ", type unrecognized");
        }

        /* Byte 2 is code to signal availability of 128-bit ID */
        if (deviceID[2] == 0xa5) {
                sprintf(blurbtxt + strlen(blurbtxt),
                        ", 128-bit ID");
        }

        /* Byte 3 announces the availability of another read ID command */
        if (deviceID[3] == 0xc0) {
                sprintf(blurbtxt + strlen(blurbtxt),
                        ", extra cmd");
        }

        if (flags & SMARTMEDIA_WP)
                sprintf(blurbtxt + strlen(blurbtxt),
                        ", WP");

        printk("%s\n", blurbtxt);

        return cardinfo;
}

/*
 * Read from disk address the indicated number of sectors.
 * Here a sector has size info->pagesize (and address is
 * given in this unit).
 */
static int
sm_read_data(struct us_data *us, struct sm_ops *sm,
             unsigned long address, unsigned int count,
             unsigned char *content, int use_sg) {

        struct sm_card_info *info = (struct sm_card_info *) us->extra;
        unsigned int lba, maxlba, pba;
        unsigned int page, pages;
        unsigned char *buffer = NULL;
        unsigned char *ptr;
        struct scatterlist *sg = NULL;
        int result, i, len;

        // 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 = count * info->pagesize;

        if (use_sg) {
                sg = (struct scatterlist *) content;
                buffer = kmalloc(len, GFP_NOIO);
                if (buffer == NULL)
                        return USB_STOR_TRANSPORT_ERROR;
                ptr = buffer;
        } else
                ptr = content;

        // Figure out the initial LBA and page
        lba = address >> info->blockshift;
        page = (address & info->blockmask);
        maxlba = info->capacity >> (info->pageshift + info->blockshift);

        // This could be made much more efficient by checking for
        // contiguous LBA's. Another exercise left to the student.

        result = USB_STOR_TRANSPORT_GOOD;

        while (count > 0) {

                /* Find number of pages we can read in this block */
                pages = info->blocksize - page;
                if (pages > count)
                        pages = count;

                /* Not overflowing capacity? */
                if (lba >= maxlba) {
                        US_DEBUGP("Error: Requested lba %u exceeds "
                                  "maximum %u\n", lba, maxlba);
                        result = USB_STOR_TRANSPORT_ERROR;
                        break;
                }

                /* Find where this lba lives on disk */
                pba = info->lba_to_pba[lba];

                if (pba == UNDEF) {     /* this lba was never written */
#if 0
                        US_DEBUGP("Read %d null pages (LBA %d) page %d\n",
                                  pages, lba, page);
#endif
                        /*
                         * This is not an error. It just means
                         * that the block has never been written.
                         * Unwritten blocks read as 0xff.
                         */

                        memset(ptr, 0xff, pages << info->pageshift);

                } else {
                        US_DEBUGP("Read %d pages, from PBA %d"
                                  " (LBA %d) page %d\n",
                                  pages, pba, lba, page);

                        address = (pba << info->blockshift) + page;

                        result = sm->sm_read_data(us, address, pages, ptr, 0);
                        if (result != USB_STOR_TRANSPORT_GOOD)
                                break;
                }

                page = 0;
                lba++;
                count -= pages;
                ptr += (pages << info->pageshift);
        }

        if (use_sg && result == USB_STOR_TRANSPORT_GOOD) {
                int transferred = 0;

                for (i=0; i<use_sg && transferred<len; i++) {
                        unsigned char *buf;
                        unsigned int length;

                        buf = page_address(sg[i].page) + sg[i].offset;

                        length = len-transferred;
                        if (length > sg[i].length)
                                length = sg[i].length;

                        memcpy(buf, buffer+transferred, length);
                        transferred += sg[i].length;
                }
        }

        if (use_sg)
                kfree(buffer);

        return result;
}

unsigned int
smartmedia_find_unused_pba(struct sm_card_info *info, unsigned int lba) {
        static unsigned int lastpba = 1;
        int numblocks = info->capacity >> (info->blockshift + info->pageshift);
        int minpba, maxpba, i;

        /* find pba in the same block as lba */
        minpba = (lba / 1000) * 1024;
        if (minpba == 0)
                minpba = 2;
        maxpba = minpba + 1024;
        if (maxpba > numblocks)
                maxpba = numblocks;

        /* avoid giving out recent blocks again */
        if (lastpba/1024 != pbamin/1024)
                lastpba = pbamin-1;

        for (i = lastpba+1; i < maxpba; i++) {
                if (info->pba_to_lba[i] == UNDEF) {
                        lastpba = i;
                        return i;
                }
        }
        for (i = minpba; i <= lastpba; i++) {
                if (info->pba_to_lba[i] == UNDEF) {
                        lastpba = i;
                        return i;
                }
        }

        /* medium error; no defect spare location available */
        set_sense_info(0x03, 0x32, 0);

        return 0;
}

/*
 * Write to disk address the indicated number of sectors.
 * Here a sector has size info->pagesize (and address is
 * given in this unit).
 */
static int
sm_write_data(struct us_data *us, struct sm_ops *sm,
              unsigned long address, unsigned int sectors,
              unsigned char *content, int use_sg) {
        struct sm_card_info *info = us->extra;
        unsigned int lba, page, pages;
        unsigned char *buffer = NULL;
        unsigned char *ptr;
        struct scatterlist *sg = NULL;
        int result, i, len;

        // If we're using scatter-gather, we have to create a new
        // buffer to write 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) {
                int transferred = 0;

                sg = (struct scatterlist *)content;
                buffer = kmalloc(len, GFP_NOIO);
                if (buffer == NULL)
                        return USB_STOR_TRANSPORT_ERROR;

                for (i=0; i<use_sg && transferred<len; i++) {
                        unsigned char *buf;
                        unsigned int length;

                        buf = page_address(sg[i].page) + sg[i].offset;

                        length = len-transferred;
                        if (length > sg[i].length)
                                length = sg[i].length;

                        memcpy(buffer+transferred, buf, length);
                        transferred += sg[i].length;
                }
                ptr = buffer;
        } else
                ptr = content;

        // Figure out the initial LBA and page
        lba = address >> info->blockshift;
        page = (address & info->blockmask);

        // This could be made much more efficient by checking for
        // contiguous LBA's. Another exercise left to the student.

        result = USB_STOR_TRANSPORT_GOOD;

        while (sectors > 0) {

                // Write as many sectors as possible in this block

                pages = info->blocksize - page;
                if (pages > sectors)
                        pages = sectors;

                result = sm->sm_write_lba(us, lba, page, pages, ptr);
                if (result != USB_STOR_TRANSPORT_GOOD)
                        break;

                page = 0;
                lba++;
                sectors -= pages;
                ptr += (pages << info->pageshift);
        }

        if (use_sg)
                kfree(buffer);

        return result;
}

/* return 0 on failure */
int
smartmedia_allocate_map(struct sm_card_info *info) {
        int numblocks = info->capacity >> (info->blockshift + info->pageshift);
        int i;

        kfree(info->lba_to_pba);
        kfree(info->pba_to_lba);
        info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
        info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO);

        if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) {
                kfree(info->lba_to_pba);
                kfree(info->pba_to_lba);
                info->lba_to_pba = NULL;
                info->pba_to_lba = NULL;
                return 0;
        }

        for (i = 0; i < numblocks; i++)
                info->lba_to_pba[i] = info->pba_to_lba[i] = UNDEF;

        return 1;
}

static void
sm_set_trivial_map(struct sm_card_info *info) {
        int numblocks = info->capacity >> (info->blockshift + info->pageshift);
        int i;

        /* No translation: PBA = LBA */
        for (i=0; i<numblocks; i++)
                info->pba_to_lba[i] = info->lba_to_pba[i] = i;

        printk("Note: no smartmedia translation today\n");
}

int
smartmedia_transport(Scsi_Cmnd *srb, struct us_data *us, struct sm_ops *sm) {
        static unsigned char sensekey = 0;
        static unsigned char sensecode = 0;
        static unsigned char havefakesense = 0;

        unsigned char *ptr;
        unsigned long capacity;
        unsigned int page, pages;
        int result;

        unsigned char inquiry_response[36] = {
                0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00
        };

        unsigned char mode_page_01[16] = {
                0x0F, 0x00, 0, 0x00,
                0x01, 0x0A,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
        };

        struct sm_card_info *info = us->extra;
        if (!info) {
                nand_init_ecc();
                sm_init_card_info((struct sm_card_info **) & us->extra);
                info = us->extra;
                if (!info)
                        return USB_STOR_TRANSPORT_ERROR;
        }

        ptr = (unsigned char *)srb->request_buffer;

        if (srb->cmnd[0] == REQUEST_SENSE) {
                if (havefakesense || !sm->sm_request_sense) {
                        memset(ptr, 0, srb->request_bufflen);
                        if (srb->request_bufflen > 7) {
                                ptr[0] = 0xF0;
                                ptr[2] = sensekey;
                                ptr[7] = srb->request_bufflen - 7;
                        }
                        if (srb->request_bufflen > 12)
                                ptr[12] = sensecode;
                        sensekey = sensecode = havefakesense = 0;
                        return USB_STOR_TRANSPORT_GOOD;
                } else {
                        return sm->sm_request_sense(us, srb, srb->cmd_len);
                }
        }

        havefakesense = 1;

        /* Dummy up a response for INQUIRY - it seems SmartMedia readers
           (sddr09, datafab) do not respond to INQUIRY commands */

        if (srb->cmnd[0] == INQUIRY) {
                memset(inquiry_response+8, 0, 28);
                fill_inquiry_response(us, inquiry_response, 36);
                return USB_STOR_TRANSPORT_GOOD;
        }

        if (srb->cmnd[0] == READ_CAPACITY) {
                struct nand_flash_dev *cardinfo;

                sm->sm_init(us);        /* get controlshift, read WP bit */

                cardinfo = sm_get_cardinfo(us, info->flags, sm);
                if (!cardinfo) {
                        /* probably no media */
                        sensekey = 0x02;        /* not ready */
                        sensecode = 0x3a;       /* medium not present */
                        return USB_STOR_TRANSPORT_FAILED;
                }

                info->capacity = (1 << cardinfo->chipshift);
                info->pageshift = cardinfo->pageshift;
                info->pagesize = (1 << info->pageshift);
                info->blockshift = cardinfo->blockshift;
                info->blocksize = (1 << info->blockshift);
                info->blockmask = info->blocksize - 1;

                // map initialization, must follow get_cardinfo()
                // Report capacity in 512-byte sectors

                if (smartmedia_control) {
                        /* no lba-pba available */
                        capacity = (1 << (cardinfo->chipshift -
                                          cardinfo->pageshift +
                                          info->controlshift - 9));
                } else if (smartmedia_raw) {
                        if (!smartmedia_allocate_map(info))
                                return USB_STOR_TRANSPORT_FAILED;
                        sm_set_trivial_map(info);
                        capacity = (info->capacity >> 9);
                } else {
                        sm->sm_read_map(us);
                        capacity = (info->capacity >> 16) * 125;
                }

                printk("sm: capacity = %ld sectors (%ld MB)\n",
                       capacity, ((capacity+1024) >> 11));

                // In fact, the number of the last sector
                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);

                // Report 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);

                return USB_STOR_TRANSPORT_GOOD;
        }

        if (srb->cmnd[0] == MODE_SENSE ||
            srb->cmnd[0] == MODE_SENSE_10) {

                // Read-write error recovery page: there needs to
                // be a check for write-protect here

                if ( (srb->cmnd[2] & 0x3F) == 0x01 ) {

                        US_DEBUGP(
                                "Dummy up request for mode page 1\n");

                        if (ptr == NULL || 
                            srb->request_bufflen<sizeof(mode_page_01))
                                return USB_STOR_TRANSPORT_ERROR;

                        mode_page_01[0] = sizeof(mode_page_01) - 1;
                        mode_page_01[2] = (info->flags & SMARTMEDIA_WP) ? 0x80 : 0;
                        memcpy(ptr, mode_page_01, sizeof(mode_page_01));
                        return USB_STOR_TRANSPORT_GOOD;

                } else if ( (srb->cmnd[2] & 0x3F) == 0x3F ) {

                        US_DEBUGP("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;

                }

                US_DEBUGP("Unexpected MODE_SENSE request\n");
                return USB_STOR_TRANSPORT_ERROR;
        }

        if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {

                US_DEBUGP("%s medium removal.\n",
                          (srb->cmnd[4] & 0x03) ? "Prevent" : "Allow");

                return USB_STOR_TRANSPORT_GOOD;

        }

        sensekey = sensecode = havefakesense = 0;

        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]);

                US_DEBUGP("READ_10: read page %d pagect %d\n",
                          page, pages);

                if (smartmedia_control) {
                        if (!sm->sm_read_control)
                                return USB_STOR_TRANSPORT_ERROR;
                        return sm->sm_read_control(us, page, pages,
                                                   ptr, srb->use_sg);
                }

                return sm_read_data(us, sm, page, pages, ptr, srb->use_sg);
        }

        if (srb->cmnd[0] == WRITE_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]);

                US_DEBUGP("WRITE_10: write page %d pagect %d\n",
                          page, pages);

                if (info->flags & (SMARTMEDIA_WP | SMARTMEDIA_RO)) {
                        sensekey = 0x07;        /* data protect */
                        sensecode = 0x27;       /* write protected */
                        havefakesense = 1;
                        return USB_STOR_TRANSPORT_FAILED;
                }
                return sm_write_data(us, sm, page, pages, ptr, srb->use_sg);
        }

        if (srb->cmnd[0] == TEST_UNIT_READY)
                return sm->sm_test_unit_ready(us, srb, srb->cmd_len);

        US_DEBUGP("Unknown SCSI request 0x%02X\n", srb->cmnd[0]);
        havefakesense = 1;
        return USB_STOR_TRANSPORT_ERROR;
}

_______________________________________________________________

Have big pipes? SourceForge.net is looking for download mirrors. We supply
the hardware. You get the recognition. Email Us: [EMAIL PROTECTED]
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to