📄 devmscd.c
字号:
/*************************************************************
* Philips USB Mass Storage Class driver (Device side)
*
* (c) 2002 Koninklijke Philips Electronics N.V., All rights reserved
*
* This source code and any compilation or derivative thereof is the
* proprietary information of Koninklijke Philips Electronics N.V.
* and is confidential in nature.
* Under no circumstances is this software to be exposed to or placed
* under an Open Source License of any type without the expressed
* written permission of Koninklijke Philips Electronics N.V.
*
* File Name: devmscd.c
*
* History:
*
* Version Date Author Comments
* -------------------------------------------------
* 1.0 09/23/02 SYARRA Initial Creation
* 1.21 08/04/03 SYARRA Stict checking of
* usb commands
*
* Note: use tab space 4
*************************************************************/
#include <linux/config.h>
#define MODULE
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/tqueue.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/segment.h>
#include <asm/io.h>
#include <linux/proc_fs.h>
#include <linux/poll.h>
#include "pdc_intf.h"
#include "devmscd.h"
#include "mscdbridge.h"
#include "pdc_bus.h"
#define devmscd_change_state(dev, new_state) dev->state = new_state
/*--------------------------------------------------------------*
* local variables declerations
*--------------------------------------------------------------*/
struct devmscd_device devmscd_dev;
struct pdc_urb read_urb, write_urb, csw_urb;
mscdbridge_req_t bridge_req;
mscd_req_t *bridge_read_req, *bridge_write_req;
struct pdc_pipe_desc bulk_pipe_desc[2];
#if 0
static char devmscd_state_name[DEVMSCD_DATA_OUT+1][20] = {
"DEVMSCD_IDLE ",
"DEVMSCD_CBW ",
"DEVMSCD_CSW ",
"DEVMSCD_DATA_IN ",
"DEVMSCD_DATA_OUT"
};
#endif
/*--------------------------------------------------------------*
* local function declerations
*--------------------------------------------------------------*/
static int devmscd_class_req(void *__dev, __u8 *req);
static int devmscd_configure(void *__dev, unsigned char cfg);
static void devmscd_reset(struct devmscd_device *dev);
static void devmscd_read_urb_complete(struct pdc_urb *urb);
static void devmscd_write_urb_complete(struct pdc_urb *urb);
static void devmscd_set_command_res(mscdbridge_req_t *req);
static int devmscd_read_data(__u8 *buff, __u32 bytes);
static int devmscd_write_data(__u8 *buff, __u32 bytes);
/*--------------------------------------------------------------*
* external function definitions
*--------------------------------------------------------------*/
/*
* This function currently supports read, write operations.
* Stores the request and calls the corresponding read or write function
* Currently queueing is not implemented
*/
int devmscd_submit_req(mscd_req_t *req)
{
int result = MSCD_SUCCESS;
func_debug(("devmscd_submit_req(%p)\n",req))
switch(req->req_type) {
case MSCD_READ:
/* Bridge wants to receive data from the USB Host */
if(!bridge_read_req) {
req->status = MSCD_PENDING;
bridge_read_req = req;
return devmscd_read_data(req->data_buff, req->req_data_len);
}
break;
case MSCD_WRITE:
/* Bridge wants to send data to the USB Host */
if(!bridge_write_req) {
req->status = MSCD_PENDING;
bridge_write_req = req;
return devmscd_write_data(req->data_buff, req->req_data_len);
}
break;
default:
result = MSCD_FAILED;
break;
}
return result;
} /* End of devmscd_submit_req */
/*
* This function currently supports read, write operations.
* rears the request and calls the corresponding usb device cancel operation
* Currently queueing is not implemented
*/
int devmscd_cancel_req(mscd_req_t *req)
{
int result = MSCD_SUCCESS;
func_debug(("devmscd_cancel_req(%p)\n",req))
switch(req->req_type) {
case MSCD_READ:
if(bridge_read_req) {
/* There is a read request pending, so clear this */
bridge_read_req = NULL;
if(read_urb.status != PDC_URB_COMPLETE)
return pdc_cancel_urb(&read_urb);
else return MSCD_SUCCESS;
}
break;
case MSCD_WRITE:
if(bridge_write_req) {
/* There is a write request pending, so clear this */
bridge_read_req = NULL;
if(write_urb.status != PDC_URB_COMPLETE)
return pdc_cancel_urb(&write_urb);
else return MSCD_SUCCESS;
}
break;
default:
/* Not supported */
result = MSCD_FAILED;
break;
}
return result;
} /* End of devmscd_cancel_req */
/*--------------------------------------------------------------*
* local function definitions
*--------------------------------------------------------------*/
/*
* Make the URB req and call the Peripheral controller driver
* read function
*/
int devmscd_read_data(__u8 *buff, __u32 bytes)
{
func_debug(("devmscd_read_data(%p,%x)\n",buff,bytes))
/* Fill the read URB */
read_urb.next = NULL;
read_urb.pipe = devmscd_dev.data_in_pipe;
read_urb.pipe_type = PDC_PIPE_BULK;
read_urb.operation = PDC_OPR_READ;
read_urb.status = PDC_URB_PENDING;
read_urb.transfer_buffer = buff;
read_urb.transfer_buffer_length = bytes;
read_urb.actual_length = 0x00;
read_urb.complete = devmscd_read_urb_complete; /* call back function */
return pdc_submit_urb(&read_urb);
} /* End of devmscd_read_data */
/*
* Make the URB req and call the Peripheral controller driver
* write function.
*/
int devmscd_write_data(__u8 *buff, __u32 bytes)
{
struct pdc_urb *urb;
func_debug(("devmscd_write_data(%p,%x)\n",buff,bytes))
if(bytes == DEVMSCD_CSW_LENGTH) urb = &csw_urb;
else urb = &write_urb;
/* Fill the wrtite URB */
urb->next = NULL;
urb->pipe = devmscd_dev.data_out_pipe;
read_urb.pipe_type = PDC_PIPE_BULK;
urb->operation = PDC_OPR_WRITE;
urb->status = PDC_URB_PENDING;
urb->transfer_buffer = buff;
urb->transfer_buffer_length = bytes;
urb->actual_length = 0x00;
urb->complete = devmscd_write_urb_complete;
/* transfer residue will be updated in the call back function */
return pdc_submit_urb(urb);
} /* End of devmscd_write_data */
/*
* If the command response is not success, stall the endpoint.
* Fill the CSW and send it to the host. Go back to IDLE state.
*/
void devmscd_set_command_res(mscdbridge_req_t *req)
{
struct devmscd_device *dev = &devmscd_dev;
__u8 status = req->status;
struct pdc_pipe_opr bulk_pipe_opr;
func_debug(("devmscd_set_command_res(%p)\n",req))
if(dev->state != DEVMSCD_IDLE) {
if((status != MSCD_SUCCESS) && (dev->cbw[12]&0x80)) {
/* Stall Bulk In End Point */
bulk_pipe_opr.handle = dev->data_out_pipe;
bulk_pipe_opr.context = (unsigned long) dev;
bulk_pipe_opr.opr = PDC_PIPE_STALL;
pdc_pipe_operation(&bulk_pipe_opr);
} else if(status == MSCD_SUCCESS && dev->tx_residue) {
if(read_urb.status == PDC_URB_COMPLETE && write_urb.status == PDC_URB_COMPLETE) {
mdelay(3);
bulk_pipe_opr.handle = dev->data_out_pipe;
bulk_pipe_opr.context = (unsigned long) dev;
bulk_pipe_opr.opr = PDC_PIPE_STALL;
pdc_pipe_operation(&bulk_pipe_opr);
} else {
dev->status_queue = 1;
}
}
/*
* Copy the transfer residue to the Command status Word
*/
dev->csw[8] = dev->tx_residue & 0xFF;
dev->csw[9] = (dev->tx_residue >> 8) & 0xFF;
dev->csw[10] = (dev->tx_residue >> 16) & 0xFF;
dev->csw[11] = (dev->tx_residue >> 24) & 0xFF;
dev->csw[12] = status;
devmscd_change_state(dev, DEVMSCD_CSW);
/* If no read or write operations are not in progress
* send the status to the host, else wait for the read,
* or write operation to finish
*/
if((read_urb.status == PDC_URB_COMPLETE && write_urb.status == PDC_URB_COMPLETE) && (dev->status_queue == 0)) {
devmscd_read_data(dev->cbw,DEVMSCD_CBW_LENGTH);
devmscd_change_state(dev, DEVMSCD_IDLE);
devmscd_write_data(dev->csw, DEVMSCD_CSW_LENGTH);
} else {
/* Wait for the data stage to finish */
dev->status_queue = 1;
}
} else {
/*
* Command response received in idle state , Might be a reset has done
* or .... Ignore this
*/
detail_debug(("Command response received in Invalid state, Ignored\n"))
}
} /* End of devmscd_set_command_res */
/*
* read URB complete function.
* In case of IDLE state, this is a CBW. Other cases it is a data request
* reurn
*/
void devmscd_read_urb_complete(struct pdc_urb *urb)
{
struct devmscd_device *dev = &devmscd_dev;
mscd_req_t *req;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -