Merge "usb: core: Limit HCD old enumeration scheme request to root ports"
diff --git a/Documentation/usb/uicc.txt b/Documentation/usb/uicc.txt
new file mode 100644
index 0000000..7bf4d86
--- /dev/null
+++ b/Documentation/usb/uicc.txt
@@ -0,0 +1,161 @@
+Introduction
+============
+
+This feature requires supporting Mass Storage and Integrated Circuit Card
+interfaces exposed by the UICC (Universal Integrated Circuit Card) device.
+The MSM acts as a USB host and UICC acts as a peripheral. The UICC device
+that is used here is also referred to as Mega-SIM. This feature will be
+supported on MSM8x26.
+
+Hardware description
+====================
+
+The USB3503 HSIC (High Speed Inter Chip) hub's down stream port is modified
+to support Inter-Chip USB for connecting the UICC device. The USB3503 is
+connected to MSM via HSIC interface. The UICC device operates in Full Speed
+mode.
+
+The UICC device will support CCID (Integrated Circuit Card interface Device)
+specification. This interface supports 1 Bulk In, 1 Bulk Out and 1 Interrupt
+endpoint. The Interrupt endpoint is used by the device to send asynchronous
+notifications like card insertion/removal and hardware error events.
+The Bulk endpoints are used for the data communication.
+
+The UICC device will support the Mass Storage Bulk Only 1.0 specification.
+It supports SCSI Transparent subclass '06', corresponding to support of the
+SCSI Primary Command set. It implements SCSI Peripheral Device Type '00'
+(TYPE_DISK) corresponding to a direct access SCSI block device.
+
+Software description
+====================
+
+The MSM HSIC controller driver(drivers/usb/host/ehci-msm-hsic.c)  takes care
+of HSIC PHY and link management. The USB3503 HSIC hub is managed by the SMSC
+hub driver(drivers/misc/smsc_hubc.c). Both these drivers are well tested on
+APQ8074 dragon board and are re-used to support this feature.
+
+The mass storage interface is managed by the standard Linux USB storage driver.
+This driver interfaces with SCSI and block layers to export the disk to
+user space.
+
+A new USB driver is implemented to manage the CCID interface. This driver is
+referred to as USB CCID driver in this document. This driver is implemented
+as a pass-through module and provides the character device interface to
+user space. The CCID specification is implemented in the user space.
+
+The CCID command and responses are exchanged over the Bulk endpoints. The
+user space application uses write() and read() calls to send commands and
+receive responses.
+
+The CCID class specific requests are sent over the control endpoint. As
+control requests have a specific format, ioctls are implemented.
+
+The UICC device sends asynchronous notifications over the interrupt endpoint.
+The card insertion/removal and hardware error events are sent to user space
+via an ioctl().
+
+Design Goals:
+============
+
+1. Re-use the existing services available in user space. This is achieved
+by implementing the kernel USB CCID driver as a pass-through module.
+
+2. Support runtime card insertion/removal.
+
+3. Support runtime power management.
+
+4. Support Multiple card configuration. More than 1 IC can be connected to
+the USB UICC device.
+
+Power Management
+================
+
+The USB core uses the runtime PM framework to auto suspend the USB devices that
+are not in use. The Auto-suspend is forbidden for all devices except hub class
+devices. The USB CCID driver enables auto-suspend for the UICC device.
+
+An USB device can be suspended only when all of its interfaces are suspended.
+The USB storage interface device acts as a parent device to the underlying
+SCSI host, target and block devices. Runtime PM must be enabled for the
+SCSI device to allow USB storage interface suspend. The SCSI device runtime
+suspend and auto-suspend timeout will be configured from user space via sysfs
+files.
+
+The HSIC platform device and USB3503 HUB device will be runtime suspended
+only after the USB UICC device is suspended.
+
+SMP/multi-core
+==============
+
+The USB CCID driver does not allow multiple clients to open the device file
+concurrently. -EBUSY will be returned if open() is attempted when the
+file is already opened.
+
+The write() and read() methods are implemented synchronously. If another
+write() is called when a previous write() is in progress, -EBUSY is
+returned. The same is applicable to read().
+
+Mutexes will be used to prevent concurrent open(), read() and write() access.
+
+Interface
+=========
+
+A character device file (/dev/ccid_bridge) will be exposed by the USB CCID
+driver. open(), read(), write(), ioctl() and close() methods are implemented.
+This device node is accessible only to the root by default.  User space init
+or udev scripts should change the permissions of this device file if it needs
+to be accessed by non-root applications.
+
+open(): The open() is blocked until the UICC device is detected and the CCID
+interface probe is completed. Returns the appropriate error code in case of
+failure.
+
+read(): An URB is submitted on the Bulk In endpoint. The read() is blocked
+until the URB is completed and the data is copied to the user space buffer
+upon success. An appropriate error code is returned in case of failure.
+-ENODEV must be treated as a serious error and no further I/O will be
+attempted.
+
+write(): An URB is submitted on the Bulk Out endpoint. The write() is blocked
+until the URB is completed. An appropriate error code is returned in case of
+failure. -ENODEV must be treated as a serious error and no further I/O will be
+attempted.
+
+ioctl(): The ioctl() method is required for facilitating Control transfers and
+Interrupt transfers.
+
+USB_CCID_GET_CLASS_DESC: This read-only ioctl returns the smart card class
+descriptor as described in the 5.1 section of USB smart card class spec.
+
+USB_CCID_ABORT: This write-only ioctl sends A ABORT class specific request on
+control endpoint. The class request details are mentioned in section 5.3.1.
+
+USB_CCID_GET_CLOCK_FREQUENCIES: This read and write ioctl returns the clock
+frequencies supported by the CCID device. A GET_CLOCK_FREQUENCIES class request
+is sent on the control endpoint. The class request details are mentioned in
+section 5.3.2.
+
+USB_CCID_GET_DATA_RATES: This read and write ioctl returns the data rates
+supported by the CCID device. A GET_DATA_RATES class request is sent on the
+control endpoint. The class request details are mentioned in section 5.3.3.
+
+USB_CCID_GET_EVENT: This read-only ioctl returns the asynchronous event sent
+by the UICC device. The ioctl() is blocked until such event is received from
+the UICC device. This ioctl() returns -ENOENT error code when the device
+does not have an interrupt endpoint and does not support remote wakeup
+capability.
+
+close(): Cancels any ongoing I/O before it returns.
+
+Config options
+==============
+
+Turn on USB_EHCI_MSM_HSIC, USB_HSIC_SMSC_HUB and USB_CCID_BRIDGE configs to
+enable this feature.
+
+References
+==========
+
+Specification for Integrated Circuit(s) Cards Interface Devices
+
+Smart Cards; UICC-Terminal interface; Physical and logical characteristics
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 9176117..5607257 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -122,7 +122,7 @@
 	qcom,dec-ocmem-ab-ib = <0 0>,
 		<176000 519000>,
 		<456000 519000>,
-		<864000 519000>,
+		<864000 629000>,
 		<1728000 1038000>,
 		<2766000 1661000>,
 		<3456000 2076000>,
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 6b1f88d..6c3898c 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -359,6 +359,7 @@
 CONFIG_USB_EHCI_MSM=y
 CONFIG_USB_EHCI_MSM_HSIC=y
 CONFIG_USB_ACM=y
+CONFIG_USB_CCID_BRIDGE=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DATAFAB=y
 CONFIG_USB_STORAGE_FREECOM=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 2d54549..e14118d 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -383,6 +383,7 @@
 CONFIG_USB_EHCI_MSM=y
 CONFIG_USB_EHCI_MSM_HSIC=y
 CONFIG_USB_ACM=y
+CONFIG_USB_CCID_BRIDGE=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DATAFAB=y
 CONFIG_USB_STORAGE_FREECOM=y
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index d1b1885..3ea719f 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -151,6 +151,7 @@
 
 #define PLL_POLL_MAX_READS	10
 #define PLL_POLL_TIMEOUT_US	50
+#define SEQ_M_MAX_COUNTER	7
 
 static long vco_cached_rate;
 static unsigned char *mdss_dsi_base;
@@ -1034,12 +1035,12 @@
 static void dsi_pll_toggle_lock_detect(void)
 {
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
-		0x05);
+		0x0d);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
-		0x04);
+		0x0c);
 	udelay(1);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
-		0x05);
+		0x0d);
 }
 
 static int dsi_pll_lock_status(void)
@@ -1093,24 +1094,25 @@
 	 * the updates to take effect. These delays are necessary for the
 	 * PLL to successfully lock
 	 */
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x34);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
-	udelay(1000);
+	udelay(600);
 
 	pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
-	for (i = 0; (i < 4) && !pll_locked; i++) {
+	for (i = 0; (i < SEQ_M_MAX_COUNTER) && !pll_locked; i++) {
+		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG,
+			0x00);
+		udelay(50);
 		DSS_REG_W(mdss_dsi_base,
-			DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
-		if (i != 0)
-			DSS_REG_W(mdss_dsi_base,
-				DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x34);
-		udelay(1);
+			DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+		udelay(100);
 		DSS_REG_W(mdss_dsi_base,
 			DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
-		udelay(1000);
+		udelay(600);
 		pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
 	}
 
@@ -1134,6 +1136,8 @@
 	 * the updates to take effect. These delays are necessary for the
 	 * PLL to successfully lock
 	 */
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+	udelay(50);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
@@ -1145,7 +1149,7 @@
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
-	udelay(1000);
+	udelay(600);
 
 	pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
 	pr_debug("%s: PLL status = %s\n", __func__,
@@ -1165,6 +1169,8 @@
 	 * the updates to take effect. These delays are necessary for the
 	 * PLL to successfully lock
 	 */
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+	udelay(50);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
@@ -1174,7 +1180,7 @@
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0d);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
-	udelay(1000);
+	udelay(600);
 
 	pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
 	pr_debug("%s: PLL status = %s\n", __func__,
@@ -1194,12 +1200,14 @@
 	 * the updates to take effect. These delays are necessary for the
 	 * PLL to successfully lock
 	 */
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+	udelay(50);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
-	udelay(1000);
+	udelay(600);
 
 	pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
 	pr_debug("%s: PLL status = %s\n", __func__,
@@ -1219,6 +1227,8 @@
 	 * the updates to take effect. These delays are necessary for the
 	 * PLL to successfully lock
 	 */
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+	udelay(50);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
@@ -1226,7 +1236,7 @@
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0d);
 	udelay(1);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
-	udelay(1000);
+	udelay(600);
 
 	pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
 	pr_debug("%s: PLL status = %s\n", __func__,
@@ -1258,10 +1268,10 @@
 	for (i = 0; i < 3; i++) {
 		/* DSI Uniphy lock detect setting */
 		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
-			0x04);
+			0x0c);
 		udelay(100);
 		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
-			0x05);
+			0x0d);
 		udelay(500);
 		/* poll for PLL ready status */
 		max_reads = 5;
@@ -1459,7 +1469,7 @@
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG, 0x02);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG3, 0x2b);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG4, 0x66);
-	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x05);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x0d);
 
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG1,
 		(u32)(sdm_cfg1 & 0xff));
@@ -1478,7 +1488,7 @@
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG, 0x71);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0,
 		(u32)sdm_cfg0);
-	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG0, 0x0a);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG0, 0x12);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG6, 0x30);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG7, 0x00);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG8, 0x60);
@@ -1640,13 +1650,14 @@
 	.ref_clk_rate = 19200000,
 	.min_rate = 350000000,
 	.max_rate = 750000000,
-	.pll_en_seq_cnt = 6,
+	.pll_en_seq_cnt = 7,
 	.pll_enable_seqs[0] = dsi_pll_enable_seq_m,
-	.pll_enable_seqs[1] = dsi_pll_enable_seq_d,
+	.pll_enable_seqs[1] = dsi_pll_enable_seq_m,
 	.pll_enable_seqs[2] = dsi_pll_enable_seq_d,
-	.pll_enable_seqs[3] = dsi_pll_enable_seq_f1,
-	.pll_enable_seqs[4] = dsi_pll_enable_seq_c,
-	.pll_enable_seqs[5] = dsi_pll_enable_seq_e,
+	.pll_enable_seqs[3] = dsi_pll_enable_seq_d,
+	.pll_enable_seqs[4] = dsi_pll_enable_seq_f1,
+	.pll_enable_seqs[5] = dsi_pll_enable_seq_c,
+	.pll_enable_seqs[6] = dsi_pll_enable_seq_e,
 	.lpfr_lut_size = 10,
 	.lpfr_lut = (struct lpfr_cfg[]){
 		{479500000, 8},
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index 9d33bf4..73dd868 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -108,8 +108,7 @@
  *
  * Note that the `pages' array should be composed of all 4K pages.
  */
-int ion_heap_pages_zero(struct page **pages, int num_pages,
-				bool should_invalidate)
+int ion_heap_pages_zero(struct page **pages, int num_pages)
 {
 	int i, j, k, npages_to_vmap;
 	void *ptr = NULL;
@@ -143,19 +142,17 @@
 			return -ENOMEM;
 
 		memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
-		if (should_invalidate) {
-			/*
-			 * invalidate the cache to pick up the zeroing
-			 */
-			for (k = 0; k < npages_to_vmap; k++) {
-				void *p = kmap_atomic(pages[i + k]);
-				phys_addr_t phys = page_to_phys(
-							pages[i + k]);
+		/*
+		 * invalidate the cache to pick up the zeroing
+		 */
+		for (k = 0; k < npages_to_vmap; k++) {
+			void *p = kmap_atomic(pages[i + k]);
+			phys_addr_t phys = page_to_phys(
+				pages[i + k]);
 
-				dmac_inv_range(p, p + PAGE_SIZE);
-				outer_inv_range(phys, phys + PAGE_SIZE);
-				kunmap_atomic(p);
-			}
+			dmac_inv_range(p, p + PAGE_SIZE);
+			outer_inv_range(phys, phys + PAGE_SIZE);
+			kunmap_atomic(p);
 		}
 		vunmap(ptr);
 	}
@@ -196,8 +193,7 @@
 	pages_mem->free_fn(pages_mem->pages);
 }
 
-int ion_heap_high_order_page_zero(struct page *page,
-				int order, bool should_invalidate)
+int ion_heap_high_order_page_zero(struct page *page, int order)
 {
 	int i, ret;
 	struct pages_mem pages_mem;
@@ -210,8 +206,7 @@
 	for (i = 0; i < (1 << order); ++i)
 		pages_mem.pages[i] = page + i;
 
-	ret = ion_heap_pages_zero(pages_mem.pages, npages,
-				should_invalidate);
+	ret = ion_heap_pages_zero(pages_mem.pages, npages);
 	ion_heap_free_pages_mem(&pages_mem);
 	return ret;
 }
@@ -240,8 +235,7 @@
 			pages_mem.pages[npages++] = page + j;
 	}
 
-	ret = ion_heap_pages_zero(pages_mem.pages, npages,
-				ion_buffer_cached(buffer));
+	ret = ion_heap_pages_zero(pages_mem.pages, npages);
 	ion_heap_free_pages_mem(&pages_mem);
 	return ret;
 }
diff --git a/drivers/gpu/ion/ion_page_pool.c b/drivers/gpu/ion/ion_page_pool.c
index 94f9445..cc2a36d 100644
--- a/drivers/gpu/ion/ion_page_pool.c
+++ b/drivers/gpu/ion/ion_page_pool.c
@@ -40,8 +40,7 @@
 		return NULL;
 
 	if (pool->gfp_mask & __GFP_ZERO)
-		if (ion_heap_high_order_page_zero(
-				page, pool->order, pool->should_invalidate))
+		if (ion_heap_high_order_page_zero(page, pool->order))
 			goto error_free_pages;
 
 	sg_init_table(&sg, 1);
@@ -175,8 +174,7 @@
 	return nr_freed;
 }
 
-struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
-	bool should_invalidate)
+struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)
 {
 	struct ion_page_pool *pool = kmalloc(sizeof(struct ion_page_pool),
 					     GFP_KERNEL);
@@ -188,7 +186,6 @@
 	INIT_LIST_HEAD(&pool->high_items);
 	pool->gfp_mask = gfp_mask;
 	pool->order = order;
-	pool->should_invalidate = should_invalidate;
 	mutex_init(&pool->mutex);
 	plist_node_init(&pool->list, order);
 
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index aa0a9e2..c57efc1 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -234,11 +234,9 @@
 void ion_heap_unmap_kernel(struct ion_heap *, struct ion_buffer *);
 int ion_heap_map_user(struct ion_heap *, struct ion_buffer *,
 			struct vm_area_struct *);
-int ion_heap_pages_zero(struct page **pages, int num_pages,
-			bool should_invalidate);
+int ion_heap_pages_zero(struct page **pages, int num_pages);
 int ion_heap_buffer_zero(struct ion_buffer *buffer);
-int ion_heap_high_order_page_zero(struct page *page,
-				int order, bool should_invalidate);
+int ion_heap_high_order_page_zero(struct page *page, int order);
 
 /**
  * ion_heap_init_deferred_free -- initialize deferred free functionality
@@ -357,8 +355,6 @@
  * @gfp_mask:		gfp_mask to use from alloc
  * @order:		order of pages in the pool
  * @list:		plist node for list of pools
- * @should_invalidate:	whether or not the cache needs to be invalidated at
- *			page allocation time.
  *
  * Allows you to keep a pool of pre allocated pages to use from your heap.
  * Keeping a pool of pages that is ready for dma, ie any cached mapping have
@@ -374,11 +370,9 @@
 	gfp_t gfp_mask;
 	unsigned int order;
 	struct plist_node list;
-	bool should_invalidate;
 };
 
-struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
-	bool should_invalidate);
+struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order);
 void ion_page_pool_destroy(struct ion_page_pool *);
 void *ion_page_pool_alloc(struct ion_page_pool *);
 void ion_page_pool_free(struct ion_page_pool *, struct page *);
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index 8e885b2..be1a89c 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -355,8 +355,7 @@
  * nothing. If it succeeds you'll eventually need to use
  * ion_system_heap_destroy_pools to destroy the pools.
  */
-static int ion_system_heap_create_pools(struct ion_page_pool **pools,
-					bool should_invalidate)
+static int ion_system_heap_create_pools(struct ion_page_pool **pools)
 {
 	int i;
 	for (i = 0; i < num_orders; i++) {
@@ -365,8 +364,7 @@
 
 		if (orders[i] > 4)
 			gfp_flags = high_order_gfp_flags;
-		pool = ion_page_pool_create(gfp_flags, orders[i],
-					should_invalidate);
+		pool = ion_page_pool_create(gfp_flags, orders[i]);
 		if (!pool)
 			goto err_create_pool;
 		pools[i] = pool;
@@ -397,10 +395,10 @@
 	if (!heap->cached_pools)
 		goto err_alloc_cached_pools;
 
-	if (ion_system_heap_create_pools(heap->uncached_pools, false))
+	if (ion_system_heap_create_pools(heap->uncached_pools))
 		goto err_create_uncached_pools;
 
-	if (ion_system_heap_create_pools(heap->cached_pools, true))
+	if (ion_system_heap_create_pools(heap->cached_pools))
 		goto err_create_cached_pools;
 
 	heap->heap.shrinker.shrink = ion_system_heap_shrink;
diff --git a/drivers/gpu/msm/adreno_coresight.c b/drivers/gpu/msm/adreno_coresight.c
index 1b827ff..d0ba145 100644
--- a/drivers/gpu/msm/adreno_coresight.c
+++ b/drivers/gpu/msm/adreno_coresight.c
@@ -55,7 +55,12 @@
 int adreno_coresight_enable(struct coresight_device *csdev)
 {
 	struct kgsl_device *device = dev_get_drvdata(csdev->dev.parent);
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_device *adreno_dev;
+
+	if (device == NULL)
+		return -ENODEV;
+
+	adreno_dev = ADRENO_DEVICE(device);
 
 	/* Check if coresight compatible device, return error otherwise */
 	if (adreno_dev->gpudev->coresight_enable)
@@ -80,7 +85,12 @@
 void adreno_coresight_disable(struct coresight_device *csdev)
 {
 	struct kgsl_device *device = dev_get_drvdata(csdev->dev.parent);
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_device *adreno_dev;
+
+	if (device == NULL)
+		return;
+
+	adreno_dev = ADRENO_DEVICE(device);
 
 	/* Check if coresight compatible device, bail otherwise */
 	if (adreno_dev->gpudev->coresight_disable)
@@ -134,6 +144,10 @@
 	struct kgsl_device *device = dev_get_drvdata(dev->parent);
 	struct coresight_attr *csight_attr = container_of(attr,
 			struct coresight_attr, attr);
+
+	if (device == NULL)
+		return -ENODEV;
+
 	return coresight_read_reg(device, csight_attr->regname, buf);
 }
 
@@ -142,11 +156,16 @@
 		const char *buf, size_t size)
 {
 	struct kgsl_device *device = dev_get_drvdata(dev->parent);
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_device *adreno_dev;
 	struct coresight_attr *csight_attr = container_of(attr,
 			struct coresight_attr, attr);
 	unsigned int regval = 0;
 
+	if (device == NULL)
+		return -ENODEV;
+
+	adreno_dev = ADRENO_DEVICE(device);
+
 	regval = coresight_convert_reg(buf);
 
 	if (adreno_dev->gpudev->coresight_config_debug_reg)
diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig
index 2519e32..f7321e5 100644
--- a/drivers/usb/class/Kconfig
+++ b/drivers/usb/class/Kconfig
@@ -50,3 +50,15 @@
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called usbtmc.
+
+config USB_CCID_BRIDGE
+	tristate "USB  Smart Card Class (CCID) support"
+	help
+	  Say Y here if you want to connect a USB Smart Card device that
+	  follows the USB.org specification for Integrated Circuit(s) Cards
+	  Interface Devices to your computer's USB port.  This module
+	  provides a character device interface to exchange the messages.
+	  Ioctls facilitate control transfers and interrupt transfers.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ccid_bridge.
diff --git a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile
index 32e8527..c2ee6f3 100644
--- a/drivers/usb/class/Makefile
+++ b/drivers/usb/class/Makefile
@@ -7,3 +7,4 @@
 obj-$(CONFIG_USB_PRINTER)	+= usblp.o
 obj-$(CONFIG_USB_WDM)		+= cdc-wdm.o
 obj-$(CONFIG_USB_TMC)		+= usbtmc.o
+obj-$(CONFIG_USB_CCID_BRIDGE)	+= ccid_bridge.o
diff --git a/drivers/usb/class/ccid_bridge.c b/drivers/usb/class/ccid_bridge.c
new file mode 100644
index 0000000..a3e100a
--- /dev/null
+++ b/drivers/usb/class/ccid_bridge.c
@@ -0,0 +1,885 @@
+/* Copyright (c) 2013, The Linux Foundation. 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt "\n", __func__
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/wait.h>
+#include <linux/cdev.h>
+
+#include <linux/usb/ccid_bridge.h>
+
+#define CCID_CLASS_DECRIPTOR_TYPE 0x21
+#define CCID_NOTIFY_SLOT_CHANGE	0x50
+#define CCID_NOTIFY_HARDWARE_ERROR 0x51
+#define CCID_ABORT_REQ 0x1
+#define CCID_GET_CLK_FREQ_REQ 0x2
+#define CCID_GET_DATA_RATES 0x3
+
+#define CCID_BRIDGE_MSG_SZ 512
+#define CCID_BRIDGE_OPEN_TIMEOUT 500 /* msec */
+#define CCID_CONTROL_TIMEOUT 500 /* msec */
+#define CCID_BRIDGE_MSG_TIMEOUT 500 /* msec */
+
+struct ccid_bridge {
+	struct usb_device *udev;
+	struct usb_interface *intf;
+	unsigned int in_pipe;
+	unsigned int out_pipe;
+	unsigned int int_pipe;
+	struct urb *inturb;
+	struct urb *readurb;
+	struct urb *writeurb;
+
+	bool opened;
+	bool events_supported;
+	bool is_suspended;
+	struct mutex open_mutex;
+	struct mutex write_mutex;
+	struct mutex read_mutex;
+	struct mutex event_mutex;
+	int write_result;
+	int read_result;
+	int event_result;
+	wait_queue_head_t open_wq;
+	wait_queue_head_t write_wq;
+	wait_queue_head_t read_wq;
+	wait_queue_head_t event_wq;
+	struct usb_ccid_event cur_event;
+	void *intbuf;
+
+	dev_t chrdev;
+	struct cdev cdev;
+	struct class *class;
+	struct device *device;
+};
+
+static struct ccid_bridge *__ccid_bridge_dev;
+
+static void ccid_bridge_out_cb(struct urb *urb)
+{
+	struct ccid_bridge *ccid = urb->context;
+
+	if (urb->dev->state == USB_STATE_NOTATTACHED)
+		ccid->write_result = -ENODEV;
+	else
+		ccid->write_result = urb->status ? : urb->actual_length;
+
+	pr_debug("write result = %d", ccid->write_result);
+	wake_up(&ccid->write_wq);
+}
+
+static void ccid_bridge_in_cb(struct urb *urb)
+{
+	struct ccid_bridge *ccid = urb->context;
+
+	if (urb->dev->state == USB_STATE_NOTATTACHED)
+		ccid->read_result = -ENODEV;
+	else
+		ccid->read_result = urb->status ? : urb->actual_length;
+
+	pr_debug("read result = %d", ccid->read_result);
+	wake_up(&ccid->read_wq);
+}
+
+static void ccid_bridge_int_cb(struct urb *urb)
+{
+	struct ccid_bridge *ccid = urb->context;
+	u8 *msg_type;
+	bool wakeup = true;
+
+	if (urb->dev->state == USB_STATE_NOTATTACHED || (urb->status &&
+				urb->status != -ENOENT)) {
+		ccid->event_result = -ENODEV;
+		wakeup = true;
+		goto out;
+	}
+
+	/*
+	 * Don't wakeup the event ioctl process during suspend.
+	 * The suspend state is not visible to user space.
+	 * we wake up the process after resume to send RESUME
+	 * event if the device supports remote wakeup.
+	 */
+	if (urb->status == -ENOENT && !urb->actual_length) {
+		ccid->event_result = -ENOENT;
+		wakeup = false;
+		goto out;
+	}
+
+	ccid->event_result = 0;
+	msg_type = urb->transfer_buffer;
+	switch (*msg_type) {
+	case CCID_NOTIFY_SLOT_CHANGE:
+		pr_debug("NOTIFY_SLOT_CHANGE event arrived");
+		ccid->cur_event.event = USB_CCID_NOTIFY_SLOT_CHANGE_EVENT;
+		ccid->cur_event.u.notify.slot_icc_state = *(++msg_type);
+		break;
+	case CCID_NOTIFY_HARDWARE_ERROR:
+		pr_debug("NOTIFY_HARDWARE_ERROR event arrived");
+		ccid->cur_event.event = USB_CCID_HARDWARE_ERROR_EVENT;
+		ccid->cur_event.u.error.slot = *(++msg_type);
+		ccid->cur_event.u.error.seq = *(++msg_type);
+		ccid->cur_event.u.error.error_code = *(++msg_type);
+		break;
+	default:
+		pr_err("UNKNOWN event arrived\n");
+		ccid->event_result = -EINVAL;
+	}
+
+out:
+	pr_debug("returning %d", ccid->event_result);
+	if (wakeup)
+		wake_up(&ccid->event_wq);
+}
+
+static int ccid_bridge_submit_inturb(struct ccid_bridge *ccid)
+{
+	int ret = 0;
+
+	/*
+	 * Don't resume the bus to submit an interrupt URB.
+	 * We submit the URB in resume path.  This is important.
+	 * Because the device will be in suspend state during
+	 * multiple system suspend/resume cycles.  The user space
+	 * process comes here during system resume after it is
+	 * unfrozen.
+	 */
+	if (!ccid->int_pipe || ccid->is_suspended)
+		goto out;
+
+	ret = usb_autopm_get_interface(ccid->intf);
+	if (ret < 0) {
+		pr_debug("fail to get autopm with %d\n", ret);
+		goto out;
+	}
+	ret = usb_submit_urb(ccid->inturb, GFP_KERNEL);
+	if (ret < 0)
+		pr_err("fail to submit int urb with %d\n", ret);
+	usb_autopm_put_interface(ccid->intf);
+
+out:
+	pr_debug("returning %d", ret);
+	return ret;
+}
+
+static int ccid_bridge_get_event(struct ccid_bridge *ccid)
+{
+	int ret = 0;
+
+	/*
+	 * The first event returned after the device resume
+	 * will be RESUME event.  This event is set by
+	 * the resume.
+	 */
+	if (ccid->cur_event.event)
+		goto out;
+
+	ccid->event_result = -EINPROGRESS;
+
+	ret = ccid_bridge_submit_inturb(ccid);
+	if (ret < 0)
+		goto out;
+
+	/*
+	 * Wait for the notification on interrupt endpoint
+	 * or remote wakeup event from the resume.  The
+	 * int urb completion handler and resume callback
+	 * take care of setting the current event.
+	 */
+	mutex_unlock(&ccid->event_mutex);
+	ret = wait_event_interruptible(ccid->event_wq,
+			(ccid->event_result != -EINPROGRESS));
+	mutex_lock(&ccid->event_mutex);
+
+	if (ret == -ERESTARTSYS) /* interrupted */
+		usb_kill_urb(ccid->inturb);
+	else
+		ret = ccid->event_result;
+out:
+	pr_debug("returning %d", ret);
+	return ret;
+}
+
+static int ccid_bridge_open(struct inode *ip, struct file *fp)
+{
+	struct ccid_bridge *ccid = container_of(ip->i_cdev,
+				struct ccid_bridge, cdev);
+	int ret;
+
+	pr_debug("called");
+
+	mutex_lock(&ccid->open_mutex);
+	if (ccid->opened) {
+		ret = -EBUSY;
+		goto out;
+	}
+	mutex_unlock(&ccid->open_mutex);
+
+	ret = wait_event_interruptible_timeout(ccid->open_wq,
+			ccid->intf != NULL, msecs_to_jiffies(
+				CCID_BRIDGE_OPEN_TIMEOUT));
+
+	mutex_lock(&ccid->open_mutex);
+
+	if (ret != -ERESTARTSYS && ccid->intf) {
+		fp->private_data = ccid;
+		ccid->opened = true;
+		ret = 0;
+	} else if (!ret) { /* timed out */
+		ret = -ENODEV;
+	}
+out:
+	mutex_unlock(&ccid->open_mutex);
+	pr_debug("returning %d", ret);
+	return ret;
+}
+
+static ssize_t ccid_bridge_write(struct file *fp, const char __user *ubuf,
+				 size_t count, loff_t *pos)
+{
+	struct ccid_bridge *ccid = fp->private_data;
+	int ret;
+	char *kbuf;
+
+	pr_debug("called with %d", count);
+
+	if (!ccid->intf) {
+		pr_debug("intf is not active");
+		return -ENODEV;
+	}
+
+	mutex_lock(&ccid->write_mutex);
+
+	if (!count || count > CCID_BRIDGE_MSG_SZ) {
+		pr_err("invalid count");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	kbuf = kmalloc(count, GFP_KERNEL);
+	if (!kbuf) {
+		pr_err("fail to allocate memory");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = copy_from_user(kbuf, ubuf, count);
+	if (ret) {
+		pr_err("fail to copy user buf");
+		ret = -EFAULT;
+		goto free_kbuf;
+	}
+
+	ret = usb_autopm_get_interface(ccid->intf);
+	if (ret) {
+		pr_err("fail to get autopm with %d", ret);
+		goto free_kbuf;
+	}
+
+	ccid->write_result = 0;
+
+	usb_fill_bulk_urb(ccid->writeurb, ccid->udev, ccid->out_pipe,
+			kbuf, count, ccid_bridge_out_cb, ccid);
+	ret = usb_submit_urb(ccid->writeurb, GFP_KERNEL);
+	if (ret < 0) {
+		pr_err("urb submit fail with %d", ret);
+		goto put_pm;
+	}
+
+	ret = wait_event_interruptible_timeout(ccid->write_wq,
+			ccid->write_result != 0,
+			msecs_to_jiffies(CCID_BRIDGE_MSG_TIMEOUT));
+	if (!ret || ret == -ERESTARTSYS) { /* timedout or interrupted */
+		usb_kill_urb(ccid->writeurb);
+		if (!ret)
+			ret = -ETIMEDOUT;
+	} else {
+		ret = ccid->write_result;
+	}
+
+	pr_debug("returning %d", ret);
+
+put_pm:
+	if (ret != -ENODEV)
+		usb_autopm_put_interface(ccid->intf);
+free_kbuf:
+	kfree(kbuf);
+out:
+	mutex_unlock(&ccid->write_mutex);
+	return ret;
+
+}
+
+static ssize_t ccid_bridge_read(struct file *fp, char __user *ubuf,
+				 size_t count, loff_t *pos)
+{
+	struct ccid_bridge *ccid = fp->private_data;
+	int ret;
+	char *kbuf;
+
+	pr_debug("called with %d", count);
+	if (!ccid->intf) {
+		pr_debug("intf is not active");
+		return -ENODEV;
+	}
+
+	mutex_lock(&ccid->read_mutex);
+
+	if (!count || count > CCID_BRIDGE_MSG_SZ) {
+		pr_err("invalid count");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	kbuf = kmalloc(count, GFP_KERNEL);
+	if (!kbuf) {
+		pr_err("fail to allocate memory");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = usb_autopm_get_interface(ccid->intf);
+	if (ret) {
+		pr_err("fail to get autopm with %d", ret);
+		goto free_kbuf;
+	}
+
+	ccid->read_result = 0;
+
+	usb_fill_bulk_urb(ccid->readurb, ccid->udev, ccid->in_pipe,
+			kbuf, count, ccid_bridge_in_cb, ccid);
+	ret = usb_submit_urb(ccid->readurb, GFP_KERNEL);
+	if (ret < 0) {
+		pr_err("urb submit fail with %d", ret);
+		if (ret != -ENODEV)
+			usb_autopm_put_interface(ccid->intf);
+		goto free_kbuf;
+	}
+
+
+	ret = wait_event_interruptible_timeout(ccid->read_wq,
+			ccid->read_result != 0,
+			msecs_to_jiffies(CCID_BRIDGE_MSG_TIMEOUT));
+	if (!ret || ret == -ERESTARTSYS) { /* timedout or interrupted */
+		usb_kill_urb(ccid->readurb);
+		if (!ret)
+			ret = -ETIMEDOUT;
+	} else {
+		ret = ccid->read_result;
+	}
+
+
+	if (ret > 0) {
+		if (copy_to_user(ubuf, kbuf, ret))
+			ret = -EFAULT;
+	}
+
+	usb_autopm_put_interface(ccid->intf);
+	pr_debug("returning %d", ret);
+
+free_kbuf:
+	kfree(kbuf);
+out:
+	mutex_unlock(&ccid->read_mutex);
+	return ret;
+}
+
+static long
+ccid_bridge_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+	struct ccid_bridge *ccid = fp->private_data;
+	char *buf;
+	struct usb_ccid_data data;
+	struct usb_ccid_abort abort;
+	struct usb_descriptor_header *header;
+	int ret;
+	struct usb_device *udev = ccid->udev;
+	__u8 intf = ccid->intf->cur_altsetting->desc.bInterfaceNumber;
+	__u8 breq = 0;
+
+	if (!ccid->intf) {
+		pr_debug("intf is not active");
+		return -ENODEV;
+	}
+
+	mutex_lock(&ccid->event_mutex);
+	switch (cmd) {
+	case USB_CCID_GET_CLASS_DESC:
+		pr_debug("GET_CLASS_DESC ioctl called");
+		ret = copy_from_user(&data, (void __user *)arg, sizeof(data));
+		if (ret) {
+			ret = -EFAULT;
+			break;
+		}
+		ret = __usb_get_extra_descriptor(udev->rawdescriptors[0],
+				le16_to_cpu(udev->config[0].desc.wTotalLength),
+				CCID_CLASS_DECRIPTOR_TYPE, (void **) &buf);
+		if (ret) {
+			ret = -ENOENT;
+			break;
+		}
+		header = (struct usb_descriptor_header *) buf;
+		if (data.length != header->bLength) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = copy_to_user((void __user *)data.data, buf, data.length);
+		if (ret)
+			ret = -EFAULT;
+		break;
+	case USB_CCID_GET_CLOCK_FREQUENCIES:
+		pr_debug("GET_CLOCK_FREQUENCIES ioctl called");
+		breq = CCID_GET_CLK_FREQ_REQ;
+		/* fall through */
+	case USB_CCID_GET_DATA_RATES:
+		if (!breq) {
+			pr_debug("GET_DATA_RATES ioctl called");
+			breq = CCID_GET_DATA_RATES;
+		}
+		ret = copy_from_user(&data, (void __user *)arg, sizeof(data));
+		if (ret) {
+			ret = -EFAULT;
+			break;
+		}
+		buf = kmalloc(data.length, GFP_KERNEL);
+		if (!buf) {
+			ret = -ENOMEM;
+			break;
+		}
+		ret = usb_autopm_get_interface(ccid->intf);
+		if (ret < 0) {
+			pr_debug("fail to get autopm with %d", ret);
+			break;
+		}
+		ret = usb_control_msg(ccid->udev,
+				usb_rcvctrlpipe(ccid->udev, 0),
+				breq, (USB_DIR_IN | USB_TYPE_CLASS |
+				 USB_RECIP_INTERFACE), 0, intf, buf,
+				data.length, CCID_CONTROL_TIMEOUT);
+		usb_autopm_put_interface(ccid->intf);
+		if (ret == data.length) {
+			ret = copy_to_user((void __user *)data.data, buf,
+					data.length);
+			if (ret)
+				ret = -EFAULT;
+		} else {
+			if (ret > 0)
+				ret = -EPIPE;
+		}
+		kfree(buf);
+		break;
+	case USB_CCID_ABORT:
+		pr_debug("ABORT ioctl called");
+		breq = CCID_ABORT_REQ;
+		ret = copy_from_user(&abort, (void __user *)arg, sizeof(abort));
+		if (ret) {
+			ret = -EFAULT;
+			break;
+		}
+		ret = usb_autopm_get_interface(ccid->intf);
+		if (ret < 0) {
+			pr_debug("fail to get autopm with %d", ret);
+			break;
+		}
+		ret = usb_control_msg(ccid->udev,
+				usb_sndctrlpipe(ccid->udev, 0),
+				breq, (USB_DIR_OUT | USB_TYPE_CLASS |
+				 USB_RECIP_INTERFACE),
+				(abort.seq << 8) | abort.slot, intf, NULL,
+				0, CCID_CONTROL_TIMEOUT);
+		if (ret < 0)
+			pr_err("abort request failed with err %d\n", ret);
+		usb_autopm_put_interface(ccid->intf);
+		break;
+	case USB_CCID_GET_EVENT:
+		pr_debug("GET_EVENT ioctl called");
+		if (!ccid->events_supported) {
+			ret = -ENOENT;
+			break;
+		}
+		ret = ccid_bridge_get_event(ccid);
+		if (ret == 0) {
+			ret = copy_to_user((void __user *)arg, &ccid->cur_event,
+					sizeof(ccid->cur_event));
+			if (ret)
+				ret = -EFAULT;
+		}
+		ccid->cur_event.event = 0;
+		break;
+	default:
+		pr_err("UNKNOWN ioctl called");
+		ret = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&ccid->event_mutex);
+	pr_debug("returning %d", ret);
+	return ret;
+}
+
+static int ccid_bridge_release(struct inode *ip, struct file *fp)
+{
+	struct ccid_bridge *ccid = fp->private_data;
+
+	pr_debug("called");
+
+	usb_kill_urb(ccid->writeurb);
+	usb_kill_urb(ccid->readurb);
+	if (ccid->int_pipe)
+		usb_kill_urb(ccid->inturb);
+
+	ccid->event_result = -EIO;
+	wake_up(&ccid->event_wq);
+
+	mutex_lock(&ccid->open_mutex);
+	ccid->opened = false;
+	mutex_unlock(&ccid->open_mutex);
+	return 0;
+}
+
+static const struct file_operations ccid_bridge_fops = {
+	.owner = THIS_MODULE,
+	.open = ccid_bridge_open,
+	.write = ccid_bridge_write,
+	.read = ccid_bridge_read,
+	.unlocked_ioctl = ccid_bridge_ioctl,
+	.release = ccid_bridge_release,
+};
+
+static int ccid_bridge_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct ccid_bridge *ccid = usb_get_intfdata(intf);
+	int ret = 0;
+
+	pr_debug("called");
+
+	if (!ccid->opened)
+		goto out;
+
+	mutex_lock(&ccid->event_mutex);
+	if (ccid->int_pipe) {
+		usb_kill_urb(ccid->inturb);
+		if (ccid->event_result != -ENOENT) {
+			ret = -EBUSY;
+			goto rel_mutex;
+		}
+	}
+
+	ccid->is_suspended = true;
+rel_mutex:
+	mutex_unlock(&ccid->event_mutex);
+out:
+	pr_debug("returning %d", ret);
+	return ret;
+}
+
+static int ccid_bridge_resume(struct usb_interface *intf)
+{
+	struct ccid_bridge *ccid = usb_get_intfdata(intf);
+	int ret;
+
+	pr_debug("called");
+
+	if (!ccid->opened)
+		goto out;
+
+	mutex_lock(&ccid->event_mutex);
+
+	ccid->is_suspended = false;
+
+	if (device_can_wakeup(&ccid->udev->dev)) {
+		ccid->event_result = 0;
+		ccid->cur_event.event = USB_CCID_RESUME_EVENT;
+		wake_up(&ccid->event_wq);
+	} else if (ccid->int_pipe) {
+		ccid->event_result = -EINPROGRESS;
+		ret = usb_submit_urb(ccid->inturb, GFP_KERNEL);
+		if (ret < 0)
+			pr_debug("fail to submit inturb with %d\n", ret);
+	}
+
+	mutex_unlock(&ccid->event_mutex);
+out:
+	return 0;
+}
+
+static int
+ccid_bridge_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct ccid_bridge *ccid = __ccid_bridge_dev;
+	struct usb_host_interface *intf_desc;
+	struct usb_endpoint_descriptor *ep_desc;
+	struct usb_host_endpoint *ep;
+	__u8 epin_addr = 0, epout_addr = 0, epint_addr = 0;
+	int i, ret;
+
+	intf_desc = intf->cur_altsetting;
+
+	if (intf_desc->desc.bNumEndpoints > 3)
+		return -ENODEV;
+
+	for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) {
+		ep_desc = &intf_desc->endpoint[i].desc;
+
+		if (usb_endpoint_is_bulk_in(ep_desc))
+			epin_addr = ep_desc->bEndpointAddress;
+		else if (usb_endpoint_is_bulk_out(ep_desc))
+			epout_addr = ep_desc->bEndpointAddress;
+		else if (usb_endpoint_is_int_in(ep_desc))
+			epint_addr = ep_desc->bEndpointAddress;
+		else
+			return -ENODEV;
+	}
+
+	if (!epin_addr || !epout_addr)
+		return -ENODEV;
+
+	ccid->udev = usb_get_dev(interface_to_usbdev(intf));
+	ccid->in_pipe = usb_rcvbulkpipe(ccid->udev, epin_addr);
+	ccid->out_pipe = usb_sndbulkpipe(ccid->udev, epout_addr);
+	if (epint_addr)
+		ccid->int_pipe = usb_rcvbulkpipe(ccid->udev, epint_addr);
+
+	ccid->writeurb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!ccid->writeurb) {
+		pr_err("fail to allocate write urb");
+		ret = -ENOMEM;
+		goto put_udev;
+	}
+	ccid->readurb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!ccid->readurb) {
+		pr_err("fail to allocate read urb");
+		ret = -ENOMEM;
+		goto free_writeurb;
+	}
+
+	if (ccid->int_pipe) {
+		pr_debug("interrupt endpoint is present");
+		ep = usb_pipe_endpoint(ccid->udev, ccid->int_pipe);
+		ccid->inturb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!ccid->inturb) {
+			pr_err("fail to allocate int urb");
+			ret = -ENOMEM;
+			goto free_readurb;
+		}
+		ccid->intbuf = kmalloc(usb_endpoint_maxp(&ep->desc),
+				GFP_KERNEL);
+		if (!ccid->intbuf) {
+			pr_err("fail to allocated int buf");
+			ret = -ENOMEM;
+			goto free_inturb;
+		}
+		usb_fill_int_urb(ccid->inturb, ccid->udev,
+				usb_rcvintpipe(ccid->udev, epint_addr),
+				ccid->intbuf, usb_endpoint_maxp(&ep->desc),
+				ccid_bridge_int_cb, ccid,
+				ep->desc.bInterval);
+	}
+
+	if (ccid->int_pipe || device_can_wakeup(&ccid->udev->dev)) {
+		pr_debug("event support is present");
+		ccid->events_supported = true;
+	}
+
+	usb_set_intfdata(intf, ccid);
+
+	mutex_lock(&ccid->open_mutex);
+	ccid->intf = intf;
+	wake_up(&ccid->open_wq);
+	mutex_unlock(&ccid->open_mutex);
+
+	pr_info("success");
+	return 0;
+
+free_inturb:
+	if (ccid->int_pipe)
+		usb_free_urb(ccid->inturb);
+free_readurb:
+	usb_free_urb(ccid->readurb);
+free_writeurb:
+	usb_free_urb(ccid->writeurb);
+put_udev:
+	usb_put_dev(ccid->udev);
+	return ret;
+}
+
+static void ccid_bridge_disconnect(struct usb_interface *intf)
+{
+	struct ccid_bridge *ccid = usb_get_intfdata(intf);
+
+	pr_debug("called");
+
+	usb_kill_urb(ccid->writeurb);
+	usb_kill_urb(ccid->readurb);
+	if (ccid->int_pipe)
+		usb_kill_urb(ccid->inturb);
+
+	ccid->event_result = -ENODEV;
+	wake_up(&ccid->event_wq);
+
+	/*
+	 * This would synchronize any ongoing read/write/ioctl.
+	 * After acquiring the mutex, we can safely set
+	 * intf to NULL.
+	 */
+	mutex_lock(&ccid->open_mutex);
+	mutex_lock(&ccid->write_mutex);
+	mutex_lock(&ccid->read_mutex);
+	mutex_lock(&ccid->event_mutex);
+
+	usb_free_urb(ccid->writeurb);
+	usb_free_urb(ccid->readurb);
+	if (ccid->int_pipe) {
+		usb_free_urb(ccid->inturb);
+		kfree(ccid->intbuf);
+		ccid->int_pipe = 0;
+	}
+
+	ccid->intf = NULL;
+
+	mutex_unlock(&ccid->event_mutex);
+	mutex_unlock(&ccid->read_mutex);
+	mutex_unlock(&ccid->write_mutex);
+	mutex_unlock(&ccid->open_mutex);
+
+}
+
+static const struct usb_device_id ccid_bridge_ids[] = {
+	{ USB_INTERFACE_INFO(USB_CLASS_CSCID, 0, 0) },
+
+	{} /* terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, ccid_bridge_ids);
+
+static struct usb_driver ccid_bridge_driver = {
+	.name = "ccid_bridge",
+	.probe = ccid_bridge_probe,
+	.disconnect = ccid_bridge_disconnect,
+	.suspend = ccid_bridge_suspend,
+	.resume = ccid_bridge_resume,
+	.id_table = ccid_bridge_ids,
+	.supports_autosuspend = 1,
+};
+
+static int __init ccid_bridge_init(void)
+{
+	int ret;
+	struct ccid_bridge *ccid;
+
+	ccid = kzalloc(sizeof(*ccid), GFP_KERNEL);
+	if (!ccid) {
+		pr_err("Fail to allocate ccid");
+		ret = -ENOMEM;
+		goto out;
+	}
+	__ccid_bridge_dev = ccid;
+
+	mutex_init(&ccid->open_mutex);
+	mutex_init(&ccid->write_mutex);
+	mutex_init(&ccid->read_mutex);
+	mutex_init(&ccid->event_mutex);
+
+	init_waitqueue_head(&ccid->open_wq);
+	init_waitqueue_head(&ccid->write_wq);
+	init_waitqueue_head(&ccid->read_wq);
+	init_waitqueue_head(&ccid->event_wq);
+
+	ret = usb_register(&ccid_bridge_driver);
+	if (ret < 0) {
+		pr_err("Fail to register ccid usb driver with %d", ret);
+		goto free_ccid;
+	}
+
+	ret = alloc_chrdev_region(&ccid->chrdev, 0, 1, "ccid_bridge");
+	if (ret < 0) {
+		pr_err("Fail to allocate ccid char dev region with %d", ret);
+		goto unreg_driver;
+	}
+	ccid->class = class_create(THIS_MODULE, "ccid_bridge");
+	if (IS_ERR(ccid->class)) {
+		ret = PTR_ERR(ccid->class);
+		pr_err("Fail to create ccid class with %d", ret);
+		goto unreg_chrdev;
+	}
+	cdev_init(&ccid->cdev, &ccid_bridge_fops);
+	ccid->cdev.owner = THIS_MODULE;
+
+	ret = cdev_add(&ccid->cdev, ccid->chrdev, 1);
+	if (ret < 0) {
+		pr_err("Fail to add ccid cdev with %d", ret);
+		goto destroy_class;
+	}
+	ccid->device = device_create(ccid->class,
+					NULL, ccid->chrdev, NULL,
+					"ccid_bridge");
+	if (IS_ERR(ccid->device)) {
+		ret = PTR_ERR(ccid->device);
+		pr_err("Fail to create ccid device with %d", ret);
+		goto del_cdev;
+	}
+
+	pr_info("success");
+
+	return 0;
+
+del_cdev:
+	cdev_del(&ccid->cdev);
+destroy_class:
+	class_destroy(ccid->class);
+unreg_chrdev:
+	unregister_chrdev_region(ccid->chrdev, 1);
+unreg_driver:
+	usb_deregister(&ccid_bridge_driver);
+free_ccid:
+	mutex_destroy(&ccid->open_mutex);
+	mutex_destroy(&ccid->write_mutex);
+	mutex_destroy(&ccid->read_mutex);
+	mutex_destroy(&ccid->event_mutex);
+	kfree(ccid);
+	__ccid_bridge_dev = NULL;
+out:
+	return ret;
+}
+
+static void __exit ccid_bridge_exit(void)
+{
+	struct ccid_bridge *ccid = __ccid_bridge_dev;
+
+	pr_debug("called");
+	device_destroy(ccid->class, ccid->chrdev);
+	cdev_del(&ccid->cdev);
+	class_destroy(ccid->class);
+	unregister_chrdev_region(ccid->chrdev, 1);
+
+	usb_deregister(&ccid_bridge_driver);
+
+	mutex_destroy(&ccid->open_mutex);
+	mutex_destroy(&ccid->write_mutex);
+	mutex_destroy(&ccid->read_mutex);
+	mutex_destroy(&ccid->event_mutex);
+
+	kfree(ccid);
+	__ccid_bridge_dev = NULL;
+}
+
+module_init(ccid_bridge_init);
+module_exit(ccid_bridge_exit);
+
+MODULE_DESCRIPTION("USB CCID bridge driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild
index 087d163..fe4d6da 100644
--- a/include/linux/usb/Kbuild
+++ b/include/linux/usb/Kbuild
@@ -1,4 +1,5 @@
 header-y += audio.h
+header-y += ccid_bridge.h
 header-y += cdc.h
 header-y += ch9.h
 header-y += ch11.h
diff --git a/include/linux/usb/ccid_bridge.h b/include/linux/usb/ccid_bridge.h
new file mode 100644
index 0000000..1d1b895
--- /dev/null
+++ b/include/linux/usb/ccid_bridge.h
@@ -0,0 +1,64 @@
+#ifndef __UAPI_USB_CCID_BRIDGE_H
+#define __UAPI_USB_CCID_BRIDGE_H
+
+#include <linux/ioctl.h>
+
+/**
+ * struct usb_ccid_data - Used to receive the CCID class descriptor,
+ *        clock rates and data rates supported by the device.
+ * @length: The length of the buffer.
+ * @data: The buffer as it is returned by the device for GET_DESCRIPTOR,
+ *        GET_CLOCK_FREQUENCIES and GET_DATA_RATES requests.
+ */
+struct usb_ccid_data {
+	uint8_t length;
+	void *data;
+};
+
+/**
+ * struct usb_ccid_abort - Used to abort an already sent command.
+ * @seq: The sequence number of the command.
+ * @slot: The slot of the IC, on which the command is sent.
+ */
+struct usb_ccid_abort {
+	uint8_t seq;
+	uint8_t slot;
+};
+
+#define USB_CCID_NOTIFY_SLOT_CHANGE_EVENT 1
+#define USB_CCID_HARDWARE_ERROR_EVENT 2
+#define USB_CCID_RESUME_EVENT 3
+/**
+ * struct usb_ccid_event - Used to receive notify slot change or hardware
+ *        error event.
+ * @notify: If the event is USB_CCID_NOTIFY_SLOT_CHANGE_EVENT, slot_icc_state
+ *        has the information about the current slots state.
+ * @error: If the event is USB_CCID_HARDWARE_ERROR_EVENT, error has
+ *        information about the hardware error condition.
+ */
+struct usb_ccid_event {
+	uint8_t event;
+	union {
+		struct {
+			uint8_t slot_icc_state;
+		} notify;
+
+		struct {
+			uint8_t slot;
+			uint8_t seq;
+			uint8_t error_code;
+		} error;
+	} u;
+};
+
+#define USB_CCID_GET_CLASS_DESC _IOWR('C', 0, struct usb_ccid_data)
+
+#define USB_CCID_GET_CLOCK_FREQUENCIES _IOWR('C', 1, struct usb_ccid_data)
+
+#define USB_CCID_GET_DATA_RATES _IOWR('C', 2, struct usb_ccid_data)
+
+#define USB_CCID_ABORT _IOW('C', 3, struct usb_ccid_abort)
+
+#define USB_CCID_GET_EVENT _IOR('C', 4, struct usb_ccid_event)
+
+#endif /* __UAPI_USB_CCID_BRIDGE_H */