// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for SanDisk SDDR-55 SmartMedia reader
*
* SDDR55 driver v0.1:
*
* First release
*
* Current development and maintenance by:
* (c) 2002 Simon Munton
*/
#include <linux/jiffies.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include "usb.h"
#include "transport.h"
#include "protocol.h"
#include "debug.h"
#include "scsiglue.h"
#define DRV_NAME "ums-sddr55"
MODULE_DESCRIPTION("Driver for SanDisk SDDR-55 SmartMedia reader");
MODULE_AUTHOR("Simon Munton");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(USB_STORAGE);
/*
* The table of devices
*/
#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
vendorName, productName, useProtocol, useTransport, \
initFunction, flags) \
{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
.driver_info = (flags) }
static struct usb_device_id sddr55_usb_ids[] = {
# include "unusual_sddr55.h"
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, sddr55_usb_ids);
#undef UNUSUAL_DEV
/*
* The flags table
*/
#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
vendor_name, product_name, use_protocol, use_transport, \
init_function, Flags) \
{ \
.vendorName = vendor_name, \
.productName = product_name, \
.useProtocol = use_protocol, \
.useTransport = use_transport, \
.initFunction = init_function, \
}
static struct us_unusual_dev sddr55_unusual_dev_list[] = {
# include "unusual_sddr55.h"
{ } /* Terminating entry */
};
#undef UNUSUAL_DEV
#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
#define LSB_of(s) ((s)&0xFF)
#define MSB_of(s) ((s)>>8)
#define PAGESIZE 512
#define set_sense_info(sk, asc, ascq) \
do { \
info->sense_data[2] = sk; \
info->sense_data[12] = asc; \
info->sense_data[13] = ascq; \
} while (0)
struct sddr55_card_info {
unsigned long capacity; /* Size of card in bytes */
int max_log_blks; /* maximum number of logical blocks */
int pageshift; /* log2 of pagesize */
int smallpageshift; /* 1 if pagesize == 256 */
int blocksize; /* Size of block in pages */
int blockshift; /* log2 of blocksize */
int blockmask; /* 2^blockshift - 1 */
int read_only; /* non zero if card is write protected */
int force_read_only; /* non zero if we find a map error*/
int *lba_to_pba; /* logical to physical map */
int *pba_to_lba; /* physical to logical map */
int fatal_error; /* set if we detect something nasty */
unsigned long last_access; /* number of jiffies since we last talked to device */
unsigned char sense_data[18];
};
#define NOT_ALLOCATED 0xffffffff
#define BAD_BLOCK 0xffff
#define CIS_BLOCK 0x400
#define UNUSED_BLOCK 0x3ff
static int
sddr55_bulk_transport(struct us_data *us, int direction,
unsigned char *data, unsigned int len) {
struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
unsigned int pipe = (direction == DMA_FROM_DEVICE) ?
us->recv_bulk_pipe : us->send_bulk_pipe;
if (!len)
return USB_STOR_XFER_GOOD;
info->last_access = jiffies;
return usb_stor_bulk_transfer_buf(us, pipe, data, len, NULL);
}
/*
* check if card inserted, if there is, update read_only status
* return non zero if no card
*/
static int sddr55_status(struct us_data *us)
{
int result;
unsigned char *command = us->iobuf;
unsigned char *status = us->iobuf;
struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
/* send command */
memset(command, 0, 8);
command[5] = 0xB0;
command[7] = 0x80;
result = sddr55_bulk_transport(us,
DMA_TO_DEVICE, command, 8);
usb_stor_dbg(us, "Result for send_command in status %d\n", result);
if (result != USB_STOR_XFER_GOOD) {
set_sense_info (4, 0, 0); /* hardware error */
return USB_STOR_TRANSPORT_ERROR;
}
result = sddr55_bulk_transport(us,
DMA_FROM_DEVICE, status, 4);
/* expect to get short transfer if no card fitted */
if (result == USB_STOR_XFER_SHORT || result == USB_STOR_XFER_STALLED) {
/* had a short transfer, no card inserted, free map memory */
kfree(info->lba_to_pba);
kfree(info->pba_to_lba);
info->lba_to_pba = NULL;
info->pba_to_lba = NULL;
info->fatal_error = 0;
info->force_read_only = 0;
set_sense_info (2, 0x3a, 0); /* not ready, medium not present */
return USB_STOR_TRANSPORT_FAILED;
}
if (result != USB_STOR_XFER_GOOD) {
set_sense_info (4, 0, 0); /* hardware error */
return USB_STOR_TRANSPORT_FAILED;
}
/* check write protect status */
info->read_only = (status[0] & 0x20);
/* now read status */
result = sddr55_bulk_transport(us,
DMA_FROM_DEVICE, status, 2);
if (result