diff options
| author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-06-05 11:47:01 +0200 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-06-05 11:47:01 +0200 |
| commit | 40a2bc5b5c03c7219f40be1f5be51089a156b974 (patch) | |
| tree | b0f7a9bbf7b64727a0f1b35f70ead1a4d2809736 /csdio2.patch | |
| parent | 7d9e0d94f09501482a336a7a2e692c159ec4c9a9 (diff) | |
| download | patches-40a2bc5b5c03c7219f40be1f5be51089a156b974.tar.gz | |
refresh and move some patches out of the main queue
Diffstat (limited to 'csdio2.patch')
| -rw-r--r-- | csdio2.patch | 1404 |
1 files changed, 0 insertions, 1404 deletions
diff --git a/csdio2.patch b/csdio2.patch deleted file mode 100644 index 2c6a7a363a8232..00000000000000 --- a/csdio2.patch +++ /dev/null @@ -1,1404 +0,0 @@ -mmc: Char SDIO Device Driver - -Squashed commit of the following: - -commit c3fb53893cbc4b5e217ef176010d1b88982a9454 -Author: Alexander Kolesnikov <akolesni@codeaurora.org> -Date: Wed Sep 15 17:16:52 2010 +0200 - - csdio: Set/get vdd ioctl support - - Implement power up/down sequence for internal UBM chip. - This commit includes generic, platform independent part. - - CRs-Fixed: 255849 - Change-Id: I526c78765ba32b310463a231c5cf578cb37c6deb - Signed-off-by: Alexander Kolesnikov <akolesni@codeaurora.org> - -commit e1ba27311fcf3de2a5ca9a3fc1303328720dd120 -Author: Nela Gurevich <nelag@codeaurora.org> -Date: Thu Aug 19 14:00:09 2010 +0300 - - csdio: Move csdio.h to kernel/include - - Change-Id: Idf8df750e9f3bcc014d1afa673c9c27c97253195 - Signed-off-by: Nela Gurevich <nelag@codeaurora.org> - -commit 31d1b09c677c26efb71fa36ff6fe1e7f2d83abbc -Author: Alexander Kolesnikov <akolesni@codeaurora.org> -Date: Tue Aug 10 13:26:20 2010 +0300 - - mmc: Char SDIO Device Driver - - The Char SDIO Device Driver is an interface which exposes an SDIO - card/function from kernel space as a char device in user space. - - Change-Id: If298cdd6d4426b700e69affa5a3602cd221ad89c - Signed-off-by: Alexander Kolesnikov <akolesni@codeaurora.org> - -Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> ---- - Documentation/csdio.txt | 189 ++++++++ - drivers/char/Kconfig | 23 - drivers/char/Makefile | 1 - drivers/char/csdio.c | 1070 ++++++++++++++++++++++++++++++++++++++++++++++ - include/linux/csdio.h | 37 + - include/uapi/linux/Kbuild | 1 - 6 files changed, 1321 insertions(+) - ---- /dev/null -+++ b/Documentation/csdio.txt -@@ -0,0 +1,189 @@ -+Introduction -+============ -+The Char SDIO Device Driver is an interface which exposes an SDIO -+card/function from kernel space as a char device in user space. -+ -+The driver doesn't interact with any HW directly. It relies on SDIO -+card/function interface provided as a part of Linux kernel. -+ -+Hardware description -+==================== -+Each SDIO device/card contains an SDIO client HW block. -+The host interacts with the device by sending byte sequences called -+command (CMD). Some commands can be followed by data blocks. The -+device sends back a byte sequence called response (R) and a data -+block if required. CMD3, CMD5 and CMD7 are used to initialize the -+device. CMD52 and CMD53 are used to access the device. Command -+format and properties are defined by SDIO Specification document -+published by SD Association: -+ http://www.sdcard.org/developers/tech/sdio/. -+ -+CMD52 and CMD53 can access up to 8 address spaces called Functions. -+Function 0 contains system information predefined by SD/SDIO -+standard and Functions 1-7 are defined by the SDIO device -+manufacturer. -+ -+An SDIO device/card can send an interrupt to SDIO host. This -+interrupt is intercepted and handled by SDIO host. -+ -+Software description -+==================== -+Linux provides a framework for handling SDIO devices. It implements -+kind of plug-and-play model in which the Linux SDIO Host Driver is -+responsible for initializing an SDIO device upon insertion. It also -+reads device/card identification information and enumerates functions -+provided by the device and then looks up in the list of -+preregistered user SDIO drivers for a suitable one. -+ -+During its lifecycle the user SDIO driver interacts with the Linux -+SDIO Host Driver in order to send/receive information to/from SDIO -+device/card. The user SDIO driver doesn't work with CMD52/CMD53 -+directly. Instead it uses an abstraction provided by the Linux SDIO -+Host Driver. -+ -+The Linux SDIO Host Driver is also in charge of handling SDIO -+interrupts. User SDIO driver can register its own callback in SDIO -+Host Driver and get a notification about interrupt event. -+ -+The Char SDIO Device Driver follows the design guidelines mentioned -+above. It provides the following functionality: -+ -+ - Register itself in the user SDIO drivers list; -+ - Handle Probe event upon insertion of supported card/device; -+ - Creates and maintains a char device driver for each SDIO Function -+ found in the card/device; -+ - Translates read/write/ioctl calls to appropriate SDIO call -+ sequences; -+ -+In order to handle general SDIO configuration functionality and -+Function 0 the Char SDIO Device Driver provides additional -+simplified char device driver. -+ -+The Manufacturer and Device IDs of handled SDIO device should be -+provided as parameters for kernel module or as configuration -+parameters in case of statically linked driver. -+ -+Design -+====== -+The main goal of the Char SDIO Device Driver is to expose an SDIO -+card/device from kernel space to user space as a char device driver. -+The driver should be generic and simple as far as possible. -+ -+The biggest design tradeoff is maintaining a balance between the -+system call overhead required to initiate an SDIO transaction from -+user space and overall SDIO communication performance. But luckily, -+because of nature of SDIO protocol, this overhead is negligible -+comparing to time required to execute SDIO transaction itself. So, -+each CMD52 (read or write) consists from single ioctl system call. -+And each CMD53 invokes single ioctl system call followed by read or -+write system call. -+ -+The Char SDIO Device Driver registers its own class of the devices -+called 'csdio'. This class will serve as a common roof for all SDIO -+devices served by different instances of the Char SDIO Device Driver. -+Additional benefit from maintaining its own class is the driver -+ability to overwrite default permissions of the dev nodes created by -+the driver. -+ -+Power Management -+================ -+None -+ -+SMP/multi-core -+============== -+The driver does not anticipate any issues related to multi-core -+since it is expected to run on one core only. -+ -+Security -+======== -+None -+ -+Performance -+=========== -+None -+ -+Interface -+========= -+The Char SDIO Device Driver has two char device interfaces: -+ - Control Interface; -+ - Function Interface. -+ -+Char SDIO Device Driver Control Interface consists of: -+ - open() - device node is /dev/csdio0; -+ - close() -+ - ioctl() - the following options are available: -+ - CSDIO_IOC_ENABLE_HIGHSPEED_MODE; -+ - CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS; -+ - CSDIO_IOC_ENABLE_ISR; -+ - CSDIO_IOC_DISABLE_ISR. -+ -+Char SDIO Device Driver Function Interface consists of: -+ - open() - device node is /dev/csdiofX, where X is Function Id; -+ - close() -+ - read() - send CMD53 read; -+ - write() - send CMD53 write; -+ - ioctl() - the following options are available: -+ - CSDIO_IOC_SET_OP_CODE - 0 fixed adrress, 1 autoincrement. -+ - CSDIO_IOC_FUNCTION_SET_BLOCK_SIZE; -+ - CSDIO_IOC_SET_BLOCK_MODE - 0 byte mode, 1 block mode; -+ - CSDIO_IOC_CMD52 - execute CMD52, receives the -+ following structure as a parameter: -+ struct csdio_cmd52_ctrl_t { -+ uint32_t m_write; // 0 - read, 1 -write -+ uint32_t m_address; -+ uint32_t m_data; // data to write or read data -+ uint32_t m_ret; // command execution status -+ }__attribute__ ((packed)); -+ - CSDIO_IOC_CMD53 - setup CMD53 data transfer, receives the -+ following structure as a parameter: -+ struct csdio_cmd53_ctrl_t { -+ uint32_t m_block_mode; -+ uint32_t m_op_code; -+ uint32_t m_address; -+ }__attribute__ ((packed)); -+ - CSDIO_IOC_CONNECT_ISR; -+ - CSDIO_IOC_DISCONNECT_ISR; -+ - CSDIO_IOC_GET_VDD; -+ - CSDIO_IOC_SET_VDD. -+ -+Additionally, user space application can use fcntl system call with -+parameters F_SETOWN and F_SETFL in order to set an asynchronous -+callback for SDIO interrupt. -+ -+Driver parameters -+================= -+If the driver is compiled as a kernel module, the following -+parameters can be used in order to provide Manufacturer and Device IDs -+upon module download: -+ - csdio_vendor_id; -+ - csdio_device_id. -+If the driver is intended to work with specific SDIO host the -+host_name parameter should be added followed by the name of the MMC -+host platform device. -+ -+Config options -+============== -+These are the kernel configuration options: -+ - CONFIG_CSDIO_VENDOR_ID; -+ - CONFIG_CSDIO_DEVICE_ID. -+ -+Dependencies -+============ -+The Char SDIO Device Driver depends on Linux SDIO Host Driver. -+ -+User space utilities -+==================== -+None -+ -+Other -+===== -+None -+ -+Known issues -+============ -+None -+ -+To do -+===== -+Provide mechanism to support a number of SDIO devices simultaneously -+connected to different SDIO hosts. ---- a/drivers/char/Kconfig -+++ b/drivers/char/Kconfig -@@ -594,5 +594,28 @@ config TILE_SROM - - source "drivers/char/xillybus/Kconfig" - -+config MMC_GENERIC_CSDIO -+ tristate "Generic sdio driver" -+ default n -+ help -+ SDIO function driver that extends SDIO card as character device -+ in user space. -+ -+config CSDIO_VENDOR_ID -+ hex "Card VendorId" -+ depends on MMC_GENERIC_CSDIO -+ default "0" -+ help -+ Enter vendor id for targeted sdio device, this may be overwritten by -+ module parameters. -+ -+config CSDIO_DEVICE_ID -+ hex "CardDeviceId" -+ depends on MMC_GENERIC_CSDIO -+ default "0" -+ help -+ Enter device id for targeted sdio device, this may be overwritten by -+ module parameters. -+ - endmenu - ---- a/drivers/char/Makefile -+++ b/drivers/char/Makefile -@@ -44,6 +44,7 @@ obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gp - obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o - obj-$(CONFIG_GPIO_TB0219) += tb0219.o - obj-$(CONFIG_TELCLOCK) += tlclk.o -+obj-$(CONFIG_MMC_GENERIC_CSDIO) += csdio.o - - obj-$(CONFIG_MWAVE) += mwave/ - obj-y += agp/ ---- /dev/null -+++ b/drivers/char/csdio.c -@@ -0,0 +1,1070 @@ -+/* -+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/mutex.h> -+#include <linux/serial_reg.h> -+#include <linux/circ_buf.h> -+#include <linux/gfp.h> -+#include <linux/uaccess.h> -+#include <linux/slab.h> -+#include <linux/platform_device.h> -+ -+/* Char device */ -+#include <linux/cdev.h> -+#include <linux/fs.h> -+ -+/* Sdio device */ -+#include <linux/mmc/core.h> -+#include <linux/mmc/host.h> -+#include <linux/mmc/card.h> -+#include <linux/mmc/sdio.h> -+#include <linux/mmc/sdio_func.h> -+#include <linux/mmc/sdio_ids.h> -+ -+#include <linux/csdio.h> -+ -+#define VERSION "0.5" -+#define CSDIO_NUM_OF_SDIO_FUNCTIONS 7 -+#define CSDIO_DEV_NAME "csdio" -+#define TP_DEV_NAME CSDIO_DEV_NAME"f" -+#define CSDIO_DEV_PERMISSIONS 0666 -+ -+#define CSDIO_SDIO_BUFFER_SIZE (64*512) -+ -+int csdio_major; -+int csdio_minor; -+int csdio_transport_nr_devs = CSDIO_NUM_OF_SDIO_FUNCTIONS; -+static uint csdio_vendor_id; -+static uint csdio_device_id; -+static char *host_name; -+ -+static struct csdio_func_t { -+ struct sdio_func *m_func; -+ int m_enabled; -+ struct cdev m_cdev; /* char device structure */ -+ struct device *m_device; -+ u32 m_block_size; -+} *g_csdio_func_table[CSDIO_NUM_OF_SDIO_FUNCTIONS] = {0}; -+ -+struct csdio_t { -+ struct cdev m_cdev; -+ struct device *m_device; -+ struct class *m_driver_class; -+ struct fasync_struct *m_async_queue; -+ unsigned char m_current_irq_mask; /* currently enabled irqs */ -+ struct mmc_host *m_host; -+ unsigned int m_num_of_func; -+} g_csdio; -+ -+struct csdio_file_descriptor { -+ struct csdio_func_t *m_port; -+ u32 m_block_mode;/* data tran. byte(0)/block(1) */ -+ u32 m_op_code; /* address auto increment flag */ -+ u32 m_address; -+}; -+ -+static void *g_sdio_buffer; -+ -+/* -+ * Open and release -+ */ -+static int csdio_transport_open(struct inode *inode, struct file *filp) -+{ -+ int ret = 0; -+ struct csdio_func_t *port = NULL; /* device information */ -+ struct sdio_func *func = NULL; -+ struct csdio_file_descriptor *descriptor = NULL; -+ -+ port = container_of(inode->i_cdev, struct csdio_func_t, m_cdev); -+ func = port->m_func; -+ descriptor = kzalloc(sizeof(struct csdio_file_descriptor), GFP_KERNEL); -+ if (!descriptor) { -+ ret = -ENOMEM; -+ goto exit; -+ } -+ -+ pr_info(TP_DEV_NAME"%d: open: func=%p, port=%p\n", -+ func->num, func, port); -+ sdio_claim_host(func); -+ ret = sdio_enable_func(func); -+ if (ret) { -+ pr_err(TP_DEV_NAME"%d:Enable func failed (%d)\n", -+ func->num, ret); -+ ret = -EIO; -+ goto free_descriptor; -+ } -+ descriptor->m_port = port; -+ filp->private_data = descriptor; -+ goto release_host; -+ -+free_descriptor: -+ kfree(descriptor); -+release_host: -+ sdio_release_host(func); -+exit: -+ return ret; -+} -+ -+static int csdio_transport_release(struct inode *inode, struct file *filp) -+{ -+ int ret = 0; -+ struct csdio_file_descriptor *descriptor = filp->private_data; -+ struct csdio_func_t *port = descriptor->m_port; -+ struct sdio_func *func = port->m_func; -+ -+ pr_info(TP_DEV_NAME"%d: release\n", func->num); -+ sdio_claim_host(func); -+ ret = sdio_disable_func(func); -+ if (ret) { -+ pr_err(TP_DEV_NAME"%d:Disable func failed(%d)\n", -+ func->num, ret); -+ ret = -EIO; -+ } -+ sdio_release_host(func); -+ kfree(descriptor); -+ return ret; -+} -+ -+/* -+ * Data management: read and write -+ */ -+static ssize_t csdio_transport_read(struct file *filp, -+ char __user *buf, -+ size_t count, -+ loff_t *f_pos) -+{ -+ ssize_t ret = 0; -+ struct csdio_file_descriptor *descriptor = filp->private_data; -+ struct csdio_func_t *port = descriptor->m_port; -+ struct sdio_func *func = port->m_func; -+ size_t t_count = count; -+ -+ if (descriptor->m_block_mode) { -+ pr_info(TP_DEV_NAME "%d: CMD53 read, Md:%d, Addr:0x%04X," -+ " Un:%zd (Bl:%zd, BlSz:%d)\n", func->num, -+ descriptor->m_block_mode, -+ descriptor->m_address, -+ count*port->m_block_size, -+ count, port->m_block_size); -+ /* recalculate size */ -+ count *= port->m_block_size; -+ } -+ sdio_claim_host(func); -+ if (descriptor->m_op_code) { -+ /* auto increment */ -+ ret = sdio_memcpy_fromio(func, g_sdio_buffer, -+ descriptor->m_address, count); -+ } else { /* FIFO */ -+ ret = sdio_readsb(func, g_sdio_buffer, -+ descriptor->m_address, count); -+ } -+ sdio_release_host(func); -+ if (!ret) { -+ if (copy_to_user(buf, g_sdio_buffer, count)) -+ ret = -EFAULT; -+ else -+ ret = t_count; -+ } -+ if (ret < 0) { -+ pr_err(TP_DEV_NAME "%d: CMD53 read failed (%zd)" -+ "(Md:%d, Addr:0x%04X, Sz:%zd)\n", -+ func->num, ret, -+ descriptor->m_block_mode, -+ descriptor->m_address, count); -+ } -+ return ret; -+} -+ -+static ssize_t csdio_transport_write(struct file *filp, -+ const char __user *buf, -+ size_t count, -+ loff_t *f_pos) -+{ -+ ssize_t ret = 0; -+ struct csdio_file_descriptor *descriptor = filp->private_data; -+ struct csdio_func_t *port = descriptor->m_port; -+ struct sdio_func *func = port->m_func; -+ size_t t_count = count; -+ -+ if (descriptor->m_block_mode) -+ count *= port->m_block_size; -+ -+ if (copy_from_user(g_sdio_buffer, buf, count)) { -+ pr_err(TP_DEV_NAME"%d:copy_from_user failed\n", func->num); -+ ret = -EFAULT; -+ } else { -+ sdio_claim_host(func); -+ if (descriptor->m_op_code) { -+ /* auto increment */ -+ ret = sdio_memcpy_toio(func, descriptor->m_address, -+ g_sdio_buffer, count); -+ } else { -+ /* FIFO */ -+ ret = sdio_writesb(func, descriptor->m_address, -+ g_sdio_buffer, count); -+ } -+ sdio_release_host(func); -+ if (!ret) { -+ ret = t_count; -+ } else { -+ pr_err(TP_DEV_NAME "%d: CMD53 write failed (%zd)" -+ "(Md:%d, Addr:0x%04X, Sz:%zd)\n", -+ func->num, ret, descriptor->m_block_mode, -+ descriptor->m_address, count); -+ } -+ } -+ return ret; -+} -+ -+/* disable interrupt for sdio client */ -+static int disable_sdio_client_isr(struct sdio_func *func) -+{ -+ int ret; -+ -+ /* disable for all functions, to restore interrupts -+ * use g_csdio.m_current_irq_mask */ -+ sdio_f0_writeb(func, 0, SDIO_CCCR_IENx, &ret); -+ if (ret) -+ pr_err(CSDIO_DEV_NAME" Can't sdio_f0_writeb (%d)\n", ret); -+ -+ return ret; -+} -+ -+/* -+ * This handles the interrupt from SDIO. -+ */ -+static void csdio_sdio_irq(struct sdio_func *func) -+{ -+ int ret; -+ -+ pr_info(CSDIO_DEV_NAME" csdio_sdio_irq: func=%d\n", func->num); -+ ret = disable_sdio_client_isr(func); -+ if (ret) { -+ pr_err(CSDIO_DEV_NAME" Can't disable client isr(%d)\n", ret); -+ return; -+ } -+ /* signal asynchronous readers */ -+ if (g_csdio.m_async_queue) -+ kill_fasync(&g_csdio.m_async_queue, SIGIO, POLL_IN); -+} -+ -+/* -+ * The ioctl() implementation -+ */ -+static long csdio_transport_ioctl(struct file *filp, -+ unsigned int cmd, -+ unsigned long arg) -+{ -+ int err = 0; -+ int ret = 0; -+ struct csdio_file_descriptor *descriptor = filp->private_data; -+ struct csdio_func_t *port = descriptor->m_port; -+ struct sdio_func *func = port->m_func; -+ -+ /* extract the type and number bitfields -+ sanity check: return ENOTTY (inappropriate ioctl) before -+ access_ok() -+ */ -+ if ((_IOC_TYPE(cmd) != CSDIO_IOC_MAGIC) || -+ (_IOC_NR(cmd) > CSDIO_IOC_MAXNR)) { -+ pr_err(TP_DEV_NAME "Wrong ioctl command parameters\n"); -+ ret = -ENOTTY; -+ goto exit; -+ } -+ -+ /* the direction is a bitmask, and VERIFY_WRITE catches R/W -+ * transfers. `Type' is user-oriented, while access_ok is -+ kernel-oriented, so the concept of "read" and "write" is reversed -+ */ -+ 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) { -+ pr_err(TP_DEV_NAME "Wrong ioctl access direction\n"); -+ ret = -EFAULT; -+ goto exit; -+ } -+ -+ switch (cmd) { -+ case CSDIO_IOC_SET_OP_CODE: -+ { -+ pr_info(TP_DEV_NAME"%d:SET_OP_CODE=%d\n", -+ func->num, descriptor->m_op_code); -+ ret = get_user(descriptor->m_op_code, -+ (unsigned char __user *)arg); -+ if (ret) { -+ pr_err(TP_DEV_NAME"%d:SET_OP_CODE get data" -+ " from user space failed(%d)\n", -+ func->num, ret); -+ ret = -ENOTTY; -+ break; -+ } -+ } -+ break; -+ case CSDIO_IOC_FUNCTION_SET_BLOCK_SIZE: -+ { -+ unsigned block_size; -+ -+ ret = get_user(block_size, (unsigned __user *)arg); -+ if (ret) { -+ pr_err(TP_DEV_NAME"%d:SET_BLOCK_SIZE get data" -+ " from user space failed(%d)\n", -+ func->num, ret); -+ ret = -ENOTTY; -+ break; -+ } -+ pr_info(TP_DEV_NAME"%d:SET_BLOCK_SIZE=%d\n", -+ func->num, block_size); -+ sdio_claim_host(func); -+ ret = sdio_set_block_size(func, block_size); -+ if (!ret) { -+ port->m_block_size = block_size; -+ } else { -+ pr_err(TP_DEV_NAME"%d:SET_BLOCK_SIZE set block" -+ " size to %d failed (%d)\n", -+ func->num, block_size, ret); -+ ret = -ENOTTY; -+ break; -+ } -+ sdio_release_host(func); -+ } -+ break; -+ case CSDIO_IOC_SET_BLOCK_MODE: -+ { -+ pr_info(TP_DEV_NAME"%d:SET_BLOCK_MODE=%d\n", -+ func->num, descriptor->m_block_mode); -+ ret = get_user(descriptor->m_block_mode, -+ (unsigned char __user *)arg); -+ if (ret) { -+ pr_err(TP_DEV_NAME"%d:SET_BLOCK_MODE get data" -+ " from user space failed\n", -+ func->num); -+ ret = -ENOTTY; -+ break; -+ } -+ } -+ break; -+ case CSDIO_IOC_CMD52: -+ { -+ struct csdio_cmd52_ctrl_t cmd52ctrl; -+ int cmd52ret; -+ -+ if (copy_from_user(&cmd52ctrl, -+ (const unsigned char __user *)arg, -+ sizeof(cmd52ctrl))) { -+ pr_err(TP_DEV_NAME"%d:IOC_CMD52 get data" -+ " from user space failed\n", -+ func->num); -+ ret = -ENOTTY; -+ break; -+ } -+ sdio_claim_host(func); -+ if (cmd52ctrl.m_write) -+ sdio_writeb(func, cmd52ctrl.m_data, -+ cmd52ctrl.m_address, &cmd52ret); -+ else -+ cmd52ctrl.m_data = sdio_readb(func, -+ cmd52ctrl.m_address, &cmd52ret); -+ -+ cmd52ctrl.m_ret = cmd52ret; -+ sdio_release_host(func); -+ if (cmd52ctrl.m_ret) -+ pr_err(TP_DEV_NAME"%d:IOC_CMD52 failed (%d)\n", -+ func->num, cmd52ctrl.m_ret); -+ -+ if (copy_to_user((unsigned char __user *)arg, -+ &cmd52ctrl, -+ sizeof(cmd52ctrl))) { -+ pr_err(TP_DEV_NAME"%d:IOC_CMD52 put data" -+ " to user space failed\n", -+ func->num); -+ ret = -ENOTTY; -+ break; -+ } -+ } -+ break; -+ case CSDIO_IOC_CMD53: -+ { -+ struct csdio_cmd53_ctrl_t csdio_cmd53_ctrl; -+ -+ if (copy_from_user(&csdio_cmd53_ctrl, -+ (const char __user *)arg, -+ sizeof(csdio_cmd53_ctrl))) { -+ ret = -EPERM; -+ pr_err(TP_DEV_NAME"%d:" -+ "Get data from user space failed\n", -+ func->num); -+ break; -+ } -+ descriptor->m_block_mode = -+ csdio_cmd53_ctrl.m_block_mode; -+ descriptor->m_op_code = csdio_cmd53_ctrl.m_op_code; -+ descriptor->m_address = csdio_cmd53_ctrl.m_address; -+ } -+ break; -+ case CSDIO_IOC_CONNECT_ISR: -+ { -+ pr_info(CSDIO_DEV_NAME" SDIO_CONNECT_ISR" -+ " func=%d, csdio_sdio_irq=%pK\n", -+ func->num, csdio_sdio_irq); -+ sdio_claim_host(func); -+ ret = sdio_claim_irq(func, csdio_sdio_irq); -+ sdio_release_host(func); -+ if (ret) { -+ pr_err(CSDIO_DEV_NAME" SDIO_CONNECT_ISR" -+ " claim irq failed(%d)\n", ret); -+ } else { -+ /* update current irq mask for disable/enable */ -+ g_csdio.m_current_irq_mask |= (1 << func->num); -+ } -+ } -+ break; -+ case CSDIO_IOC_DISCONNECT_ISR: -+ { -+ pr_info(CSDIO_DEV_NAME " SDIO_DISCONNECT_ISR func=%d\n", -+ func->num); -+ sdio_claim_host(func); -+ sdio_release_irq(func); -+ sdio_release_host(func); -+ /* update current irq mask for disable/enable */ -+ g_csdio.m_current_irq_mask &= ~(1 << func->num); -+ } -+ break; -+ default: /* redundant, as cmd was checked against MAXNR */ -+ pr_warning(TP_DEV_NAME"%d: Redundant IOCTL\n", -+ func->num); -+ ret = -ENOTTY; -+ } -+exit: -+ return ret; -+} -+ -+static const struct file_operations csdio_transport_fops = { -+ .owner = THIS_MODULE, -+ .read = csdio_transport_read, -+ .write = csdio_transport_write, -+ .unlocked_ioctl = csdio_transport_ioctl, -+ .open = csdio_transport_open, -+ .release = csdio_transport_release, -+}; -+ -+static void csdio_transport_cleanup(struct csdio_func_t *port) -+{ -+ int devno = MKDEV(csdio_major, csdio_minor + port->m_func->num); -+ device_destroy(g_csdio.m_driver_class, devno); -+ port->m_device = NULL; -+ cdev_del(&port->m_cdev); -+} -+ -+#if defined(CONFIG_DEVTMPFS) -+static inline int csdio_cdev_update_permissions( -+ const char *devname, int dev_minor) -+{ -+ return 0; -+} -+#else -+static int csdio_cdev_update_permissions( -+ const char *devname, int dev_minor) -+{ -+ int ret = 0; -+ mm_segment_t fs; -+ struct file *file; -+ struct inode *inode; -+ struct iattr newattrs; -+ int mode = CSDIO_DEV_PERMISSIONS; -+ char dev_file[64]; -+ -+ fs = get_fs(); -+ set_fs(get_ds()); -+ -+ snprintf(dev_file, sizeof(dev_file), "/dev/%s%d", -+ devname, dev_minor); -+ file = filp_open(dev_file, O_RDWR, 0); -+ if (IS_ERR(file)) { -+ ret = -EFAULT; -+ goto exit; -+ } -+ -+ inode = file->f_path.dentry->d_inode; -+ -+ mutex_lock(&inode->i_mutex); -+ newattrs.ia_mode = -+ (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); -+ newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; -+ ret = notify_change(file->f_path.dentry, &newattrs); -+ mutex_unlock(&inode->i_mutex); -+ -+ filp_close(file, NULL); -+ -+exit: -+ set_fs(fs); -+ return ret; -+} -+#endif -+ -+static struct device *csdio_cdev_init(struct cdev *char_dev, -+ const struct file_operations *file_op, int dev_minor, -+ const char *devname, struct device *parent) -+{ -+ int ret = 0; -+ struct device *new_device = NULL; -+ dev_t devno = MKDEV(csdio_major, dev_minor); -+ -+ /* Initialize transport device */ -+ cdev_init(char_dev, file_op); -+ char_dev->owner = THIS_MODULE; -+ char_dev->ops = file_op; -+ ret = cdev_add(char_dev, devno, 1); -+ -+ /* Fail gracefully if need be */ -+ if (ret) { -+ pr_warning("Error %d adding CSDIO char device '%s%d'", -+ ret, devname, dev_minor); -+ goto exit; -+ } -+ pr_info("'%s%d' char driver registered\n", devname, dev_minor); -+ -+ /* create a /dev entry for transport drivers */ -+ new_device = device_create(g_csdio.m_driver_class, parent, devno, NULL, -+ "%s%d", devname, dev_minor); -+ if (!new_device) { -+ pr_err("Can't create device node '/dev/%s%d'\n", -+ devname, dev_minor); -+ goto cleanup; -+ } -+ /* no irq attached */ -+ g_csdio.m_current_irq_mask = 0; -+ -+ if (csdio_cdev_update_permissions(devname, dev_minor)) { -+ pr_warning("%s%d: Unable to update access permissions of the" -+ " '/dev/%s%d'\n", -+ devname, dev_minor, devname, dev_minor); -+ } -+ -+ pr_info("%s%d: Device node '/dev/%s%d' created successfully\n", -+ devname, dev_minor, devname, dev_minor); -+ goto exit; -+cleanup: -+ cdev_del(char_dev); -+exit: -+ return new_device; -+} -+ -+/* Looks for first non empty function, returns NULL otherwise */ -+static struct sdio_func *get_active_func(void) -+{ -+ int i; -+ -+ for (i = 0; i < CSDIO_NUM_OF_SDIO_FUNCTIONS; i++) { -+ if (g_csdio_func_table[i]) -+ return g_csdio_func_table[i]->m_func; -+ } -+ return NULL; -+} -+ -+static ssize_t -+show_vdd(struct device *dev, struct device_attribute *attr, char *buf) -+{ -+ if (NULL == g_csdio.m_host) -+ return snprintf(buf, PAGE_SIZE, "N/A\n"); -+ return snprintf(buf, PAGE_SIZE, "%d\n", -+ g_csdio.m_host->ios.vdd); -+} -+ -+static int -+set_vdd_helper(int value) -+{ -+ struct mmc_ios *ios = NULL; -+ -+ if (NULL == g_csdio.m_host) { -+ pr_err("%s0: Set VDD, no MMC host assigned\n", CSDIO_DEV_NAME); -+ return -ENXIO; -+ } -+ -+ mmc_claim_host(g_csdio.m_host); -+ ios = &g_csdio.m_host->ios; -+ ios->vdd = value; -+ g_csdio.m_host->ops->set_ios(g_csdio.m_host, ios); -+ mmc_release_host(g_csdio.m_host); -+ return 0; -+} -+ -+static ssize_t -+set_vdd(struct device *dev, struct device_attribute *att, -+ const char *buf, size_t count) -+{ -+ int value = 0; -+ -+ sscanf(buf, "%d", &value); -+ if (set_vdd_helper(value)) -+ return -ENXIO; -+ return count; -+} -+ -+static DEVICE_ATTR(vdd, S_IRUGO | S_IWUSR, -+ show_vdd, set_vdd); -+ -+static struct attribute *dev_attrs[] = { -+ &dev_attr_vdd.attr, -+ NULL, -+}; -+ -+static struct attribute_group dev_attr_grp = { -+ .attrs = dev_attrs, -+}; -+ -+/* -+ * The ioctl() implementation for control device -+ */ -+static long csdio_ctrl_ioctl(struct file *filp, -+ unsigned int cmd, unsigned long arg) -+{ -+ int err = 0; -+ int ret = 0; -+ -+ pr_info("CSDIO ctrl ioctl.\n"); -+ -+ /* extract the type and number bitfields -+ sanity check: return ENOTTY (inappropriate ioctl) before -+ access_ok() -+ */ -+ if ((_IOC_TYPE(cmd) != CSDIO_IOC_MAGIC) || -+ (_IOC_NR(cmd) > CSDIO_IOC_MAXNR)) { -+ pr_err(CSDIO_DEV_NAME "Wrong ioctl command parameters\n"); -+ ret = -ENOTTY; -+ goto exit; -+ } -+ -+ /* the direction is a bitmask, and VERIFY_WRITE catches R/W -+ transfers. `Type' is user-oriented, while access_ok is -+ kernel-oriented, so the concept of "read" and "write" is reversed -+ */ -+ 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) { -+ pr_err(CSDIO_DEV_NAME "Wrong ioctl access direction\n"); -+ ret = -EFAULT; -+ goto exit; -+ } -+ -+ switch (cmd) { -+ case CSDIO_IOC_ENABLE_HIGHSPEED_MODE: -+ pr_info(CSDIO_DEV_NAME" ENABLE_HIGHSPEED_MODE\n"); -+ break; -+ case CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS: -+ { -+ struct mmc_host *host = g_csdio.m_host; -+ struct mmc_ios *ios = NULL; -+ -+ if (NULL == host) { -+ pr_err("%s0: " -+ "CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS," -+ " no MMC host assigned\n", -+ CSDIO_DEV_NAME); -+ ret = -EFAULT; -+ goto exit; -+ } -+ ios = &host->ios; -+ -+ mmc_claim_host(host); -+ ret = get_user(host->ios.clock, -+ (unsigned int __user *)arg); -+ if (ret) { -+ pr_err(CSDIO_DEV_NAME -+ " get data from user space failed\n"); -+ } else { -+ pr_err(CSDIO_DEV_NAME -+ "SET_DATA_TRANSFER_CLOCKS(%d-%d)(%d)\n", -+ host->f_min, host->f_max, -+ host->ios.clock); -+ host->ops->set_ios(host, ios); -+ } -+ mmc_release_host(host); -+ } -+ break; -+ case CSDIO_IOC_ENABLE_ISR: -+ { -+ int ret; -+ unsigned char reg; -+ struct sdio_func *func = get_active_func(); -+ -+ if (!func) { -+ pr_err(CSDIO_DEV_NAME " CSDIO_IOC_ENABLE_ISR" -+ " no active sdio function\n"); -+ ret = -EFAULT; -+ goto exit; -+ } -+ pr_info(CSDIO_DEV_NAME -+ " CSDIO_IOC_ENABLE_ISR func=%d\n", -+ func->num); -+ reg = g_csdio.m_current_irq_mask | 1; -+ -+ sdio_claim_host(func); -+ sdio_f0_writeb(func, reg, SDIO_CCCR_IENx, &ret); -+ sdio_release_host(func); -+ if (ret) { -+ pr_err(CSDIO_DEV_NAME -+ " Can't sdio_f0_writeb (%d)\n", -+ ret); -+ goto exit; -+ } -+ } -+ break; -+ case CSDIO_IOC_DISABLE_ISR: -+ { -+ int ret; -+ struct sdio_func *func = get_active_func(); -+ if (!func) { -+ pr_err(CSDIO_DEV_NAME " CSDIO_IOC_ENABLE_ISR" -+ " no active sdio function\n"); -+ ret = -EFAULT; -+ goto exit; -+ } -+ pr_info(CSDIO_DEV_NAME -+ " CSDIO_IOC_DISABLE_ISR func=%p\n", -+ func); -+ -+ sdio_claim_host(func); -+ ret = disable_sdio_client_isr(func); -+ sdio_release_host(func); -+ if (ret) { -+ pr_err("%s0: Can't disable client isr (%d)\n", -+ CSDIO_DEV_NAME, ret); -+ goto exit; -+ } -+ } -+ break; -+ case CSDIO_IOC_SET_VDD: -+ { -+ unsigned int vdd = 0; -+ -+ ret = get_user(vdd, (unsigned int __user *)arg); -+ if (ret) { -+ pr_err("%s0: CSDIO_IOC_SET_VDD," -+ " get data from user space failed\n", -+ CSDIO_DEV_NAME); -+ goto exit; -+ } -+ pr_info(CSDIO_DEV_NAME" CSDIO_IOC_SET_VDD - %d\n", vdd); -+ -+ ret = set_vdd_helper(vdd); -+ if (ret) -+ goto exit; -+ } -+ break; -+ case CSDIO_IOC_GET_VDD: -+ { -+ if (NULL == g_csdio.m_host) { -+ pr_err("%s0: CSDIO_IOC_GET_VDD," -+ " no MMC host assigned\n", -+ CSDIO_DEV_NAME); -+ ret = -EFAULT; -+ goto exit; -+ } -+ ret = put_user(g_csdio.m_host->ios.vdd, -+ (unsigned short __user *)arg); -+ if (ret) { -+ pr_err("%s0: CSDIO_IOC_GET_VDD, put data" -+ " to user space failed\n", -+ CSDIO_DEV_NAME); -+ goto exit; -+ } -+ } -+ break; -+ default: /* redundant, as cmd was checked against MAXNR */ -+ pr_warning(CSDIO_DEV_NAME" Redundant IOCTL\n"); -+ ret = -ENOTTY; -+ } -+exit: -+ return ret; -+} -+ -+static int csdio_ctrl_fasync(int fd, struct file *filp, int mode) -+{ -+ pr_info(CSDIO_DEV_NAME -+ " csdio_ctrl_fasync: fd=%d, filp=%p, mode=%d\n", -+ fd, filp, mode); -+ return fasync_helper(fd, filp, mode, &g_csdio.m_async_queue); -+} -+ -+/* -+ * Open and close -+ */ -+static int csdio_ctrl_open(struct inode *inode, struct file *filp) -+{ -+ int ret = 0; -+ struct csdio_t *csdio_ctrl_drv = NULL; /* device information */ -+ -+ pr_info("CSDIO ctrl open.\n"); -+ csdio_ctrl_drv = container_of(inode->i_cdev, struct csdio_t, m_cdev); -+ filp->private_data = csdio_ctrl_drv; /* for other methods */ -+ return ret; -+} -+ -+static int csdio_ctrl_release(struct inode *inode, struct file *filp) -+{ -+ pr_info("CSDIO ctrl release.\n"); -+ /* remove this filp from the asynchronously notified filp's */ -+ csdio_ctrl_fasync(-1, filp, 0); -+ return 0; -+} -+ -+static const struct file_operations csdio_ctrl_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = csdio_ctrl_ioctl, -+ .open = csdio_ctrl_open, -+ .release = csdio_ctrl_release, -+ .fasync = csdio_ctrl_fasync, -+}; -+ -+static int csdio_probe(struct sdio_func *func, -+ const struct sdio_device_id *id) -+{ -+ struct csdio_func_t *port; -+ int ret = 0; -+ struct mmc_host *host = func->card->host; -+ -+ if (NULL != g_csdio.m_host && g_csdio.m_host != host) { -+ pr_info("%s: Device is on unexpected host\n", -+ CSDIO_DEV_NAME); -+ ret = -ENODEV; -+ goto exit; -+ } -+ -+ /* enforce single instance policy */ -+ if (g_csdio_func_table[func->num-1]) { -+ pr_err("%s - only single SDIO device supported", -+ sdio_func_id(func)); -+ ret = -EEXIST; -+ goto exit; -+ } -+ -+ port = kzalloc(sizeof(struct csdio_func_t), GFP_KERNEL); -+ if (!port) { -+ pr_err("Can't allocate memory\n"); -+ ret = -ENOMEM; -+ goto exit; -+ } -+ -+ /* initialize SDIO side */ -+ port->m_func = func; -+ sdio_set_drvdata(func, port); -+ -+ pr_info("%s - SDIO device found. Function %d\n", -+ sdio_func_id(func), func->num); -+ -+ port->m_device = csdio_cdev_init(&port->m_cdev, &csdio_transport_fops, -+ csdio_minor + port->m_func->num, -+ TP_DEV_NAME, &port->m_func->dev); -+ -+ /* create appropriate char device */ -+ if (!port->m_device) -+ goto free; -+ -+ if (0 == g_csdio.m_num_of_func && NULL == host_name) -+ g_csdio.m_host = host; -+ g_csdio.m_num_of_func++; -+ g_csdio_func_table[func->num-1] = port; -+ port->m_enabled = 1; -+ goto exit; -+free: -+ kfree(port); -+exit: -+ return ret; -+} -+ -+static void csdio_remove(struct sdio_func *func) -+{ -+ struct csdio_func_t *port = sdio_get_drvdata(func); -+ -+ csdio_transport_cleanup(port); -+ sdio_claim_host(func); -+ sdio_release_irq(func); -+ sdio_disable_func(func); -+ sdio_release_host(func); -+ kfree(port); -+ g_csdio_func_table[func->num-1] = NULL; -+ g_csdio.m_num_of_func--; -+ if (0 == g_csdio.m_num_of_func && NULL == host_name) -+ g_csdio.m_host = NULL; -+ pr_info("%s%d: Device removed (%s). Function %d\n", -+ CSDIO_DEV_NAME, func->num, sdio_func_id(func), func->num); -+} -+ -+/* CONFIG_CSDIO_VENDOR_ID and CONFIG_CSDIO_DEVICE_ID are defined in Kconfig. -+ * Use kernel configuration to change the values or overwrite them through -+ * module parameters */ -+static struct sdio_device_id csdio_ids[] = { -+ { SDIO_DEVICE(CONFIG_CSDIO_VENDOR_ID, CONFIG_CSDIO_DEVICE_ID) }, -+ { /* end: all zeroes */}, -+}; -+ -+MODULE_DEVICE_TABLE(sdio, csdio_ids); -+ -+static struct sdio_driver csdio_driver = { -+ .probe = csdio_probe, -+ .remove = csdio_remove, -+ .name = "csdio", -+ .id_table = csdio_ids, -+}; -+ -+static void __exit csdio_exit(void) -+{ -+ dev_t devno = MKDEV(csdio_major, csdio_minor); -+ -+ sdio_unregister_driver(&csdio_driver); -+ sysfs_remove_group(&g_csdio.m_device->kobj, &dev_attr_grp); -+ kfree(g_sdio_buffer); -+ device_destroy(g_csdio.m_driver_class, devno); -+ cdev_del(&g_csdio.m_cdev); -+ class_destroy(g_csdio.m_driver_class); -+ unregister_chrdev_region(devno, csdio_transport_nr_devs); -+ pr_info("%s: Exit driver module\n", CSDIO_DEV_NAME); -+} -+ -+static char *csdio_devnode(struct device *dev, umode_t *mode) -+{ -+ *mode = CSDIO_DEV_PERMISSIONS; -+ return NULL; -+} -+ -+static int __init csdio_init(void) -+{ -+ int ret = 0; -+ dev_t devno = 0; -+ -+ pr_info("Init CSDIO driver module.\n"); -+ -+ /* Get a range of minor numbers to work with, asking for a dynamic */ -+ /* major unless directed otherwise at load time. */ -+ if (csdio_major) { -+ devno = MKDEV(csdio_major, csdio_minor); -+ ret = register_chrdev_region(devno, csdio_transport_nr_devs, -+ CSDIO_DEV_NAME); -+ } else { -+ ret = alloc_chrdev_region(&devno, csdio_minor, -+ csdio_transport_nr_devs, CSDIO_DEV_NAME); -+ csdio_major = MAJOR(devno); -+ } -+ if (ret < 0) { -+ pr_err("CSDIO: can't get major %d\n", csdio_major); -+ goto exit; -+ } -+ pr_info("CSDIO char driver major number is %d\n", csdio_major); -+ -+ /* kernel module got parameters: overwrite vendor and device id's */ -+ if ((csdio_vendor_id != 0) && (csdio_device_id != 0)) { -+ csdio_ids[0].vendor = (u16)csdio_vendor_id; -+ csdio_ids[0].device = (u16)csdio_device_id; -+ } -+ -+ /* prepare create /dev/... instance */ -+ g_csdio.m_driver_class = class_create(THIS_MODULE, CSDIO_DEV_NAME); -+ if (IS_ERR(g_csdio.m_driver_class)) { -+ ret = -ENOMEM; -+ pr_err(CSDIO_DEV_NAME " class_create failed\n"); -+ goto unregister_region; -+ } -+ g_csdio.m_driver_class->devnode = csdio_devnode; -+ -+ /* create CSDIO ctrl driver */ -+ g_csdio.m_device = csdio_cdev_init(&g_csdio.m_cdev, -+ &csdio_ctrl_fops, csdio_minor, CSDIO_DEV_NAME, NULL); -+ if (!g_csdio.m_device) { -+ pr_err("%s: Unable to create ctrl driver\n", -+ CSDIO_DEV_NAME); -+ goto destroy_class; -+ } -+ -+ g_sdio_buffer = kmalloc(CSDIO_SDIO_BUFFER_SIZE, GFP_KERNEL); -+ if (!g_sdio_buffer) { -+ pr_err("Unable to allocate %d bytes\n", CSDIO_SDIO_BUFFER_SIZE); -+ ret = -ENOMEM; -+ goto destroy_cdev; -+ } -+ -+ ret = sysfs_create_group(&g_csdio.m_device->kobj, &dev_attr_grp); -+ if (ret) { -+ pr_err("%s: Unable to create device attribute\n", -+ CSDIO_DEV_NAME); -+ goto free_sdio_buff; -+ } -+ -+ g_csdio.m_num_of_func = 0; -+ g_csdio.m_host = NULL; -+ -+ if (NULL != host_name) { -+ struct device *dev = bus_find_device_by_name(&platform_bus_type, -+ NULL, host_name); -+ if (NULL != dev) { -+ g_csdio.m_host = dev_get_drvdata(dev); -+ } else { -+ pr_err("%s: Host '%s' doesn't exist!\n", CSDIO_DEV_NAME, -+ host_name); -+ } -+ } -+ -+ pr_info("%s: Match with VendorId=0x%X, DeviceId=0x%X, Host = %s\n", -+ CSDIO_DEV_NAME, csdio_device_id, csdio_vendor_id, -+ (NULL == host_name) ? "Any" : host_name); -+ -+ /* register sdio driver */ -+ ret = sdio_register_driver(&csdio_driver); -+ if (ret) { -+ pr_err("%s: Unable to register as SDIO driver\n", -+ CSDIO_DEV_NAME); -+ goto remove_group; -+ } -+ -+ goto exit; -+ -+remove_group: -+ sysfs_remove_group(&g_csdio.m_device->kobj, &dev_attr_grp); -+free_sdio_buff: -+ kfree(g_sdio_buffer); -+destroy_cdev: -+ cdev_del(&g_csdio.m_cdev); -+destroy_class: -+ class_destroy(g_csdio.m_driver_class); -+unregister_region: -+ unregister_chrdev_region(devno, csdio_transport_nr_devs); -+exit: -+ return ret; -+} -+module_param(csdio_vendor_id, uint, S_IRUGO); -+module_param(csdio_device_id, uint, S_IRUGO); -+module_param(host_name, charp, S_IRUGO); -+ -+module_init(csdio_init); -+module_exit(csdio_exit); -+ -+MODULE_AUTHOR("Code Aurora Forum"); -+MODULE_DESCRIPTION("CSDIO device driver version " VERSION); -+MODULE_VERSION(VERSION); -+MODULE_LICENSE("GPL v2"); ---- /dev/null -+++ b/include/linux/csdio.h -@@ -0,0 +1,37 @@ -+#ifndef CSDIO_H -+#define CSDIO_H -+ -+#include <linux/ioctl.h> -+ -+#define CSDIO_IOC_MAGIC 'm' -+ -+#define CSDIO_IOC_ENABLE_HIGHSPEED_MODE _IO(CSDIO_IOC_MAGIC, 0) -+#define CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS _IO(CSDIO_IOC_MAGIC, 1) -+#define CSDIO_IOC_SET_OP_CODE _IO(CSDIO_IOC_MAGIC, 2) -+#define CSDIO_IOC_FUNCTION_SET_BLOCK_SIZE _IO(CSDIO_IOC_MAGIC, 3) -+#define CSDIO_IOC_SET_BLOCK_MODE _IO(CSDIO_IOC_MAGIC, 4) -+#define CSDIO_IOC_CONNECT_ISR _IO(CSDIO_IOC_MAGIC, 5) -+#define CSDIO_IOC_DISCONNECT_ISR _IO(CSDIO_IOC_MAGIC, 6) -+#define CSDIO_IOC_CMD52 _IO(CSDIO_IOC_MAGIC, 7) -+#define CSDIO_IOC_CMD53 _IO(CSDIO_IOC_MAGIC, 8) -+#define CSDIO_IOC_ENABLE_ISR _IO(CSDIO_IOC_MAGIC, 9) -+#define CSDIO_IOC_DISABLE_ISR _IO(CSDIO_IOC_MAGIC, 10) -+#define CSDIO_IOC_SET_VDD _IO(CSDIO_IOC_MAGIC, 11) -+#define CSDIO_IOC_GET_VDD _IO(CSDIO_IOC_MAGIC, 12) -+ -+#define CSDIO_IOC_MAXNR 12 -+ -+struct csdio_cmd53_ctrl_t { -+ uint32_t m_block_mode; /* data tran. byte(0)/block(1) mode */ -+ uint32_t m_op_code; /* address auto increment flag */ -+ uint32_t m_address; -+} __attribute__ ((packed)); -+ -+struct csdio_cmd52_ctrl_t { -+ uint32_t m_write; -+ uint32_t m_address; -+ uint32_t m_data; -+ uint32_t m_ret; -+} __attribute__ ((packed)); -+ -+#endif ---- a/include/uapi/linux/Kbuild -+++ b/include/uapi/linux/Kbuild -@@ -97,6 +97,7 @@ header-y += coff.h - header-y += connector.h - header-y += const.h - header-y += cramfs_fs.h -+header-y += csdio.h - header-y += cuda.h - header-y += cyclades.h - header-y += cycx_cfm.h |
