mirror of
				https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
				synced 2025-10-30 23:58:51 +01:00 
			
		
		
		
	Fixed MTP to work with TWRP
This commit is contained in:
		
						commit
						f6dfaef42e
					
				
					 50820 changed files with 20846062 additions and 0 deletions
				
			
		
							
								
								
									
										244
									
								
								drivers/misc/samsung/scsc/mifintrbit.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								drivers/misc/samsung/scsc/mifintrbit.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,244 @@ | |||
| /****************************************************************************
 | ||||
|  * | ||||
|  * Copyright (c) 2014 - 2016 Samsung Electronics Co., Ltd. All rights reserved | ||||
|  * | ||||
|  ****************************************************************************/ | ||||
| 
 | ||||
| /* Uses */ | ||||
| #include <linux/bitmap.h> | ||||
| #include <linux/errno.h> | ||||
| #include <linux/spinlock.h> | ||||
| #include <scsc/scsc_logring.h> | ||||
| #include "scsc_mif_abs.h" | ||||
| 
 | ||||
| /* Implements */ | ||||
| #include "mifintrbit.h" | ||||
| 
 | ||||
| /* default handler just logs a warning and clears the bit */ | ||||
| static void mifintrbit_default_handler(int irq, void *data) | ||||
| { | ||||
| 	struct mifintrbit *intr = (struct mifintrbit *)data; | ||||
| 	unsigned long     flags; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&intr->spinlock, flags); | ||||
| 	intr->mif->irq_bit_clear(intr->mif, irq); | ||||
| 	spin_unlock_irqrestore(&intr->spinlock, flags); | ||||
| } | ||||
| 
 | ||||
| static void print_bitmaps(struct mifintrbit *intr) | ||||
| { | ||||
| 	unsigned long dst1, dst2, dst3; | ||||
| 
 | ||||
| 	bitmap_copy_le(&dst1, intr->bitmap_tohost, MIFINTRBIT_NUM_INT); | ||||
| 	bitmap_copy_le(&dst2, intr->bitmap_fromhost_r4, MIFINTRBIT_NUM_INT); | ||||
| 	bitmap_copy_le(&dst3, intr->bitmap_fromhost_m4, MIFINTRBIT_NUM_INT); | ||||
| } | ||||
| 
 | ||||
| static void mifiintrman_isr(int irq, void *data) | ||||
| { | ||||
| 	struct mifintrbit *intr = (struct mifintrbit *)data; | ||||
| 	unsigned long     flags; | ||||
| 	int               irq_reg = 0; | ||||
| 	int               bit; | ||||
| 
 | ||||
| 	/* Avoid unused parameter error */ | ||||
| 	(void)irq; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&intr->spinlock, flags); | ||||
| 	irq_reg = intr->mif->irq_get(intr->mif); | ||||
| 
 | ||||
| 	print_bitmaps(intr); | ||||
| 	for_each_set_bit(bit, (unsigned long int *)&irq_reg, MIFINTRBIT_NUM_INT) { | ||||
| 		if (intr->mifintrbit_irq_handler[bit] != mifintrbit_default_handler) | ||||
| 			intr->mifintrbit_irq_handler[bit](bit, intr->irq_data[bit]); | ||||
| 	} | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&intr->spinlock, flags); | ||||
| } | ||||
| 
 | ||||
| /* Public functions */ | ||||
| int mifintrbit_alloc_tohost(struct mifintrbit *intr, mifintrbit_handler handler, void *data) | ||||
| { | ||||
| 	struct scsc_mif_abs *mif; | ||||
| 	unsigned long flags; | ||||
| 	int           which_bit = 0; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&intr->spinlock, flags); | ||||
| 
 | ||||
| 	/* Search for free slots */ | ||||
| 	which_bit = find_first_zero_bit(intr->bitmap_tohost, MIFINTRBIT_NUM_INT); | ||||
| 
 | ||||
| 	if (which_bit >= MIFINTRBIT_NUM_INT) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	if (intr->mifintrbit_irq_handler[which_bit] != mifintrbit_default_handler) { | ||||
| 		spin_unlock_irqrestore(&intr->spinlock, flags); | ||||
| 		goto error; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Get abs implementation */ | ||||
| 	mif = intr->mif; | ||||
| 
 | ||||
| 	/* Mask to prevent spurious incoming interrupts */ | ||||
| 	mif->irq_bit_mask(mif, which_bit); | ||||
| 	/* Clear the interrupt */ | ||||
| 	mif->irq_bit_clear(mif, which_bit); | ||||
| 
 | ||||
| 	/* Register the handler */ | ||||
| 	intr->mifintrbit_irq_handler[which_bit] = handler; | ||||
| 	intr->irq_data[which_bit] = data; | ||||
| 
 | ||||
| 	/* Once registration is set, and IRQ has been cleared, unmask the interrupt */ | ||||
| 	mif->irq_bit_unmask(mif, which_bit); | ||||
| 
 | ||||
| 	/* Update bit mask */ | ||||
| 	set_bit(which_bit, intr->bitmap_tohost); | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&intr->spinlock, flags); | ||||
| 
 | ||||
| 	return which_bit; | ||||
| 
 | ||||
| error: | ||||
| 	spin_unlock_irqrestore(&intr->spinlock, flags); | ||||
| 	SCSC_TAG_ERR(MIF, "Error registering irq\n"); | ||||
| 	return -EIO; | ||||
| } | ||||
| 
 | ||||
| int mifintrbit_free_tohost(struct mifintrbit *intr, int which_bit) | ||||
| { | ||||
| 	struct scsc_mif_abs *mif; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	if (which_bit >= MIFINTRBIT_NUM_INT) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&intr->spinlock, flags); | ||||
| 	/* Get abs implementation */ | ||||
| 	mif = intr->mif; | ||||
| 
 | ||||
| 	/* Mask to prevent spurious incoming interrupts */ | ||||
| 	mif->irq_bit_mask(mif, which_bit); | ||||
| 	/* Set the handler with default */ | ||||
| 	intr->mifintrbit_irq_handler[which_bit] = mifintrbit_default_handler; | ||||
| 	intr->irq_data[which_bit] = NULL; | ||||
| 	/* Clear the interrupt for hygiene */ | ||||
| 	mif->irq_bit_clear(mif, which_bit); | ||||
| 	/* Update bit mask */ | ||||
| 	clear_bit(which_bit, intr->bitmap_tohost); | ||||
| 	spin_unlock_irqrestore(&intr->spinlock, flags); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| error: | ||||
| 	SCSC_TAG_ERR(MIF, "Error unregistering irq\n"); | ||||
| 	return -EIO; | ||||
| } | ||||
| 
 | ||||
| int mifintrbit_alloc_fromhost(struct mifintrbit *intr, enum scsc_mif_abs_target target) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	int           which_bit = 0; | ||||
| 	unsigned long *p; | ||||
| 
 | ||||
| 
 | ||||
| 	spin_lock_irqsave(&intr->spinlock, flags); | ||||
| 
 | ||||
| 	if (target == SCSC_MIF_ABS_TARGET_R4) | ||||
| 		p = intr->bitmap_fromhost_r4; | ||||
| 	else if (target == SCSC_MIF_ABS_TARGET_M4) | ||||
| 		p = intr->bitmap_fromhost_m4; | ||||
| 	else | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* Search for free slots */ | ||||
| 	which_bit = find_first_zero_bit(p, MIFINTRBIT_NUM_INT); | ||||
| 
 | ||||
| 	if (which_bit == MIFINTRBIT_NUM_INT) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* Update bit mask */ | ||||
| 	set_bit(which_bit, p); | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&intr->spinlock, flags); | ||||
| 
 | ||||
| 	return which_bit; | ||||
| error: | ||||
| 	spin_unlock_irqrestore(&intr->spinlock, flags); | ||||
| 	SCSC_TAG_ERR(MIF, "Error allocating bit %d on %s\n", | ||||
| 		     which_bit, target ? "M4" : "R4"); | ||||
| 	return -EIO; | ||||
| } | ||||
| 
 | ||||
| int mifintrbit_free_fromhost(struct mifintrbit *intr, int which_bit, enum scsc_mif_abs_target target) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	unsigned long *p; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&intr->spinlock, flags); | ||||
| 
 | ||||
| 	if (which_bit >= MIFINTRBIT_NUM_INT) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	if (target == SCSC_MIF_ABS_TARGET_R4) | ||||
| 		p = intr->bitmap_fromhost_r4; | ||||
| 	else if (target == SCSC_MIF_ABS_TARGET_M4) | ||||
| 		p = intr->bitmap_fromhost_m4; | ||||
| 	else | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* Clear bit mask */ | ||||
| 	clear_bit(which_bit, p); | ||||
| 	spin_unlock_irqrestore(&intr->spinlock, flags); | ||||
| 
 | ||||
| 	return 0; | ||||
| error: | ||||
| 	spin_unlock_irqrestore(&intr->spinlock, flags); | ||||
| 	SCSC_TAG_ERR(MIF, "Error freeing bit %d on %s\n", | ||||
| 		     which_bit, target ? "M4" : "R4"); | ||||
| 	return -EIO; | ||||
| } | ||||
| 
 | ||||
| /* core API */ | ||||
| void mifintrbit_deinit(struct mifintrbit *intr) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	int i; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&intr->spinlock, flags); | ||||
| 	/* Set all handlers to default before unregistering the handler */ | ||||
| 	for (i = 0; i < MIFINTRBIT_NUM_INT; i++) | ||||
| 		intr->mifintrbit_irq_handler[i] = mifintrbit_default_handler; | ||||
| 	intr->mif->irq_unreg_handler(intr->mif); | ||||
| 	spin_unlock_irqrestore(&intr->spinlock, flags); | ||||
| } | ||||
| 
 | ||||
| void mifintrbit_init(struct mifintrbit *intr, struct scsc_mif_abs *mif) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	spin_lock_init(&intr->spinlock); | ||||
| 	/* Set all handlersd to default before hooking the hardware interrupt */ | ||||
| 	for (i = 0; i < MIFINTRBIT_NUM_INT; i++) | ||||
| 		intr->mifintrbit_irq_handler[i] = mifintrbit_default_handler; | ||||
| 
 | ||||
| 	/* reset bitmaps */ | ||||
| 	bitmap_zero(intr->bitmap_tohost, MIFINTRBIT_NUM_INT); | ||||
| 	bitmap_zero(intr->bitmap_fromhost_r4, MIFINTRBIT_NUM_INT); | ||||
| 	bitmap_zero(intr->bitmap_fromhost_m4, MIFINTRBIT_NUM_INT); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * Pre-allocate/reserve MIF interrupt bits 0 in both | ||||
| 	 * .._fromhost_r4 and .._fromhost_m4 interrupt bits. | ||||
| 	 * | ||||
| 	 * These bits are used for purpose of forcing Panics from | ||||
| 	 * either MX manager or GDB monitor channels. | ||||
| 	 */ | ||||
| 	set_bit(MIFINTRBIT_RESERVED_PANIC_R4, intr->bitmap_fromhost_r4); | ||||
| 	set_bit(MIFINTRBIT_RESERVED_PANIC_M4, intr->bitmap_fromhost_m4); | ||||
| 
 | ||||
| 	/* register isr with mif abstraction */ | ||||
| 	mif->irq_reg_handler(mif, mifiintrman_isr, (void *)intr); | ||||
| 
 | ||||
| 	/* cache mif */ | ||||
| 	intr->mif = mif; | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 awab228
						awab228