diff options
Diffstat (limited to 'uClinux-2.4.20-uc1/drivers/usb/wbusbd/w90n745_mass.c')
-rw-r--r-- | uClinux-2.4.20-uc1/drivers/usb/wbusbd/w90n745_mass.c | 1066 |
1 files changed, 1066 insertions, 0 deletions
diff --git a/uClinux-2.4.20-uc1/drivers/usb/wbusbd/w90n745_mass.c b/uClinux-2.4.20-uc1/drivers/usb/wbusbd/w90n745_mass.c new file mode 100644 index 0000000..f7c5861 --- /dev/null +++ b/uClinux-2.4.20-uc1/drivers/usb/wbusbd/w90n745_mass.c @@ -0,0 +1,1066 @@ +/**************************************************************************** + * * + * Copyright (c) 2005 - 2007 Winbond Electronics Corp. All rights reserved. * + * * + ****************************************************************************/ + +/**************************************************************************** + * + * FILENAME + * w90n745_mass.c + * + * VERSION + * 1.0 + * + * DESCRIPTION + * Winbond W90N745 USBD mass storage driver + * + * DATA STRUCTURES + * None + * + * FUNCTIONS + * None + * + * HISTORY + * 2005/08/01 Ver 1.0 + * 2005/08/16 Ver 1.1 + * + * AUTHOR + * PC34 Lsshi + * + * REMARK + * None + *************************************************************************/ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <asm/hardware.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/smp_lock.h> +#include <linux/errno.h> +#include <linux/timer.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/proc_fs.h> +#include <linux/usb_ch9.h> +#include <scsi/scsi.h> +#include <linux/poll.h> +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/unaligned.h> + +#include "w90n745_mass.h" +//#define printk(fmt, ...) +#define DBGOUT(fmt, arg...) +//printk(fmt, ##arg) + +static const char driver_name [] = "Winbond W90N745 USB Device"; + +static int USB_Device[5] = { +0x01100112, 0x10000000, 0x96850416, 0x02010100, 0x00000100 }; + +static int USB_Config[10] = { +0x00270209, 0x40000101, 0x00040932, 0x05080300 , 0x05070050, 0x00400281, +0x02050701, 0x01004002, 0x03830507, 0x00010040 }; + +static int USB_Lang_Id_String[1] = { +0x04090304 }; + +static int USB_Vender_Id_String[4] = { +0x00570310, 0x004e0049, 0x004f0042, 0x0044004e }; + +static int USB_Device_Id_String[5] = { +0x00570312, 0x00390039, 0x00380036, 0x00430033, 0x00000046 }; + +static USB_INIT_T USBInit[6] = { + {0x00,0x000000e4}, //USB Control register + {0x08,0x000046f7}, //USB Interrupt Enable register + {0x14,0x00000030}, //USB Interface and string register + {0x38,0x00000000}, //USB SIE Status Register + {0x44,0x00000001}, //USB Configured Value register + {0x48,0x00000000} //USB Endpointer A Information register +}; + +static void USB_Init(wbusb_dev* dev); +static void USB_Irq_Init(wbusb_dev* dev); +static void SDRAM2USB_Bulk(wbusb_dev* dev,UINT8* buf ,UINT32 Tran_Size); +static void USB2SDRAM_Bulk(wbusb_dev* dev,UINT8* buf ,UINT32 Tran_Size); +static void SDRAM_USB_Transfer(wbusb_dev *dev,UINT8 epname,UINT8* buf ,UINT32 Tran_Size); +static UINT8 USB_Setup_Endpoint(wbusb_dev *dev,UINT8 epname,UINT8 epnum,UINT8 epdir,UINT8 eptype, + UINT8 epcon,UINT8 epinf,UINT16 epmaxps ); + + +void write_data(wbusb_dev *dev,UINT8* buf,UINT32 length); +void read_data(wbusb_dev *dev,UINT8* buf,UINT32 length); +int check_cbw(wbusb_dev *dev,void* cbw); + +static void start_write(wbusb_dev *dev,UINT8* buf,UINT32 length); +static void start_read(wbusb_dev *dev,UINT8* buf,UINT32 length); + +static void A_task_wake_up(wbusb_dev *dev);//write task + +static void B_task_block(wbusb_dev *dev);//idle and read task +static void B_task_wake_up(wbusb_dev *dev); + +#if 0 +static void dump_buffer(void *buf, int count) +{ + int i; + + printk("USB : "); + + for(i=0; i < count; i ++) + printk("%02x ", *((unsigned char *)buf + i)); + printk("\n"); + +} +#endif + +static void start_write(wbusb_dev *dev,UINT8* buf,UINT32 length) +{ + + DECLARE_WAITQUEUE(wait, current); + add_wait_queue(&dev->wusbd_wait_a, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + if(USB_READ(REG_USB_EPA_CTL)&0x00000004) + { + printk("device -> host DMA busy ...\n"); + goto quit; + } + + USB_WRITE(REG_USB_EPA_ADDR,(UINT32)buf);//Tell DMA the memory address + USB_WRITE(REG_USB_EPA_LENTH,length); + + USB_WRITE(REG_USB_EPA_CTL,USB_READ(REG_USB_EPA_CTL)|0x00000004);//The memory is ready for endpoint A to access + + schedule(); + +quit: + set_current_state(TASK_RUNNING); + remove_wait_queue(&dev->wusbd_wait_a, &wait); + + return ; +} + +static void start_read(wbusb_dev *dev,UINT8* buf,UINT32 length) +{ + + DECLARE_WAITQUEUE(wait, current); + add_wait_queue(&dev->wusbd_wait_b, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + if(USB_READ(REG_USB_EPB_CTL)&0x00000004) + { + printk("host -> device DMA busy ...\n"); + goto quit; + } + USB_WRITE(REG_USB_EPB_ADDR,(UINT32)buf);//Tell DMA the memory address + USB_WRITE(REG_USB_EPB_LENTH,length); + + USB_WRITE(REG_USB_EPB_CTL,USB_READ(REG_USB_EPB_CTL)|0x00000004);//The memory is ready for endpoint A to access + + schedule(); + +quit: + set_current_state(TASK_RUNNING); + remove_wait_queue(&dev->wusbd_wait_b, &wait); + + return ; +} + +#if 0 +static void A_task_block(wbusb_dev *dev) +{ + + + DECLARE_WAITQUEUE(wait, current); + add_wait_queue(&dev->wusbd_wait_a, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + schedule(); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&dev->wusbd_wait_a, &wait); + + return ; +} + +#endif + +static void A_task_wake_up(wbusb_dev *dev) +{ + + wake_up_interruptible(&dev->wusbd_wait_a); + + return ; +} + + +static void B_task_block(wbusb_dev *dev) +{ + + + DECLARE_WAITQUEUE(wait, current); + add_wait_queue(&dev->wusbd_wait_b, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + schedule(); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&dev->wusbd_wait_b, &wait); + + return ; +} + +static void B_task_wake_up(wbusb_dev *dev) +{ + + wake_up_interruptible(&dev->wusbd_wait_b); + + return ; +} + + +static UINT8 USB_Setup_Endpoint(wbusb_dev *dev,UINT8 epname,UINT8 epnum,UINT8 epdir,UINT8 eptype, + UINT8 epcon,UINT8 epinf,UINT16 epmaxps ) +{ + UINT32 tmp; + + if (epname == EP_A) + { + if ((epdir==Ep_In)&&(eptype==Ep_Bulk)&&(epcon==1)) + USB_WRITE(REG_USB_EPA_INFO,0x30000010); + else if ((epdir==Ep_In)&&(eptype==Ep_Int)&&(epcon==1)) + USB_WRITE(REG_USB_EPA_INFO,0x50000010); + else if ((epdir==Ep_In)&&(eptype==Ep_Iso)&&(epcon==1)) + USB_WRITE(REG_USB_EPA_INFO,0x70000010); + else if ((epdir==Ep_Out)&&(eptype==Ep_Bulk)&&(epcon==1)) + USB_WRITE(REG_USB_EPA_INFO,0x20000010); + else + return 0; + tmp = epinf; + tmp = tmp << 8; + USB_WRITE(REG_USB_EPA_INFO,(USB_READ(REG_USB_EPA_INFO)|tmp)); + tmp = epmaxps; + tmp = tmp << 16; + USB_WRITE(REG_USB_EPA_INFO,(USB_READ(REG_USB_EPA_INFO)|tmp)); + USB_WRITE(REG_USB_EPA_INFO,(USB_READ(REG_USB_EPA_INFO)|(epnum&0x0f))); + + dev->ep[EP_A].EP_Num = epnum; + dev->ep[EP_A].EP_Dir = epdir; + dev->ep[EP_A].EP_Type = eptype; + + USB_WRITE(REG_USB_EPA_CTL,0x00000001);//enable endpoint A + } + else if (epname == EP_B) + { + if ((epdir==Ep_In)&&(eptype==Ep_Bulk)&&(epcon==1)) + USB_WRITE(REG_USB_EPB_INFO,0x30000010); + else if ((epdir==Ep_In)&&(eptype==Ep_Int)&&(epcon==1)) + USB_WRITE(REG_USB_EPB_INFO,0x50000010); + else if ((epdir==Ep_In)&&(eptype==Ep_Iso)&&(epcon==1)) + USB_WRITE(REG_USB_EPB_INFO,0x70000010); + else if ((epdir==Ep_Out)&&(eptype==Ep_Bulk)&&(epcon==1)) + USB_WRITE(REG_USB_EPB_INFO,0x20000010); + else + return 0; + + tmp = epinf; + tmp = tmp << 8; + USB_WRITE(REG_USB_EPB_INFO,(USB_READ(REG_USB_EPB_INFO)|tmp)); + tmp = epmaxps; + tmp = tmp << 16; + USB_WRITE(REG_USB_EPB_INFO,(USB_READ(REG_USB_EPB_INFO)|tmp)); + USB_WRITE(REG_USB_EPB_INFO,(USB_READ(REG_USB_EPB_INFO)|(epnum&0x0f))); + + dev->ep[EP_B].EP_Num = epnum; + dev->ep[EP_B].EP_Dir = epdir; + dev->ep[EP_B].EP_Type = eptype; + USB_WRITE(REG_USB_EPB_CTL,0x00000001);//enable endpoint B + } + + + return 0; +} + +static void USB_Cmd_Parsing(wbusb_dev *dev) +{ + UINT32 cmd; + + cmd=USB_READ(USB_DEVICE+0x18); + dev->vcmd.Req_Type = cmd&0xff; + dev->vcmd.Req = (cmd>>8)&0xff; + + dev->vcmd.Value = (cmd>>16)&0xffff;//2,3 + cmd=USB_READ(USB_DEVICE+0x1c); + dev->vcmd.Index = cmd&0xffff;//4,5 + + dev->vcmd.Length = (cmd>>16)&0xffff;//6,7 + + if (dev->usb_enumstatus==GET_STR) + dev->vcmd.Index = 0; +} + +static void USB_All_Flag_Clear(wbusb_dev *dev) +{ + + DBGOUT("%s %d\n",__FUNCTION__,__LINE__); + dev->usb_enumstatus=0; +} + + + +static void Get_Dev_Dpr_In(wbusb_dev *dev) +{ + UINT8 i; + + DBGOUT("%s %d\n",__FUNCTION__,__LINE__); + + if (dev->vcmd.Length > 0) + { + if (dev->vcmd.Length <= 16) + { + USB_WRITE(REG_USB_CVCMD,dev->vcmd.Length); + } + else + { + dev->vcmd.Length = dev->vcmd.Length - 16; + USB_WRITE(REG_USB_CVCMD,0x10);//return data packet length is 16 + } + for (i = 0 ; i < USB_READ(REG_USB_CVCMD) ; i=i+4) + { + + switch(dev->usb_enumstatus) + { + + case GET_DEV: + USB_WRITE(REG_USB_IDATA0+i,USB_Device[dev->vcmd.Index]); + break; + + case GET_CFG: + USB_WRITE(REG_USB_IDATA0+i,USB_Config[dev->vcmd.Index]); + break; + + case GET_STR: + + if ((USB_READ(REG_USB_ODATA0)&0x00ff0000) == 0x00000000) + { + USB_WRITE(REG_USB_IDATA0+i,USB_Lang_Id_String[dev->vcmd.Index]); + } + if ((USB_READ(REG_USB_ODATA0)&0x00ff0000) == 0x00010000) + { + USB_WRITE(REG_USB_IDATA0+i,USB_Vender_Id_String[dev->vcmd.Index]); + } + if ((USB_READ(REG_USB_ODATA0)&0x00ff0000) == 0x00020000) + { + USB_WRITE(REG_USB_IDATA0+i,USB_Device_Id_String[dev->vcmd.Index]); + } + + break; + + default: + printk("%s %d\n",__FUNCTION__,__LINE__); + break; + + }//switch end + dev->vcmd.Index = dev->vcmd.Index + 1; + }//for end + } + else + USB_WRITE(REG_USB_CVCMD,0x00); + +} + +static void USB_Init(wbusb_dev *dev) +{ + int j; + + for (j=0 ; j<6 ; j++) + { + USB_WRITE(USB_DEVICE+USBInit[j].dwAddr,USBInit[j].dwValue); + } + + dev->epnum=ENDPOINTS; + + for (j=0 ; j<dev->epnum ; j++) + { + dev->ep[j].EP_Num = 0xff; + dev->ep[j].EP_Dir = 0xff; + dev->ep[j].EP_Type = 0xff; + + } + + USB_Setup_Endpoint(dev,EP_A,1,Ep_In,Ep_Bulk,1,0,64);//Endpointer A bulkin //device -> host + USB_Setup_Endpoint(dev,EP_B,2,Ep_Out,Ep_Bulk,1,0,64);//Endpointer B bulkout //host -> device + + + USB_WRITE(REG_USB_EPA_IE,(USB_READ(REG_USB_EPA_IE)|0x00000008));//enable DMA interrupt + USB_WRITE(REG_USB_EPB_IE,(USB_READ(REG_USB_EPB_IE)|0x00000008));//enable DMA interrupt + + USB_WRITE(REG_USB_CTL,(USB_READ(REG_USB_CTL)|0x00000001));//D+ high + +} + + +static void USB_ISR_Reset_Start(void) +{ + DBGOUT("%s %d\n",__FUNCTION__,__LINE__); +} + +static void USB_ISR_Reset_End(wbusb_dev *dev) +{ + if ((USB_READ(REG_USB_EPA_CTL)&0x00000004)==0x00000004) + { + USB_WRITE(REG_USB_EPA_CTL,USB_READ(REG_USB_EPA_CTL)&0xfffffffb);//clear dma + USB_WRITE(REG_USB_EPA_CTL,USB_READ(REG_USB_EPA_CTL)|0x00000004); + } + if ((USB_READ(REG_USB_EPB_CTL)&0x00000004)==0x00000004) + { + USB_WRITE(REG_USB_EPB_CTL,USB_READ(REG_USB_EPB_CTL)&0xfffffffb);//clear dma + USB_WRITE(REG_USB_EPB_CTL,USB_READ(REG_USB_EPB_CTL)|0x00000004); + } +} + +static void USB_ISR_Suspend(wbusb_dev *dev) +{ + + + if(dev->usb_online) + { + USB_All_Flag_Clear(dev); + + USB_WRITE(REG_USB_EPA_CTL,USB_READ(REG_USB_EPA_CTL)&0xfffffffb);//clear dma busy bit + USB_WRITE(REG_USB_EPB_CTL,USB_READ(REG_USB_EPB_CTL)&0xfffffffb); + + + dev->usb_online=0; + + A_task_wake_up(dev); + B_task_wake_up(dev); + + printk("USB plugout !\n"); + } + +} + +static void USB_ISR_Resume(void) +{ + DBGOUT("%s %d\n",__FUNCTION__,__LINE__); +} + +static void USB_ISR_Dev_Des(wbusb_dev* dev) +{ + USB_All_Flag_Clear(dev); + + dev->usb_enumstatus=GET_DEV; + + if(!dev->usb_online){ + + dev->usb_online=1; + + A_task_wake_up(dev); + B_task_wake_up(dev); + + printk("USB plugin !\n"); + } + + if ((USB_READ(REG_USB_CTLS)&0x0000001f) == 0x00000008)//check usb control transfer status register + { + USB_Cmd_Parsing(dev);//read setup data + if (dev->vcmd.Length <=(USB_Device[0]&0x000000ff)) + USB_WRITE(REG_USB_ENG,0x00000008);//ACK + else + { + dev->vcmd.Length = (USB_Device[0]&0x000000ff); + USB_WRITE(REG_USB_ENG,0x00000008); + } + } + else { + USB_WRITE(REG_USB_ENG,0x00000002);//return stall + } + +} + +static void USB_ISR_Conf_Des(wbusb_dev* dev) +{ + + USB_All_Flag_Clear(dev); + dev->usb_enumstatus=GET_CFG; + + if ((USB_READ(REG_USB_CTLS)&0x0000001f) == 0x00000008) + { + USB_Cmd_Parsing(dev); + if (dev->vcmd.Length <= ((USB_Config[0]&0x00ff0000)>>16))//configure total length + USB_WRITE(REG_USB_ENG,0x00000008); + else + { + dev->vcmd.Length = ((USB_Config[0]&0x00ff0000)>>16); + USB_WRITE(REG_USB_ENG,0x00000008); + } + } + else { + USB_WRITE(REG_USB_ENG,0x00000002); + } +} + +static void USB_ISR_Str_Des(wbusb_dev* dev) +{ + + USB_All_Flag_Clear(dev); + dev->usb_enumstatus=GET_STR; + + if ((USB_READ(REG_USB_CTLS)&0x0000001f) == 0x00000008) + { + USB_Cmd_Parsing(dev); + if ((USB_READ(REG_USB_ODATA0)&0x00ff0000) == 0x00000000) + { + if (dev->vcmd.Length <= (USB_Lang_Id_String[0]&0x000000ff)) + USB_WRITE(REG_USB_ENG,0x00000008); + else + { + dev->vcmd.Length = (USB_Lang_Id_String[0]&0x000000ff); + USB_WRITE(REG_USB_ENG,0x00000008); + } + } + if ((USB_READ(REG_USB_ODATA0)&0x00ff0000) == 0x00010000) + { + if (dev->vcmd.Length <= (USB_Vender_Id_String[0]&0x000000ff)) + USB_WRITE(REG_USB_ENG,0x00000008); + else + { + dev->vcmd.Length = (USB_Vender_Id_String[0]&0x000000ff); + USB_WRITE(REG_USB_ENG,0x00000008); + } + } + if ((USB_READ(REG_USB_ODATA0)&0x00ff0000) == 0x00020000) + { + if (dev->vcmd.Length <= (USB_Device_Id_String[0]&0x000000ff)) + USB_WRITE(REG_USB_ENG,0x00000008); + else + { + dev->vcmd.Length = (USB_Device_Id_String[0]&0x000000ff); + USB_WRITE(REG_USB_ENG,0x00000008); + } + } + } + else { + USB_WRITE(REG_USB_ENG,0x00000002); + } + +} + + +static void USB_ISR_CtlOut(void) +{ + + USB_WRITE(REG_USB_ENG,0x00000002); + USB_WRITE(REG_USB_ENG,0x00000008); + +} + + +void Outp_Byte(UINT32 addr,UINT8 value) +{ + UINT32 tmp1,tmp2; + + tmp1=USB_READ(addr&0xfffffffc); + tmp2=(UINT32)(value); + if (addr%4==0) + { + tmp1=tmp1&0xffffff00; + tmp1=tmp1|tmp2; + } + else if (addr%4==1) + { + tmp1=tmp1&0xffff00ff; + tmp1=tmp1|(tmp2<<8); + } + else if (addr%4==2) + { + tmp1=tmp1&0xff00ffff; + tmp1=tmp1|(tmp2<<16); + } + else if (addr%4==3) + { + tmp1=tmp1&0x00ffffff; + tmp1=tmp1|(tmp2<<24); + } + USB_WRITE((addr&0xfffffffc),tmp1); +} + +void Class_Data_In(void) +{ + + USB_WRITE(REG_USB_CVCMD,0x01); + Outp_Byte(REG_USB_IDATA0,0x00); +} + +void USB_ISR_Class_Cmd(wbusb_dev *dev) +{ + USB_All_Flag_Clear(dev); + + if(USB_READ(USB_DEVICE+0x18)==0xfea1) + { + dev->usb_enumstatus=CLA_CMD; + } + USB_WRITE(REG_USB_ENG,0x00000008); + +} + +static void USB_ISR_CtlIn(wbusb_dev *dev) +{ + + switch(dev->usb_enumstatus) + { + case CLA_CMD: + Class_Data_In(); + break; + + case GET_DEV: + case GET_CFG: + case GET_STR: + Get_Dev_Dpr_In(dev); + break; + + default: + USB_WRITE(REG_USB_ENG,0x00000002); + break; + + } + + USB_WRITE(REG_USB_ENG,0x00000001);//ACK for DATA-IN is Ready + +} + +static void USB_ISR_EpA_DMA_Complete(wbusb_dev *dev) +{ + + A_task_wake_up(dev); + + USB_WRITE(REG_USB_EPA_IC,0x00000008); + +} + + +static void USB_ISR_EpB_DMA_Complete(wbusb_dev *dev) +{ + if ((USB_READ(REG_USB_EPB_LENTH)-USB_READ(REG_USB_EPB_XFER))==0x0000001f) + dev->bulkonlycmd=1; + + B_task_wake_up(dev); + + USB_WRITE(REG_USB_EPB_IC,0x00000008); + + +} + + + +static void SDRAM_USB_Transfer(wbusb_dev *dev,UINT8 epname,UINT8* buf ,UINT32 Tran_Size) +{ + + if (epname == EP_A) + { + start_write(dev,buf,Tran_Size); + } + else if (epname == EP_B) + { + start_read(dev,buf,Tran_Size); + } + + return; + +} + +static void SDRAM2USB_Bulk(wbusb_dev *dev,UINT8* buf,UINT32 Tran_Size) +{ + + if ((dev->ep[EP_A].EP_Dir==Ep_In)&&(dev->ep[EP_A].EP_Type==Ep_Bulk)) + SDRAM_USB_Transfer(dev,EP_A,buf,Tran_Size); + else if ((dev->ep[EP_B].EP_Dir==Ep_In)&&(dev->ep[EP_B].EP_Type==Ep_Bulk)) + SDRAM_USB_Transfer(dev,EP_B,buf,Tran_Size); + + return; + +} + +static void USB2SDRAM_Bulk(wbusb_dev *dev, UINT8* buf ,UINT32 Tran_Size) +{ + + if ((dev->ep[EP_A].EP_Dir==Ep_Out)&&(dev->ep[EP_A].EP_Type==Ep_Bulk)) + SDRAM_USB_Transfer(dev,EP_A,buf,Tran_Size); + else if ((dev->ep[EP_B].EP_Dir==Ep_Out)&&(dev->ep[EP_B].EP_Type==Ep_Bulk)) + SDRAM_USB_Transfer(dev,EP_B,buf,Tran_Size); + + return; + +} + +void write_data(wbusb_dev *dev,UINT8* buf,UINT32 length) +{ + + if(!dev->usb_online) + return; + SDRAM2USB_Bulk(dev, buf,length); +} + +void read_data(wbusb_dev *dev,UINT8* buf,UINT32 length) +{ + + if(!dev->usb_online) + return; + USB2SDRAM_Bulk(dev,buf,length); +} + + +void paser_irq(int irq,wbusb_dev *dev) +{ + + switch(irq) + { + case RSTI: + USB_ISR_Reset_Start(); + break; + + case SUSI: + USB_ISR_Suspend(dev); + break; + + case RUMI: + USB_ISR_Resume(); + break; + + case GDEVI: + USB_ISR_Dev_Des(dev);//Get device Descriptor(); + break; + + case GCFGI: + USB_ISR_Conf_Des(dev); + break; + + case GSTRI: + USB_ISR_Str_Des(dev); + break; + + case CLAI: + USB_ISR_Class_Cmd(dev); + break; + + case CDOI: + USB_ISR_CtlOut(); + break; + + case CDII: + USB_ISR_CtlIn(dev); + break; + + case RST_ENDI: + USB_ISR_Reset_End(dev); + break; + + default: + //printk("irq: %d not handled !\n",irq); + break; + + } + + USB_WRITE(REG_USB_IC,(1<<(irq-1)));//clear irq bit + + return ; + +} + + +void wbusbd_irq(int irq, void *usbdev, struct pt_regs *r) +{ + UINT32 id,dmaid,i; + wbusb_dev *dev; + + dev=(wbusb_dev *)(usbdev); + + dmaid = USB_READ(REG_USB_EPA_IS); + + if (dmaid&0x00000008) + { + USB_ISR_EpA_DMA_Complete(dev); + } + + dmaid = USB_READ(REG_USB_EPB_IS); + + if (dmaid&0x00000008) + { + USB_ISR_EpB_DMA_Complete(dev); + } + + id = USB_READ(REG_USB_IS); + + for(i=0;i<16;i++) + { + if(id&(1<<i)) + paser_irq(i+1,dev); + } + + return; + + +} + +int check_cbw(wbusb_dev *dev,void* cbw) +{ + + if(!dev->usb_online) + { + B_task_block(dev); + return -1; + } + + USB2SDRAM_Bulk(dev,cbw,0x1f); + + if (dev->bulkonlycmd) + { + dev->bulkonlycmd=0;//If DMA complete and got 31 bytes command, this will be "1" + + //dump_buffer(cbw, 0x1f); + + return 0; + } + + return -1; + +} + +static int wbusb_installirq(wbusb_dev *dev) +{ + + if (request_irq(INT_USBD, wbusbd_irq, SA_SHIRQ/*|SA_SAMPLE_RANDOM*/, + driver_name, dev) != 0) { + + return -EBUSY; + } + + Enable_Int(INT_USBD); + + return 0; + +} + + +static void USB_Irq_Init(wbusb_dev *dev) +{ + + init_waitqueue_head(&dev->wusbd_wait_a);//write + init_waitqueue_head(&dev->wusbd_wait_b);//read + + if(wbusb_installirq(dev)==0) + DBGOUT("install usb device irq ok\n"); + + USB_WRITE(REG_USB_EPA_IE,(USB_READ(REG_USB_EPA_IE)|0x00000008));//enable DMA interrupt + USB_WRITE(REG_USB_EPB_IE,(USB_READ(REG_USB_EPB_IE)|0x00000008));//enable DMA interrupt + + return ; +} + + wbusb_dev *the_controller=NULL; + + void* wbusb_register_driver(void) + { + if(the_controller) + return the_controller; + else + return NULL; + } + + +void wbusbd_probe(void) +{ + + wbusb_dev *dev = 0; +#if 0 + void *mem_base; + + mem_base = ioremap_nocache (USB_DEVICE, USB_OFFSET); + + if (!mem_base) { + DBGOUT("Error mapping USB Device 1.1 memory !!!"); + release_mem_region (USB_DEVICE, USB_OFFSET); + return ; + } +#endif + /* alloc, and start init */ + dev = kmalloc (sizeof *dev, GFP_KERNEL); + if (dev == NULL){ + DBGOUT("kmalloc error !\n"); + goto done; + } + + memset(dev, 0, sizeof *dev); + + dev->rw_data=write_data; + dev->rd_data=read_data; + dev->wait_cbw=check_cbw; + + USB_Init(dev); + + USB_Irq_Init(dev); + + the_controller=dev; + +done: + + return ; + +} + +/**************************************************************/ +/*ns24 zswan add it ,change the usb device apply to mass nand for hisense*/ +/*change the syscall to char device---20061023,by ns24 zswan***********/ +/**************************************************************/ +static char buffer[4096]; +static size_t usb_client_read(char *buf, size_t length) +{ + char *tmp = (char *)((UINT32)buffer | 0x80000000); + + //printk("Buffer : %08x, Count : %08x\n", buf, length); + if(length == 0) + return 0; + + if(length > 4096) + length = 4096; + + read_data(the_controller, tmp, length); + + if(copy_to_user(buf, tmp, length)) + return -EFAULT; + return length; +} + +static size_t usb_client_write(const char *buf, size_t length) +{ + char *tmp = (char *)((UINT32)buffer | 0x80000000); + + //printk("Buffer : %08x, Count : %08x\n", buf, length); + + if(length == 0) + return 0; + + if(length > 4096) + length = 4096; + + if(copy_from_user(tmp, buf, length)) + return -EFAULT; + + write_data(the_controller, tmp, length); + + return length; +} + +static int usb_client_get_cbw(char *buf) +{ + int retval = 0; + char *tmp = (char *)((UINT32)buffer | 0x80000000); + + retval = check_cbw(the_controller, tmp); + + if(copy_to_user(buf, tmp, 0x1f)) + return -EFAULT; + + return 0; +} + +static int wbusb_open(struct inode *ip, struct file *filp) +{ + return 0; +} + +static int wbusb_release(struct inode *ip, struct file *filp) +{ + return 0; +} + +static ssize_t wbusb_read(struct file *filp, char* buf, size_t count, loff_t *lp) +{ + return usb_client_read(buf, count); +} + +static ssize_t wbusb_write(struct file *filp, const char * buf, size_t count, loff_t *lp) +{ + return usb_client_write(buf, count); +} +static int wbusb_ioctl(struct inode *ip, struct file *filp, unsigned int cmd, unsigned long arg) +{ + int err = 0; + int retval = 0; + + if (_IOC_TYPE(cmd) != WBUSB_IOC_MAGIC) return -ENOTTY; + if (_IOC_NR(cmd) > WBUSB_IOC_MAXNR) return -ENOTTY; + + + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + + if (err) return -EFAULT; + + switch(cmd) { + case WBUSB_IOC_GETCBW: + retval = usb_client_get_cbw((char *)arg); + break; + default: + return -ENOTTY; + } + + return retval; + +} + +/**************************************************************/ +//struct cdev wbusb_cdev; +struct file_operations wbusb_fops = { + .owner = THIS_MODULE, + .open = wbusb_open, + .release = wbusb_release, + .read = wbusb_read, + .write = wbusb_write, + .ioctl = wbusb_ioctl, +}; + +static int __init wbusb_init (void) +{ + #ifdef CONFIG_BOARD_W90N745 + int result = -ENODEV; + DBGOUT("W90N745 USB Device Driver 1.0 ...\n"); + wbusbd_probe(); + result = register_chrdev(WBUSB_MAJOR, "usbclient", &wbusb_fops); + if( result < 0){ + unregister_chrdev(WBUSB_MAJOR, "usbclient"); + printk("can't get major %d\n", WBUSB_MAJOR); + return result; + } + + printk("Usb device driver by ns24 zswan designed successfully!\n"); + return 0; +#else + return 0; + +#endif +} + +static void wbusb_cleanup (void) +{ + DBGOUT("%s %d\n",__FUNCTION__,__LINE__); + unregister_chrdev(WBUSB_MAJOR, "usbclient"); + //return ; + +} + +module_init(wbusb_init); +module_exit(wbusb_cleanup); |