#include #include #include /* eeded for error parsing in enumerate */ #include #include #include "ssd.h" #include "ssd_debug.h" #ifdef SSD_DEBUG //MODULE_PARM(ssd_debug_ip, "s"); //MODULE_PARM_DESC(ssd_debug_ip, "ip address for udp dump"); //MODULE_PARM(ssd_debug_port, "i"); //MODULE_PARM_DESC(ssd_debug_port, "port for udp dump"); //MODULE_PARM(g_ssd_debug_level, "i"); //MODULE_PARM_DESC(g_ssd_debug_level, "debug level"); //MODULE_PARM(use_sock, "i"); //MODULE_PARM_DESC(use_sock, "enables socket usage"); static char *ssd_debug_ip = "10.0.3.200"; int ssd_debug_port = 5555; int g_ssd_debug_level = SSD_REPORTLEVEL; int use_sock = 0; void* debugcallback; #else int g_ssd_debug_level = 4; #endif /*find the pointer to a client structure */ #define INDEX_TO_CLIENTID(index) (index + 288) #define CLIENTID_TO_INDEX(devid) (devid - 288) /* replace with a proper division of headers */ #include "sdiodrv.h" /* move to a common header */ #define MAX_CLIENTS 1 u32 sdio_sync_read_priv[SDIO_PRIVATE_STORAGE_SIZE]; u32 sdio_sync_write_priv[SDIO_PRIVATE_STORAGE_SIZE]; u32 sdio_async_read_priv[EXT_SDIO_PRIVATE_STORAGE_SIZE]; u32 sdio_async_write_priv[EXT_SDIO_PRIVATE_STORAGE_SIZE]; struct ssd_driver{ struct ssd_device* dev;/* he device that is managed by this driver instance. */ ssd_client_params_t cli_params;/* ocal copy of the client params as passed on open. */ int function_selected; unsigned int timeout_clks; int dev_id; }; struct ssd_driver* opened_drivers[MAX_CLIENTS]; /* lobal: should be seen from ssd_busguard.c */ #define PCLI (opened_drivers[client_id]) #ifdef SDIO_IN_BAND_INTERRUPT int ssd_SDIO_set_4bit(unsigned char select_4bit); int sdiodrv_set_4bit(unsigned char fourbit); #endif /* interface function calls */ int ssd_SDIO_open(ssd_client_params_t* param) { int client_id = 0, ret; struct sdio_init_params ip; PDEBUG("entering %s()\n" , __FUNCTION__ ); if(!param){ PERR("invalid argument to %s\n", __FUNCTION__); return -EINVAL; } #ifdef SSD_DEBUG debugcallback = param->BusTxnCB; #endif for(client_id=0;client_idMaxClockRate; ip.BusWidth = param->BusWidth; PDEBUG("before sdiodrv_init\n"); ret = sdiodrv_init(&ip); /*in the future impl. the param struct should be passed and built from the command line. */ if(ret !=0){ printk("%s:%s:%d Error\n", __FILE__, __FUNCTION__, __LINE__); PERR("sdiodrv_init() failed - exiting %s\n",__FUNCTION__); sdiodrv_shutdown(); return -ENODEV; } /* allocate a new internal client structure */ PCLI = kmalloc(sizeof(struct ssd_driver), GFP_KERNEL); if(NULL == PCLI){ printk("%s:%s:%d Error\n", __FILE__, __FUNCTION__, __LINE__); PERR("kmalloc failed\n"); return -ENOMEM; } /* save a copy of the client params in the allocated structure */ memcpy(&(PCLI->cli_params),param,sizeof(ssd_client_params_t)); PCLI->timeout_clks = MILLI2CLKS(param->Timeout); PCLI->function_selected = FUNCTION_SELECT_1; PDEBUG("exiting %s\n",__FUNCTION__); return INDEX_TO_CLIENTID(client_id); } int ssd_SDIO_enumerate(int ClientID) { unsigned char reply; unsigned long longval; int ret, client_id = CLIENTID_TO_INDEX(ClientID); PDEBUG("entering %s()\n" , __FUNCTION__ ); if(NULL == PCLI) /* ot opened? */ return -1; /* command 0 */ ret = sdiodrv_execute_cmd(SD_IO_GO_IDLE_STATE, 0,MMC_RSP_NONE,0, &reply,1,0,PCLI->timeout_clks); if(ret)return ret; /* command 5 */ PDEBUG("issue command 5 - expect CRC error (ok)\n"); ret = sdiodrv_execute_cmd(SDIO_CMD5, VDD_VOLTAGE_WINDOW,MMC_RSP_R3,0, &reply,1,0,PCLI->timeout_clks); printk("commnd 5 Ret value: %d\n\n", ret); if(ret && ret != MMC_ERR_BADCRC) return ret; /* command SD_IO_SEND_RELATIVE_ADDR */ PDEBUG("issue command SD_IO_SEND_RELATIVE_ADDR\n"); ret = sdiodrv_execute_cmd(SD_IO_SEND_RELATIVE_ADDR, 0,MMC_RSP_R6,0, &longval,4,0,PCLI->timeout_clks); printk("commnd send relative addr Ret value: %d\n\n", ret); if(ret)return ret; /* command SD_IO_SELECT_CARD */ PDEBUG("issue command SD_IO_SELECT_CARD\n"); ret = sdiodrv_execute_cmd(SD_IO_SELECT_CARD,longval,MMC_RSP_R6,0, &reply,1,0,PCLI->timeout_clks); printk("commnd send IO select card ret value: %d\n\n", ret); if(ret)return ret; // rcaValue = longval; // printk("RCAVALUE: %08X\n\n",rcaValue); // printk("RCAVALUE: %08X\n\n",longval); PDEBUG("initialize CCCR\n"); reply = 2; ret = sdiodrv_execute_cmd(SD_IO_RW_DIRECT, SDIO_CMD52_WRITE(1,FUNCTION_SELECT_0,0,CCCR_IO_ENABLE, reply) ,MMC_RSP_R3,0, &reply,1,0,PCLI->timeout_clks); #ifdef SDIO_IN_BAND_INTERRUPT PDEBUG("Enable SDIO interrupt in the CCCR area of the TNET\n"); reply = 3; ret = sdiodrv_execute_cmd(SD_IO_RW_DIRECT, SDIO_CMD52_WRITE(1,FUNCTION_SELECT_0,0,CCCR_INT_ENABLE, reply) ,MMC_RSP_R3,0, &reply,1,0,PCLI->timeout_clks); printk("CCCR_INT_ENABLE: %08X",reply); #endif if(ret)return ret; PDEBUG("issue command CCCR_BUS_INTERFACE_CONTOROL\n"); if(PCLI->cli_params.BusWidth == 4)/* setting bus width on the device side */ { printk("Bus width is 4\n"); reply = 2; } else { printk("Bus width is 1"); reply = 0; } ret = sdiodrv_execute_cmd(SD_IO_RW_DIRECT, SDIO_CMD52_WRITE(1,FUNCTION_SELECT_0,0,CCCR_BUS_INTERFACE_CONTOROL, reply) ,MMC_RSP_R3,0, &reply,1,0,PCLI->timeout_clks); /* Call the prepare functions to fill the command buffers */ ret = sdiodrv_read_sync_prepare((void *)sdio_sync_read_priv,SD_IO_RW_EXTENDED, MMC_RSP_R3, PCLI->cli_params.BusWidth, PCLI->cli_params.blockSize, PCLI->timeout_clks); ret = sdiodrv_write_sync_prepare((void *)sdio_sync_write_priv,SD_IO_RW_EXTENDED, MMC_RSP_R3, PCLI->cli_params.BusWidth, PCLI->cli_params.blockSize, PCLI->timeout_clks); ret = sdiodrv_read_async_prepare((void *)sdio_async_read_priv,SD_IO_RW_EXTENDED, MMC_RSP_R3, PCLI->cli_params.BusWidth, PCLI->cli_params.blockSize, PCLI->cli_params.BusTxnCB, PCLI->cli_params.BusTxnHandle, 0, Xfer_dma_internal_conf, NULL, PCLI->timeout_clks); ret = sdiodrv_write_async_prepare((void *)sdio_async_write_priv,SD_IO_RW_EXTENDED, MMC_RSP_R3, PCLI->cli_params.BusWidth, PCLI->cli_params.blockSize, PCLI->cli_params.BusTxnCB, PCLI->cli_params.BusTxnHandle, 0, Xfer_dma_internal_conf, NULL, PCLI->timeout_clks); PDEBUG("exiting %s\n",__FUNCTION__); return ret; } int ssd_SDIO_close(int ClientID) { int client_id = CLIENTID_TO_INDEX(ClientID); PDEBUG("entering %s()\n" , __FUNCTION__ ); sdiodrv_shutdown(); kfree(PCLI); PCLI = NULL; PDEBUG("exiting %s\n",__FUNCTION__); return 0; } int ssd_SDIO_writeSync(int ClientID, int Address, void *DataPointer, int Length) { int ret=0, client_id = CLIENTID_TO_INDEX(ClientID); CL_TRACE_START_L2(); PDEBUG("entering %s()\n" , __FUNCTION__ ); if(NULL == PCLI||!DataPointer || Length > MAX_STREAM_SIZE_IN_BYTE_MODE || Length % 4){ CL_TRACE_END_L2("ssd.ko", "INHERIT", "SDIO_DRV_SYNC", ""); return -1; } ret = ssd_send_as_hexdump(DataPointer,Length,1); if (ret < 0){ PERR("failed sending data on debug socket\n"); } ret = sdiodrv_write_sync((void *)sdio_sync_write_priv,DataPointer, Address, Length); PDEBUG("exiting %s\n",__FUNCTION__); CL_TRACE_END_L2("ssd.ko", "INHERIT", "SDIO_DRV_SYNC", ""); return ret; } int ssd_SDIO_writeAsync(int ClientID, int Address, void *DataPointer, int Length) { int ret=0, client_id = CLIENTID_TO_INDEX(ClientID); CL_TRACE_START_L2(); PDEBUG("entering %s()\n" , __FUNCTION__ ); if(NULL == PCLI||!DataPointer || Length > MAX_STREAM_SIZE_IN_BYTE_MODE || Length % 4){ CL_TRACE_END_L2("ssd.ko", "INHERIT", "SDIO_DRV_ASYNC", ""); return -1; } ret = ssd_send_as_hexdump(DataPointer,Length,1); if (ret < 0){ PERR("failed sending data on debug socket\n"); } ret = sdiodrv_write_async((void *)sdio_async_write_priv,DataPointer, Address, Length); PDEBUG("exiting %s\n",__FUNCTION__); CL_TRACE_END_L2("ssd.ko", "INHERIT", "SDIO_DRV_ASYNC", ""); return ret; } int ssd_SDIO_writeByte(int ClientID, int Address, unsigned char data) { int ret, client_id = CLIENTID_TO_INDEX(ClientID); PDEBUG("entering %s()\n" , __FUNCTION__ ); if(NULL == PCLI) return -1; ret = ssd_send_as_hexdump(&data,1,1); if (ret < 0){ PERR("failed sending data on debug socket\n"); } ret = sdiodrv_write_byte(data, Address); PDEBUG("exiting %s\n",__FUNCTION__); return ret; } int ssd_SDIO_readSync(int ClientID, int Address, void *DataPointer, int Length) { int ret, client_id = CLIENTID_TO_INDEX(ClientID); CL_TRACE_START_L2(); PDEBUG("entering %s()\n" , __FUNCTION__ ); if(NULL == PCLI|| !DataPointer || Length > MAX_STREAM_SIZE_IN_BYTE_MODE || Length % 4){ CL_TRACE_END_L2("ssd.ko", "INHERIT", "SDIO_DRV_SYNC", ""); return -1; } ret = sdiodrv_read_sync((void *)sdio_sync_read_priv,DataPointer, Address, Length); if (ssd_send_as_hexdump(DataPointer,Length,0) < 0){ PERR("failed sending data on debug socket\n"); } PDEBUG("exiting %s\n",__FUNCTION__); CL_TRACE_END_L2("ssd.ko", "INHERIT", "SDIO_DRV_SYNC", ""); return ret; } int ssd_SDIO_readAsync(int ClientID, int Address, void *DataPointer, int Length) { int ret, client_id = CLIENTID_TO_INDEX(ClientID); CL_TRACE_START_L2(); PDEBUG("entering %s()\n" , __FUNCTION__ ); if(NULL == PCLI||!DataPointer || Length > MAX_STREAM_SIZE_IN_BYTE_MODE || Length % 4){ CL_TRACE_END_L2("ssd.ko", "INHERIT", "SDIO_DRV_ASYNC", ""); return -1; } ret = sdiodrv_read_async((void *)sdio_async_read_priv,DataPointer, Address, Length); if (ssd_send_async_read_msg(Length,ret) < 0){ PERR("failed sending data on debug socket\n"); } PDEBUG("exiting %s\n",__FUNCTION__); CL_TRACE_END_L2("ssd.ko", "INHERIT", "SDIO_DRV_ASYNC", ""); return ret; } int ssd_SDIO_readByte(int ClientID, int Address, unsigned char* data) { int ret, client_id = CLIENTID_TO_INDEX(ClientID); PDEBUG("entering %s()\n" , __FUNCTION__ ); if(NULL == PCLI) return -1; ret = sdiodrv_read_byte(data, Address); if (ssd_send_as_hexdump(data,1,1)<0){ PERR("failed sending data on debug socket\n"); } PDEBUG("exiting %s\n",__FUNCTION__); return ret; } int ssd_functionSelect(int clientID, int functionID) { int client_id = CLIENTID_TO_INDEX(clientID); PDEBUG("entering %s()\n" , __FUNCTION__ ); PCLI->function_selected = functionID; PDEBUG("exiting %s\n",__FUNCTION__); return 0; } #ifdef SDIO_IN_BAND_INTERRUPT int ssd_SDIO_set_4bit(unsigned char select_4bit) { unsigned char reply; int ret; int client_id = 0; PDEBUG("entering %s()\n" , __FUNCTION__ ); sdiodrv_set_4bit(select_4bit); if(select_4bit == 1)/* setting bus width on the device side */ reply = 2; else reply = 0; ret = sdiodrv_execute_cmd(SD_IO_RW_DIRECT, SDIO_CMD52_WRITE(1,FUNCTION_SELECT_0,0,CCCR_BUS_INTERFACE_CONTOROL, reply) ,MMC_RSP_R3,0, &reply,1,0,PCLI->timeout_clks); /* Call the prepare functions to fill the command buffers */ ret = sdiodrv_read_sync_prepare((void *)sdio_sync_read_priv,SD_IO_RW_EXTENDED, MMC_RSP_R3, PCLI->cli_params.BusWidth, PCLI->cli_params.blockSize, PCLI->timeout_clks); ret = sdiodrv_write_sync_prepare((void *)sdio_sync_write_priv,SD_IO_RW_EXTENDED, MMC_RSP_R3, PCLI->cli_params.BusWidth, PCLI->cli_params.blockSize, PCLI->timeout_clks); ret = sdiodrv_read_async_prepare((void *)sdio_async_read_priv,SD_IO_RW_EXTENDED, MMC_RSP_R3, PCLI->cli_params.BusWidth, PCLI->cli_params.blockSize, PCLI->cli_params.BusTxnCB, PCLI->cli_params.BusTxnHandle, 0, Xfer_dma_internal_conf, NULL, PCLI->timeout_clks); ret = sdiodrv_write_async_prepare((void *)sdio_async_write_priv,SD_IO_RW_EXTENDED, MMC_RSP_R3, PCLI->cli_params.BusWidth, PCLI->cli_params.blockSize, PCLI->cli_params.BusTxnCB, PCLI->cli_params.BusTxnHandle, 0, Xfer_dma_internal_conf, NULL, PCLI->timeout_clks); PDEBUG("exiting %s\n",__FUNCTION__); return ret; } #endif /* SDIO_IN_BAND_INTERRUPT */ EXPORT_SYMBOL(ssd_SDIO_open); EXPORT_SYMBOL(ssd_SDIO_enumerate); EXPORT_SYMBOL(ssd_SDIO_close); EXPORT_SYMBOL(ssd_SDIO_writeSync); EXPORT_SYMBOL(ssd_SDIO_writeAsync); EXPORT_SYMBOL(ssd_SDIO_writeByte); EXPORT_SYMBOL(ssd_SDIO_readSync); EXPORT_SYMBOL(ssd_SDIO_readAsync); EXPORT_SYMBOL(ssd_SDIO_readByte); EXPORT_SYMBOL(ssd_functionSelect); #ifdef SDIO_IN_BAND_INTERRUPT EXPORT_SYMBOL(ssd_SDIO_set_4bit); #endif