📄 mss_sdio.c
字号:
ret = kernel_thread(sdio_queue_thread, NULL, CLONE_KERNEL); if (ret < 0 ) return ret; // enable sdio interrupt mss_set_sdio_int(cmmb_dev.card->slot->host, 1); // clean identifition register sdio_read_ioreg(cmmb_dev.card, FN1, FUNC1_INT_IDENTIFY_REG, &tmp); // clean counter register sdio_write_ioreg(cmmb_dev.card, FN1, FUNC1_DATA_COUNTER1_REG, 0); sdio_write_ioreg(cmmb_dev.card, FN1, FUNC1_DATA_COUNTER2_REG, 0); sdio_write_ioreg(cmmb_dev.card, FN1, FUNC1_DATA_COUNTER3_REG, 0); return 0;}static int sdio_release(struct inode * inode, struct file *file){ cmmb_dev.flags = SDIO_QUEUE_EXIT; wake_up_interruptible(&cmmb_dev.wq); return 0;}static ssize_t sdio_read(struct file *f, char __user *buf, size_t count, loff_t *offset){ int readlen; if (cmmb_dev.datalen == 0) return 0; if (cmmb_dev.datalen > count) readlen = count; else readlen = cmmb_dev.datalen; if (cmmb_dev.databuf+CMMB_FRAME_SIZE_MAX-cmmb_dev.readp > readlen) { copy_to_user(buf, cmmb_dev.readp, readlen); cmmb_dev.readp += readlen; } else { readlen = cmmb_dev.databuf+CMMB_FRAME_SIZE_MAX-cmmb_dev.readp; copy_to_user(buf, cmmb_dev.readp, readlen); cmmb_dev.readp = cmmb_dev.databuf; } cmmb_dev.datalen -= readlen; //printk("Kernel sdio_read: %d, left %d\n",readlen,cmmb_dev.datalen); return readlen;}static ssize_t sdio_write(struct file *f, const char __user *buf, size_t count, loff_t *offset){ unsigned char *tempP;
unsigned char tempChar; int ret; unsigned int datalen; unsigned char *data;
datalen = count;
if (datalen == 0)
return 0;
data= kzalloc(count, GFP_KERNEL); if (data == NULL) { printk("write Functon kzalloc error\n"); return -1; } copy_from_user(data, buf, count); // set write counter
tempChar = datalen & 0xFF;
ret = sdio_write_ioreg(cmmb_dev.card, FN1, FUNC1_DATA_COUNTER4_REG, tempChar); if (ret < 0) { kfree(data); return -2; }
tempChar = (datalen & 0xFF00) >> 8; ret = sdio_write_ioreg(cmmb_dev.card, FN1, FUNC1_DATA_COUNTER5_REG, tempChar); if (ret < 0) { kfree(data); return -2; }
tempChar = (datalen & 0xFF0000) >> 16;
ret = sdio_write_ioreg(cmmb_dev.card, FN1, FUNC1_DATA_COUNTER6_REG, tempChar); if (ret < 0) { kfree(data); return -2; }
// send data by command53
// I only implement command53 byte mode, so the max length to send is 512 bytes
// If you can implement command53 block mode, you can send more then 512 bytes one time
tempP = data;
while(datalen > CMMB_DATA_BLOCK_SIZE)
{ ret = sdio_write_iomem(cmmb_dev.card, FN1, FUNC1_DATA_REG, BLOCK_MODE, FIXED_ADDRESS, 1, CMMB_DATA_BLOCK_SIZE, tempP); if (ret < 0) { kfree(data); printk("sdio driver: write Block error0\n"); return -3; }
datalen -= CMMB_DATA_BLOCK_SIZE;
tempP += CMMB_DATA_BLOCK_SIZE;
} if(datalen > 0)
{
ret = sdio_write_iomem(cmmb_dev.card, FN1, FUNC1_DATA_REG, BLOCK_MODE, FIXED_ADDRESS, 1, datalen, tempP); if (ret < 0) { kfree(data); printk("sdio driver: write Block error1\n"); return -3; }
}
kfree(data);
return count;}struct file_operations sdio_cmmb_fops = { open: sdio_open, read: sdio_read, write: sdio_write, release: sdio_release,};static intsbi_remove_card(struct device *dev){ struct mss_card *card; card = container_of(dev, struct mss_card, dev); class_device_destroy(cmmb_dev.sdio_class, cmmb_dev.cdev->dev);
class_destroy(cmmb_dev.sdio_class); devfs_remove("sdio-cmmb"); unregister_chrdev_region(cmmb_dev.cdev->dev, 1); cdev_del(cmmb_dev.cdev); cmmb_dev.cdev = NULL; if (cmmb_dev.databuf) kfree(cmmb_dev.databuf); return 0;}/******************************************************** Global Functions********************************************************/voidsbi_interrupt(struct mss_card *card){ //ENTER(); wake_up_interruptible(&cmmb_dev.wq); //LEAVE();}static intsbi_suspend_card(struct device *dev, pm_message_t state, u32 level){ if (level == SUSPEND_DISABLE) {#ifndef CONFIG_CPU_MONAHANS_LV mhn_mfp_set_edge(MFP_FFDSR, MFP_EDGE_FALL);#endif mss_set_clock(cmmb_dev.card->slot->host, cmmb_dev.card->slot->host->f_min); } return 0;}static intsbi_resume_card(struct device *dev, u32 level){ printk("sbi resume back level:%d\n", level); if (level == RESUME_ENABLE) { mss_set_clock(cmmb_dev.card->slot->host, cmmb_dev.card->slot->host->f_max); } return 0;}static int sbi_probe_card(struct device *dev){ struct mss_card *card; struct sdio_card *sdio_card; int ret = 0; //ENTER(); card = container_of(dev, struct mss_card, dev); if (card->card_type != MSS_SDIO_CARD) { ret = -ENODEV; //STATUS_FAILURE; goto done; } sdio_card = card->prot_card; if (!card) { ret = -ENODEV; //STATUS_FAILURE; goto done; } ret = 0; memset(&cmmb_dev, 0, sizeof(sdio_dev)); cmmb_dev.databuf = kzalloc(CMMB_FRAME_SIZE_MAX, GFP_KERNEL); if (cmmb_dev.databuf == 0) { printk("kzalloc databuf error\n"); return -ENODEV; } cmmb_dev.readp = cmmb_dev.databuf; cmmb_dev.writep = cmmb_dev.databuf; cmmb_dev.cdev = cdev_alloc(); cmmb_dev.cdev->owner = THIS_MODULE; cdev_init(cmmb_dev.cdev,&sdio_cmmb_fops); alloc_chrdev_region(&cmmb_dev.cdev->dev, 0, 1, "/dev/sdio"); ret = cdev_add(cmmb_dev.cdev, cmmb_dev.cdev->dev, 1); if(ret < 0) { cdev_del(cmmb_dev.cdev); cmmb_dev.cdev = NULL; printk("Error! Couldn't register /dev/sdio driver\n"); goto done; } cmmb_dev.sdio_class=class_create(THIS_MODULE, "sdio");
if(IS_ERR(cmmb_dev.sdio_class)) {
ret=-1;
goto out_class;
}; class_device_create(cmmb_dev.sdio_class, cmmb_dev.cdev->dev,NULL, "sdio"); devfs_mk_cdev(cmmb_dev.cdev->dev, S_IFCHR | S_IRUSR | S_IWUSR, "sdio"); cmmb_dev.card = card; done: printk("TelePath Cmmb Sdio Device find!\n"); sdio_write_ioreg(cmmb_dev.card, FN1, 0x05, 0x30); //pxd temp //LEAVE(); return ret; out_class:
class_device_destroy(cmmb_dev.sdio_class, cmmb_dev.cdev->dev);
class_destroy(cmmb_dev.sdio_class); return ret;}static struct mss_driver mss_sdio_driver = { .driver = { .name = "cmmbdriver", .probe = sbi_probe_card, .remove = sbi_remove_card, .suspend = sbi_suspend_card, .resume = sbi_resume_card, }, .sdio_int_handler = sbi_interrupt,};/***************************************************************************** * * module init and exit functions * ****************************************************************************/static int mss_sdio_card_driver_init(void){ int ret; //ENTER(); ret = register_mss_driver(&mss_sdio_driver); //LEAVE(); return ret;}static void mss_sdio_card_driver_exit(void){ //ENTER(); unregister_mss_driver(&mss_sdio_driver); //LEAVE();}module_init(mss_sdio_card_driver_init);module_exit(mss_sdio_card_driver_exit);MODULE_AUTHOR("Pxd");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("Block device driver for SDIO card");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -