⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sddr09.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Driver for SanDisk SDDR-09 SmartMedia reader * * $Id: sddr09.c,v 1.22 2001/12/08 23:32:48 mdharm Exp $ * * SDDR09 driver v0.1: * * First release * * Current development and maintenance by: *   (c) 2000, 2001 Robert Baruch (autophile@starband.net) * * The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip. * This chip is a programmable USB controller. In the SDDR-09, it has * been programmed to obey a certain limited set of SCSI commands. This * driver translates the "real" SCSI commands to the SDDR-09 SCSI * commands. * * 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 "sddr09.h"#include <linux/sched.h>#include <linux/errno.h>#include <linux/slab.h>#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )#define LSB_of(s) ((s)&0xFF)#define MSB_of(s) ((s)>>8)/* * Send a control message and wait for the response. * * us - the pointer to the us_data structure for the device to use * * request - the URB Setup Packet's first 6 bytes. The first byte always *  corresponds to the request type, and the second byte always corresponds *  to the request.  The other 4 bytes do not correspond to value and index, *  since they are used in a custom way by the SCM protocol. * * xfer_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. * * xfer_len - the number of bytes to send or receive with the URB. * */static int sddr09_send_control(struct us_data *us,		int pipe,		unsigned char request,		unsigned char requesttype,		unsigned short value,		unsigned short index,		unsigned char *xfer_data,		unsigned int xfer_len) {	int result;	// If data is going to be sent or received with the URB,	// then allocate a buffer for it. If data is to be sent,	// copy the data into the buffer./*	if (xfer_len > 0) {		buffer = kmalloc(xfer_len, GFP_NOIO);		if (!(command[0] & USB_DIR_IN))			memcpy(buffer, xfer_data, xfer_len);	}*/	// Send the URB to the device and wait for a response.	/* Why are request and request type reversed in this call? */	result = usb_stor_control_msg(us, pipe,			request, requesttype, value, index,			xfer_data, xfer_len);	// If data was sent or received with the URB, free the buffer we	// allocated earlier, but not before reading the data out of the	// buffer if we wanted to receive data./*	if (xfer_len > 0) {		if (command[0] & USB_DIR_IN)			memcpy(xfer_data, buffer, xfer_len);		kfree(buffer);	}*/	// Check the return code for the command.	if (result < 0) {		/* if the command was aborted, indicate that */		if (result == -ENOENT)			return USB_STOR_TRANSPORT_ABORTED;		/* a stall is a fatal condition from the device */		if (result == -EPIPE) {			US_DEBUGP("-- Stall on control pipe. Clearing\n");			result = usb_clear_halt(us->pusb_dev, pipe);			US_DEBUGP("-- usb_clear_halt() returns %d\n", result);			return USB_STOR_TRANSPORT_FAILED;		}		/* Uh oh... serious problem here */		return USB_STOR_TRANSPORT_ERROR;	}	return USB_STOR_TRANSPORT_GOOD;}static int sddr09_raw_bulk(struct us_data *us, 		int direction,		unsigned char *data,		unsigned int len) {	int result;	int act_len;	int pipe;	if (direction == SCSI_DATA_READ)		pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);	else		pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);	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("usbat_raw_bulk():"				" device NAKed\n");                        return US_BULK_TRANSFER_FAILED;                }                /* -ENOENT -- we canceled this transfer */                if (result == -ENOENT) {                        US_DEBUGP("usbat_raw_bulk():"				" transfer aborted\n");                        return US_BULK_TRANSFER_ABORTED;                }		if (result == -EPIPE) {			US_DEBUGP("usbat_raw_bulk():"				" output pipe stalled\n");			return USB_STOR_TRANSPORT_FAILED;		}                /* the catch-all case */                US_DEBUGP("us_transfer_partial(): 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;	}	US_DEBUGP("Transferred %d of %d bytes\n", act_len, len);	return US_BULK_TRANSFER_GOOD;}/* * Note: direction must be set if command_len == 0. */static int sddr09_bulk_transport(struct us_data *us,			  int direction,			  unsigned char *data,			  unsigned int len,			  int use_sg) {	int result = USB_STOR_TRANSPORT_GOOD;	int transferred = 0;	int i;	struct scatterlist *sg;	char string[64];	if (len==0)		return USB_STOR_TRANSPORT_GOOD;	/* transfer the data */	if (direction == SCSI_DATA_WRITE) {		/* Debug-print the first 48 bytes of the write transfer */		if (!use_sg) {			strcpy(string, "wr: ");			for (i=0; i<len && i<48; i++) {				sprintf(string+strlen(string), "%02X ",				  data[i]);				if ((i%16)==15) {					US_DEBUGP("%s\n", string);					strcpy(string, "wr: ");				}			}			if ((i%16)!=0)				US_DEBUGP("%s\n", string);		}	}	US_DEBUGP("SCM data %s transfer %d sg buffers %d\n",		  ( direction==SCSI_DATA_READ ? "in" : "out"),		  len, use_sg);	if (!use_sg)		result = sddr09_raw_bulk(us, direction, data, len);	else {		sg = (struct scatterlist *)data;		for (i=0; i<use_sg && transferred<len; i++) {			result = sddr09_raw_bulk(us, direction,				sg[i].address, 				len-transferred > sg[i].length ?					sg[i].length : len-transferred);			if (result!=US_BULK_TRANSFER_GOOD)				break;			transferred += sg[i].length;		}	}	if (direction == SCSI_DATA_READ) {		/* Debug-print the first 48 bytes of the read transfer */		if (!use_sg) {			strcpy(string, "rd: ");			for (i=0; i<len && i<48; i++) {				sprintf(string+strlen(string), "%02X ",				  data[i]);				if ((i%16)==15) {					US_DEBUGP("%s\n", string);					strcpy(string, "rd: ");				}			}			if ((i%16)!=0)				US_DEBUGP("%s\n", string);		}	}	return result;}int sddr09_read_data(struct us_data *us,		unsigned long address,		unsigned short sectors,		unsigned char *content,		int use_sg) {	int result;	unsigned char command[12] = {		0xe8, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0	};	struct sddr09_card_info *info = (struct sddr09_card_info *)us->extra;	unsigned int lba;	unsigned int pba;	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_NOIO);		if (buffer == NULL)			return USB_STOR_TRANSPORT_ERROR;		ptr = buffer;	} else		ptr = content;	// Figure out the initial LBA and page	pba = address >> (info->pageshift + info->blockshift);	lba = info->pba_to_lba[pba];	page = (address >> info->pageshift) & info->blockmask;	// This could be made much more efficient by checking for	// contiguous LBA's. Another exercise left to the student.	while (sectors>0) {		pba = info->lba_to_pba[lba];		// Read as many sectors as possible in this block		pages = info->blocksize - page;		if (pages > sectors)			pages = sectors;		US_DEBUGP("Read %02X pages, from PBA %04X"			" (LBA %04X) page %02X\n",			pages, pba, lba, page);		address = ( (pba << info->blockshift) + page ) << 			info->pageshift;		// Unlike in the documentation, the address is in		// words of 2 bytes.		command[2] = MSB_of(address>>17);		command[3] = LSB_of(address>>17); 		command[4] = MSB_of((address>>1)&0xFFFF);		command[5] = LSB_of((address>>1)&0xFFFF); 		command[10] = MSB_of(pages);		command[11] = LSB_of(pages);		result = sddr09_send_control(us,			usb_sndctrlpipe(us->pusb_dev,0),			0,			0x41,			0,			0,			command,			12);		US_DEBUGP("Result for send_control in read_data %d\n",			result);		if (result != USB_STOR_TRANSPORT_GOOD) {			if (use_sg)				kfree(buffer);			return result;		}		result = sddr09_bulk_transport(us,			SCSI_DATA_READ, ptr,			pages<<info->pageshift, 0);		if (result != USB_STOR_TRANSPORT_GOOD) {			if (use_sg)				kfree(buffer);			return result;		}		page = 0;		lba++;		sectors -= pages;		ptr += (pages << info->pageshift);	}	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;}int sddr09_read_control(struct us_data *us,		unsigned long address,		unsigned short blocks,		unsigned char *content,		int use_sg) {	// Unlike in the documentation, the last two bytes are the	// number of blocks, not sectors.	int result;	unsigned char command[12] = {		0xe8, 0x21, MSB_of(address>>16),		LSB_of(address>>16), MSB_of(address&0xFFFF),		LSB_of(address&0xFFFF), 0, 0, 0, 0,		MSB_of(blocks), LSB_of(blocks)	};	US_DEBUGP("Read control address %08lX blocks %04X\n",		address, blocks);	result = sddr09_send_control(us,		usb_sndctrlpipe(us->pusb_dev,0),		0,		0x41,		0,		0,		command,		12);	US_DEBUGP("Result for send_control in read_control %d\n",		result);	if (result != USB_STOR_TRANSPORT_GOOD)		return result;	result = sddr09_bulk_transport(us,		SCSI_DATA_READ, content,		blocks<<6, use_sg); // 0x40 bytes per block	US_DEBUGP("Result for bulk read in read_control %d\n",		result);	return result;}int sddr09_read_deviceID(struct us_data *us,		unsigned char *manufacturerID,		unsigned char *deviceID) {	int result;	unsigned char command[12] = {		0xed, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0	};	unsigned char content[64];	result = sddr09_send_control(us,		usb_sndctrlpipe(us->pusb_dev,0),		0,		0x41,		0,		0,		command,		12);	US_DEBUGP("Result of send_control for device ID is %d\n",		result);	if (result != USB_STOR_TRANSPORT_GOOD)		return result;	result = sddr09_bulk_transport(us,		SCSI_DATA_READ, content,		64, 0);	*manufacturerID = content[0];	*deviceID = content[1];	return result;}int sddr09_read_status(struct us_data *us,		unsigned char *status) {	int result;	unsigned char command[12] = {		0xec, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0	};	result = sddr09_send_control(us,		usb_sndctrlpipe(us->pusb_dev,0),		0,		0x41,		0,		0,		command,		12);	if (result != USB_STOR_TRANSPORT_GOOD)		return result;	result = sddr09_bulk_transport(us,		SCSI_DATA_READ, status,		1, 0);	return result;}int sddr09_reset(struct us_data *us) {	int result;	unsigned char command[12] = {		0xeb, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0	};	result = sddr09_send_control(us,		usb_sndctrlpipe(us->pusb_dev,0),		0,		0x41,		0,		0,		command,		12);	return result;}unsigned long sddr09_get_capacity(struct us_data *us,		unsigned int *pagesize, unsigned int *blocksize) {	unsigned char manufacturerID;	unsigned char deviceID;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -