summaryrefslogtreecommitdiffstats
path: root/uClinux-2.4.20-uc1/drivers/usb/wbusbd/w90n745_vcom.c
diff options
context:
space:
mode:
Diffstat (limited to 'uClinux-2.4.20-uc1/drivers/usb/wbusbd/w90n745_vcom.c')
-rw-r--r--uClinux-2.4.20-uc1/drivers/usb/wbusbd/w90n745_vcom.c1477
1 files changed, 1477 insertions, 0 deletions
diff --git a/uClinux-2.4.20-uc1/drivers/usb/wbusbd/w90n745_vcom.c b/uClinux-2.4.20-uc1/drivers/usb/wbusbd/w90n745_vcom.c
new file mode 100644
index 0000000..9fecdc3
--- /dev/null
+++ b/uClinux-2.4.20-uc1/drivers/usb/wbusbd/w90n745_vcom.c
@@ -0,0 +1,1477 @@
+/****************************************************************************
+ * *
+ * Copyright (c) 2005 - 2007 Winbond Electronics Corp. All rights reserved. *
+ * *
+ ****************************************************************************/
+
+/****************************************************************************
+ *
+ * FILENAME
+ * w90n745_vcom.c
+ *
+ * VERSION
+ * 1.0
+ *
+ * DESCRIPTION
+ * Winbond W90N745 USBD VCOM 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/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+//#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+
+#include <linux/fs.h>
+//#include <linux/cdev.h>
+
+#include <asm/uaccess.h>
+#include <asm/arch/hardware.h>
+#include <asm/io.h>
+#include <linux/usb.h>
+
+#include "w90n745_vcom.h"
+//#define printk(fmt, ...)
+#define DBGOUT(fmt, arg...) //printk(fmt, ##arg)
+
+//#define printk(fmt...)
+
+/* Configure USBD as VCOM in the beginning */
+#define USBDVCOM /* 2007.11.29 add, PT23 HHWu */
+
+//#define SD_DEBUG
+//#define SD_DEBUG_PRINT_LINE
+#define SD_DEBUG_ENABLE_ENTER_LEAVE
+//#define SD_DEBUG_ENABLE_MSG
+//#define SD_DEBUG_ENABLE_MSG2
+
+#ifdef SD_DEBUG
+#define PDEBUG(fmt, arg...) printk(fmt, ##arg)
+#else
+#define PDEBUG(fmt, arg...)
+#endif
+
+#ifdef SD_DEBUG_PRINT_LINE
+#define PRN_LINE() PDEBUG("[%-20s] : %d\n", __FUNCTION__, __LINE__)
+#else
+#define PRN_LINE()
+#endif
+
+#ifdef SD_DEBUG_ENABLE_ENTER_LEAVE
+#define ENTER() PDEBUG("[%-20s] : Enter...\n", __FUNCTION__)
+#define LEAVE() PDEBUG("[%-20s] : Leave...\n", __FUNCTION__)
+#else
+#define ENTER()
+#define LEAVE()
+#endif
+
+#ifdef SD_DEBUG_ENABLE_MSG
+#define MSG(msg) PDEBUG("[%-20s] : %s\n", __FUNCTION__, msg)
+#else
+#define MSG(msg)
+#endif
+
+#ifdef SD_DEBUG_ENABLE_MSG2
+#define MSG2(fmt, arg...) PDEBUG("[%-20s] : "fmt, __FUNCTION__, ##arg)
+#define PRNBUF(buf, count) {int i;MSG2("CID Data: ");for(i=0;i<count;i++)\
+ PDEBUG("%02x ", buf[i]);PDEBUG("\n");}
+#else
+#define MSG2(fmt, arg...)
+#define PRNBUF(buf, count)
+#endif
+
+
+
+
+static const char driver_name [] = "Winbond W90N745 USB Device";
+
+
+static int USB_Device_Mass[5] = {
+0x01100112, 0x10000000, 0x96850416, 0x02010100, 0x00000100 };
+
+static int USB_Device_VCOM[5] = {
+0x01100112, 0x10000000, 0x70210416/*pid & vid*/, 0x02010100, 0x00000100 };
+
+////////////////////////////////////////////////////////////////////////////
+
+static int USB_Config_Mass[10] = {
+0x00270209, 0x40000101, 0x00040932, 0x05080300 , 0x05070050, 0x00400281,
+0x02050701, 0x01004002, 0x03830507, 0x00010040 };
+
+static int USB_Config_VCOM[8] = {
+0x00200209, 0x40000101, 0x00040932, 0x00000200 , 0x05070000, 0x00400281,
+0x02050701, 0x01004002 };
+
+////////////////////////////////////////////////////////////////////////////
+
+static int USB_Lang_Id_String[1] = {
+0x04090304 };
+
+////////////////////////////////////////////////////////////////////////////
+
+static int USB_Vender_Id_String_Mass[4] = {
+0x00570310, 0x004e0049, 0x004f0042, 0x0044004e };
+
+static int USB_Vender_Id_String_VCOM[6] = {
+0x00550316, 0x00420053, 0x00440020, 0x00760065, 0x00630069 ,0x00000065};
+
+////////////////////////////////////////////////////////////////////////////
+
+static int USB_Device_Id_String_Mass[5] = {
+0x00570312, 0x00390039, 0x00380036, 0x00430033, 0x00000046 };
+
+static int USB_Device_Id_String_VCOM[12] = {
+0x0057032E, 0x00390039, 0x00300037, 0x00200032, 0x00530055, 0x00200042, 0x00690056,
+0x00740072, 0x00610075, 0x0020006C, 0x004F0043, 0x0000004D};
+
+////////////////////////////////////////////////////////////////////////////
+static unsigned int* USB_Device;
+static unsigned int* USB_Config;
+static unsigned int* USB_Device_Id_String;
+static unsigned int* USB_Vender_Id_String;
+
+static USB_INIT_T USBInit[6] = {
+ {0x00,0x000000e4}, //USB Control register
+ {0x08,0x000047f7}, //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 int bCBlockFlag = 0;
+
+
+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);
+
+static void C_task_block(wbusb_dev *dev);//vcom vendor
+static void C_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
+
+void __usleep(int count)
+{
+ int i=0;
+
+ for(i=0;i<count;i++);
+
+}
+
+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 void C_task_block(wbusb_dev *dev)
+{
+
+ ENTER();
+#if 0
+ DECLARE_WAITQUEUE(wait, current);
+ add_wait_queue(&dev->wusbd_wait_c, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ schedule();
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&dev->wusbd_wait_c, &wait);
+
+#else
+
+ bCBlockFlag = 0;
+ wait_event_interruptible(dev->wusbd_wait_c, bCBlockFlag != 0);
+#endif
+
+ LEAVE();
+
+ return ;
+}
+
+static void C_task_wake_up(wbusb_dev *dev)
+{
+ ENTER();
+
+#if 1
+ bCBlockFlag = 1;
+ wake_up_interruptible(&dev->wusbd_wait_c);
+
+ //printk("bCBlockFlag:%x\n",bCBlockFlag);
+
+#endif
+ LEAVE();
+
+ 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(W90N745_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(W90N745_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);
+
+}
+
+int Disable_USB(wbusb_dev *dev)
+{
+ ENTER();
+
+ USB_WRITE(REG_USB_CTL,0x0);//disable usb enginee
+ Disable_Int(INT_USBD);
+ free_irq(INT_USBD,dev);
+
+ __usleep(1000);
+
+ LEAVE();
+
+ return 0;
+
+}
+
+
+
+int Enable_USB(wbusb_dev *dev)
+{
+ ENTER();
+
+ USB_Init(dev);
+ USB_Irq_Init(dev);
+ __usleep(1000);
+
+ LEAVE();
+
+ return 0;
+}
+
+void Reset_USB(wbusb_dev *dev)
+{
+ ENTER();
+
+ printk("Disable USB now ...\n");
+ Disable_USB(dev);
+ __usleep(1000000);
+ printk("Enable USB now ...\n");
+ Enable_USB(dev);
+
+ LEAVE();
+}
+
+static void USB_Init(wbusb_dev *dev)
+{
+ int j;
+
+ ENTER();
+
+ for (j=0 ; j<6 ; j++)
+ {
+ USB_WRITE(W90N745_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;
+
+ }
+
+ dev->bulk_len=0;
+
+ 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
+
+ LEAVE();
+
+}
+
+
+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__);
+}
+
+
+void USB_ISR_Vendor_Cmd(wbusb_dev* dev)
+{
+
+ USB_All_Flag_Clear(dev);
+
+
+
+ if ((USB_READ(REG_USB_CTLS)&0x0000001f) == 0x00000008)
+ {
+ USB_Cmd_Parsing(dev);
+
+ if (dev->vcmd.Req_Type == 0x40)
+ {
+ dev->bulk_len=0;
+ dev->usb_enumstatus=VEN_CMDOUT;
+
+
+
+ if (dev->vcmd.Req == 0xA0)
+ {
+ if (dev->vcmd.Value == 0x12)
+ {
+ //VCOM PC driver Vendor CMD
+
+ dev->bulk_len=dev->vcmd.Index;
+ USB_WRITE(REG_USB_IE,USB_READ(REG_USB_IE)&0xfffffeff);//disable vender interrupt enable
+ C_task_wake_up(dev);
+ }
+ else if (dev->vcmd.Value == 0x13)
+ {
+
+ USB_WRITE(REG_USB_IE,USB_READ(REG_USB_IE)|0x00000100);//enable vender interrupt enable
+
+ if ((USB_READ(REG_USB_EPB_CTL)&0x00000004)==0x00000004)
+ {
+ USB_WRITE(REG_USB_EPB_CTL,USB_READ(REG_USB_EPB_CTL)|0x00000002);//reset
+ USB_WRITE(REG_USB_EPB_CTL,USB_READ(REG_USB_EPB_CTL)&0xfffffffd);
+ }
+ if ((USB_READ(REG_USB_EPB_CTL)&0x00000004)==0x00000004)
+ USB_WRITE(REG_USB_EPB_CTL,USB_READ(REG_USB_EPB_CTL)&0xfffffffb);//clear ready
+ }
+ }
+ }
+ else if (dev->vcmd.Req_Type == 0xc0)
+ dev->usb_enumstatus = VEN_CMDIN;
+ else
+ USB_WRITE(REG_USB_ENG,0x00000002);
+
+ }
+ else {
+ USB_WRITE(REG_USB_ENG,0x00000002);
+ }
+ USB_WRITE(REG_USB_ENG,0x00000008);
+ USB_WRITE(REG_USB_IC,0x00000100);
+}
+
+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);
+ }
+
+}
+
+void Vender_Data_Out(wbusb_dev* dev)
+{
+
+ if ((USB_READ(REG_USB_CTLS)&0x0000001f) != 0)
+ {
+
+ dev->vcmd.Index = dev->vcmd.Index + (USB_READ(REG_USB_CTLS)&0x0000001f);
+ dev->vcmd.Length = dev->vcmd.Length - (USB_READ(REG_USB_CTLS)&0x0000001f);;
+
+ }
+
+}
+
+
+
+static void USB_ISR_CtlOut(wbusb_dev* dev)
+{
+
+ if(dev->usb_enumstatus==VEN_CMDOUT)
+ {
+
+ Vender_Data_Out(dev);
+ }
+
+ 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 Vender_Data_In(wbusb_dev *dev)
+{
+ //UINT8 i;
+ // UINT32 tmp;
+
+
+
+ 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);
+ }
+
+ if (dev->vcmd.Req == 0x00)
+ {
+ printk("%s %d\n",__FUNCTION__,__LINE__);
+
+ }else if (dev->vcmd.Req == 0x10)
+ {
+ printk("%s %d\n",__FUNCTION__,__LINE__);
+ }else if (dev->vcmd.Req == 0x04)
+ {
+ printk("%s %d\n",__FUNCTION__,__LINE__);
+ }
+ }
+ else
+ USB_WRITE(REG_USB_CVCMD,0x00);
+}
+
+
+void USB_ISR_Class_Cmd(wbusb_dev *dev)
+{
+ USB_All_Flag_Clear(dev);
+
+ if(USB_READ(W90N745_USB_DEVICE+0x18)==0xfea1)
+ {
+ dev->usb_enumstatus=CLA_CMDIN;
+ }
+ USB_WRITE(REG_USB_ENG,0x00000008);
+
+}
+
+static void USB_ISR_CtlIn(wbusb_dev *dev)
+{
+
+ switch(dev->usb_enumstatus)
+ {
+ case CLA_CMDIN:
+ Class_Data_In();
+ break;
+
+ case VEN_CMDIN:
+ Vender_Data_In(dev);
+ 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;
+
+ if (dev->bulk_len!=0)
+ {
+ dev->bulk_len=0;
+ USB_WRITE(REG_USB_IE,USB_READ(REG_USB_IE)|0x00000100);//enable vender interrupt enable
+ }
+
+ 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 VENI:
+ USB_ISR_Vendor_Cmd(dev);
+
+ case CDOI:
+ USB_ISR_CtlOut(dev);
+ 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 ;
+
+}
+
+
+static 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_INTERRUPT/*|SA_SAMPLE_RANDOM*/,
+ driver_name, dev) != 0) {
+ printk("Request irq error\n");
+ return -EBUSY;
+ }
+
+ Enable_Int(INT_USBD);
+
+ return 0;
+
+}
+
+
+static void USB_Irq_Init(wbusb_dev *dev)
+{
+
+ ENTER();
+
+ init_waitqueue_head(&dev->wusbd_wait_a);//write
+ init_waitqueue_head(&dev->wusbd_wait_b);//read
+ init_waitqueue_head(&dev->wusbd_wait_c);//vcom vendor cmd
+
+ if(wbusb_installirq(dev)==0)
+ printk("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
+
+
+ LEAVE();
+
+ 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;
+
+ ENTER();
+ /* 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;
+
+ LEAVE();
+
+done:
+
+ return ;
+
+}
+
+static char buffer[4096];
+
+static size_t usb_client_read(char /*__user*/ *buf, size_t length)
+{
+ char *tmp = (char *)((UINT32)buffer | 0x80000000);
+
+ ENTER();
+ //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;
+
+ LEAVE();
+ return length;
+}
+
+static size_t usb_client_write(const char/* __user*/ *buf, size_t length)
+{
+ char *tmp = (char *)((UINT32)buffer | 0x80000000);
+
+ ENTER();
+ //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);
+
+ LEAVE();
+
+ return length;
+}
+
+static int usb_client_get_cbw(char *buf)
+{
+ int retval = 0;
+ char *tmp = (char *)((UINT32)buffer | 0x80000000);
+
+ ENTER();
+
+ retval = check_cbw(the_controller, tmp);
+
+ if(copy_to_user(buf, tmp, 0x1f))
+ return -EFAULT;
+
+ LEAVE();
+
+ return 0;
+}
+
+static int wbusb_open(struct inode *ip, struct file *filp)
+{
+ ENTER();
+ LEAVE();
+ return 0;
+}
+
+static int wbusb_release(struct inode *ip, struct file *filp)
+{
+ ENTER();
+ LEAVE();
+ return 0;
+}
+
+static ssize_t wbusb_read(struct file *filp, char /*__user*/ * buf, size_t count, loff_t *lp)
+{
+ return usb_client_read(buf, count);
+}
+
+static ssize_t wbusb_write(struct file *filp, const char /*__user*/ * 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;
+
+ ENTER();
+
+ 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;
+
+ case WBUSB_GETVLEN:
+
+ if(!the_controller->bulk_len)
+ {
+ //printk("waiting PC\n");
+ //C_task_block(the_controller); /* 11.28 mark, PT23 HHWu */
+ }
+
+ //printk("wakeup now !\n");
+
+ *(unsigned long*)arg=the_controller->bulk_len;
+ break;
+
+ case WBUSB_REPLUG:
+#if 0
+ if(*(char*)arg)
+ {
+#endif
+ printk("VCOM Type !!!\n");
+ USB_Device=USB_Device_VCOM;
+ USB_Config=USB_Config_VCOM;
+ USB_Device_Id_String=USB_Device_Id_String_VCOM;
+ USB_Vender_Id_String=USB_Vender_Id_String_VCOM;
+#if 0
+ }
+ else
+ {
+ printk("MASS Type !!!\n");
+ USB_Device=USB_Device_Mass;
+ USB_Config=USB_Config_Mass;
+ USB_Device_Id_String=USB_Device_Id_String_Mass;
+ USB_Vender_Id_String=USB_Vender_Id_String_Mass;
+ }
+#endif
+ memset(the_controller,0, sizeof *the_controller);
+ the_controller->rw_data=write_data;
+ the_controller->rd_data=read_data;
+ the_controller->wait_cbw=check_cbw;
+ Reset_USB(the_controller);
+
+
+ break;
+
+ default:
+ return -ENOTTY;
+ }
+
+ LEAVE();
+
+ 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)
+{
+ int retval;
+
+ ENTER();
+
+#ifdef USBDVCOM
+ printk("VCOM Type!\n");
+ USB_Device=USB_Device_VCOM;
+ USB_Config=USB_Config_VCOM;
+ USB_Device_Id_String=USB_Device_Id_String_VCOM;
+ USB_Vender_Id_String=USB_Vender_Id_String_VCOM;
+#else
+
+ USB_Device=USB_Device_Mass;
+ USB_Config=USB_Config_Mass;
+ USB_Device_Id_String=USB_Device_Id_String_Mass;
+ USB_Vender_Id_String=USB_Vender_Id_String_Mass;
+#endif
+
+ wbusbd_probe();
+#if 0
+ retval = register_chrdev_region(MKDEV(WBUSB_MAJOR, 0), 1, "usbclient");
+ if ( retval < 0) {
+ printk("wbusb : can not register chrdev region\n");
+ return retval;
+ }
+
+ cdev_init(&wbusb_cdev, &wbusb_fops);
+ wbusb_cdev.owner = THIS_MODULE;
+ wbusb_cdev.ops = &wbusb_fops;
+ retval = cdev_add(&wbusb_cdev, MKDEV(WBUSB_MAJOR, 0), 1);
+ if ( retval < 0) {
+ printk("wbusb : can not add wbusb_cdev\n");
+ unregister_chrdev_region(MKDEV(WBUSB_MAJOR, 0), 1);
+ return retval;
+ }
+#endif
+ retval = register_chrdev(WBUSB_MAJOR, "usbclient", &wbusb_fops);
+ if( retval < 0){
+ printk("can't get major %d\n", WBUSB_MAJOR);
+ return retval;
+ }
+
+
+ printk("W90N745 USB Device Driver 1.0 Initilization Success\n");
+
+
+ LEAVE();
+
+ return 0;
+
+}
+
+static void __exit wbusb_cleanup (void)
+{
+ ENTER();
+#if 0
+ cdev_del(&wbusb_cdev);
+ unregister_chrdev_region(MKDEV(WBUSB_MAJOR, 0), 1);
+#endif
+ unregister_chrdev(WBUSB_MAJOR, "smartcard");
+
+ Disable_USB(the_controller);
+
+ if(the_controller)
+ kfree(the_controller);
+
+ LEAVE();
+
+ return ;
+}
+
+module_init(wbusb_init);
+module_exit(wbusb_cleanup);
+
+MODULE_LICENSE("GPL");