mirror of
				https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
				synced 2025-10-31 08:08: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
				
			
		
							
								
								
									
										698
									
								
								drivers/misc/samsung/scsc/scsc_service.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										698
									
								
								drivers/misc/samsung/scsc/scsc_service.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,698 @@ | |||
| /****************************************************************************
 | ||||
|  * | ||||
|  * Copyright (c) 2014 - 2016 Samsung Electronics Co., Ltd. All rights reserved | ||||
|  * | ||||
|  ****************************************************************************/ | ||||
| 
 | ||||
| #include <linux/slab.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/version.h> | ||||
| #include <linux/firmware.h> | ||||
| #include <linux/wakelock.h> | ||||
| #include <scsc/scsc_mx.h> | ||||
| #include <scsc/scsc_logring.h> | ||||
| 
 | ||||
| #include "mxman.h" | ||||
| #include "scsc_mx_impl.h" | ||||
| #include "mifintrbit.h" | ||||
| #include "miframman.h" | ||||
| #include "mifmboxman.h" | ||||
| #include "srvman.h" | ||||
| #include "servman_messages.h" | ||||
| #include "mxmgmt_transport.h" | ||||
| 
 | ||||
| static ulong sm_completion_timeout_ms = 1000; | ||||
| module_param(sm_completion_timeout_ms, ulong, S_IRUGO | S_IWUSR); | ||||
| MODULE_PARM_DESC(sm_completion_timeout_ms, "Timeout Service Manager start/stop (ms) - default 1000. 0 = infinite"); | ||||
| 
 | ||||
| #define SCSC_MX_SERVICE_RECOVERY_TIMEOUT 20000 /* 20 seconds */ | ||||
| 
 | ||||
| #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) | ||||
| #define reinit_completion(completion) INIT_COMPLETION(*(completion)) | ||||
| #endif | ||||
| 
 | ||||
| struct scsc_service { | ||||
| 	struct list_head           list; | ||||
| 	struct scsc_mx             *mx; | ||||
| 	enum scsc_service_id       id; | ||||
| 	struct scsc_service_client *client; | ||||
| 	struct completion          sm_msg_start_completion; | ||||
| 	struct completion          sm_msg_stop_completion; | ||||
| }; | ||||
| 
 | ||||
| void srvman_init(struct srvman *srvman, struct scsc_mx *mx) | ||||
| { | ||||
| 	SCSC_TAG_INFO(MXMAN, "\n"); | ||||
| 	srvman->mx = mx; | ||||
| 	INIT_LIST_HEAD(&srvman->service_list); | ||||
| 	mutex_init(&srvman->service_list_mutex); | ||||
| 	mutex_init(&srvman->api_access_mutex); | ||||
| 
 | ||||
| 	wake_lock_init(&srvman->sm_wake_lock, WAKE_LOCK_SUSPEND, "srvman_wakelock"); | ||||
| } | ||||
| 
 | ||||
| void srvman_deinit(struct srvman *srvman) | ||||
| { | ||||
| 	struct scsc_service *service, *next; | ||||
| 
 | ||||
| 	SCSC_TAG_INFO(MXMAN, "\n"); | ||||
| 	list_for_each_entry_safe(service, next, &srvman->service_list, list) { | ||||
| 		list_del(&service->list); | ||||
| 		kfree(service); | ||||
| 	} | ||||
| 	mutex_destroy(&srvman->api_access_mutex); | ||||
| 	mutex_destroy(&srvman->service_list_mutex); | ||||
| 
 | ||||
| 	wake_lock_destroy(&srvman->sm_wake_lock); | ||||
| } | ||||
| 
 | ||||
| void srvman_set_error(struct srvman *srvman) | ||||
| { | ||||
| 	struct scsc_service *service; | ||||
| 
 | ||||
| 	SCSC_TAG_INFO(MXMAN, "\n"); | ||||
| 	srvman->error = true; | ||||
| 	mutex_lock(&srvman->service_list_mutex); | ||||
| 	list_for_each_entry(service, &srvman->service_list, list) { | ||||
| 		complete(&service->sm_msg_start_completion); | ||||
| 		complete(&service->sm_msg_stop_completion); | ||||
| 	} | ||||
| 	mutex_unlock(&srvman->service_list_mutex); | ||||
| } | ||||
| 
 | ||||
| void srvman_clear_error(struct srvman *srvman) | ||||
| { | ||||
| 	SCSC_TAG_INFO(MXMAN, "\n"); | ||||
| 	srvman->error = false; | ||||
| } | ||||
| 
 | ||||
| #ifndef MAXWELL_SKIP_MANAGER | ||||
| static int wait_for_sm_msg_start_cfm(struct scsc_service *service) | ||||
| { | ||||
| 	int r; | ||||
| 
 | ||||
| 	if (0 == sm_completion_timeout_ms) { | ||||
| 		/* Zero implies infinite wait, for development use only.
 | ||||
| 		 * r = -ERESTARTSYS if interrupted (e.g. Ctrl-C), 0 if completed | ||||
| 		 */ | ||||
| 		r = wait_for_completion_interruptible(&service->sm_msg_start_completion); | ||||
| 		if (r == -ERESTARTSYS) { | ||||
| 			/* Paranoid sink of any pending event skipped by the interrupted wait */ | ||||
| 			r = wait_for_completion_timeout(&service->sm_msg_start_completion, HZ / 2); | ||||
| 			if (r == 0) { | ||||
| 				SCSC_TAG_ERR(MXMAN, "timed out\n"); | ||||
| 				return -ETIMEDOUT; | ||||
| 			} | ||||
| 		} | ||||
| 		return r; | ||||
| 	} | ||||
| 	r = wait_for_completion_timeout(&service->sm_msg_start_completion, msecs_to_jiffies(sm_completion_timeout_ms)); | ||||
| 	if (r == 0) { | ||||
| 		SCSC_TAG_ERR(MXMAN, "timeout\n"); | ||||
| 		return -ETIMEDOUT; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static int wait_for_sm_msg_stop_cfm(struct scsc_service *service) | ||||
| { | ||||
| 	int r; | ||||
| 
 | ||||
| 	if (0 == sm_completion_timeout_ms) { | ||||
| 		/* Zero implies infinite wait, for development use only.
 | ||||
| 		 * r = -ERESTARTSYS if interrupted (e.g. Ctrl-C), 0 if completed | ||||
| 		 */ | ||||
| 		r = wait_for_completion_interruptible(&service->sm_msg_stop_completion); | ||||
| 		if (r == -ERESTARTSYS) { | ||||
| 			/* Paranoid sink of any pending event skipped by the interrupted wait */ | ||||
| 			r = wait_for_completion_timeout(&service->sm_msg_stop_completion, HZ / 2); | ||||
| 			if (r == 0) { | ||||
| 				SCSC_TAG_ERR(MXMAN, "timed out\n"); | ||||
| 				return -ETIMEDOUT; | ||||
| 			} | ||||
| 		} | ||||
| 		return r; | ||||
| 	} | ||||
| 	r = wait_for_completion_timeout(&service->sm_msg_stop_completion, msecs_to_jiffies(sm_completion_timeout_ms)); | ||||
| 	if (r == 0) { | ||||
| 		SCSC_TAG_ERR(MXMAN, "timeout\n"); | ||||
| 		return -ETIMEDOUT; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #ifndef MAXWELL_SKIP_MANAGER | ||||
| static int send_sm_msg_start_blocking(struct scsc_service *service, scsc_mifram_ref ref) | ||||
| { | ||||
| 	struct scsc_mx          *mx = service->mx; | ||||
| 	struct mxmgmt_transport *mxmgmt_transport = scsc_mx_get_mxmgmt_transport(mx); | ||||
| 	int                     r; | ||||
| 	struct sm_msg_packet    message = { .service_id = service->id, | ||||
| 					    .msg = SM_MSG_START_REQ, | ||||
| 					    .optional_data = ref }; | ||||
| 
 | ||||
| 	reinit_completion(&service->sm_msg_start_completion); | ||||
| 
 | ||||
| 	/* Send to FW in MM stream */ | ||||
| 	mxmgmt_transport_send(mxmgmt_transport, MMTRANS_CHAN_ID_SERVICE_MANAGEMENT, &message, sizeof(message)); | ||||
| 	r = wait_for_sm_msg_start_cfm(service); | ||||
| 	if (r) | ||||
| 		SCSC_TAG_ERR(MXMAN, "wait_for_sm_msg_start_cfm() failed: r=%d\n", r); | ||||
| 	return r; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static int send_sm_msg_stop_blocking(struct scsc_service *service) | ||||
| { | ||||
| 	struct scsc_mx          *mx = service->mx; | ||||
| 	struct mxman            *mxman = scsc_mx_get_mxman(mx); | ||||
| 	struct mxmgmt_transport *mxmgmt_transport = scsc_mx_get_mxmgmt_transport(mx); | ||||
| 	int                     r; | ||||
| 	struct sm_msg_packet	message = { .service_id = service->id, | ||||
| 					    .msg = SM_MSG_STOP_REQ, | ||||
| 					    .optional_data = 0 }; | ||||
| 
 | ||||
| 	if (mxman->mxman_state == MXMAN_STATE_FAILED) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	reinit_completion(&service->sm_msg_stop_completion); | ||||
| 
 | ||||
| 	/* Send to FW in MM stream */ | ||||
| 	mxmgmt_transport_send(mxmgmt_transport, MMTRANS_CHAN_ID_SERVICE_MANAGEMENT, &message, sizeof(message)); | ||||
| 	r = wait_for_sm_msg_stop_cfm(service); | ||||
| 	if (r) | ||||
| 		SCSC_TAG_ERR(MXMAN, "wait_for_sm_msg_stop_cfm() for service=%p service->id=%d failed: r=%d\n", service, service->id, r); | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| #ifndef MAXWELL_SKIP_MANAGER | ||||
| /*
 | ||||
|  * Receive handler for messages from the FW along the maxwell management transport | ||||
|  */ | ||||
| static void srv_message_handler(const void *message, void *data) | ||||
| { | ||||
| 	struct srvman       *srvman = (struct srvman *)data; | ||||
| 	struct scsc_service *service; | ||||
| 	const struct sm_msg_packet *msg = message; | ||||
| 	bool                found = false; | ||||
| 
 | ||||
| 	mutex_lock(&srvman->service_list_mutex); | ||||
| 	list_for_each_entry(service, &srvman->service_list, list) { | ||||
| 		if (service->id == msg->service_id) { | ||||
| 			found = true; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	mutex_unlock(&srvman->service_list_mutex); | ||||
| 	if (!found) { | ||||
| 		SCSC_TAG_ERR(MXMAN, "No service for msg->service_id=%d", msg->service_id); | ||||
| 		return; | ||||
| 	} | ||||
| 	/* Forward the message to the applicable service to deal with */ | ||||
| 	switch (msg->msg) { | ||||
| 	case SM_MSG_START_CFM: | ||||
| 		SCSC_TAG_INFO(MXMAN, "Received SM_MSG_START_CFM message service=%p with service_id=%d from the firmware\n", | ||||
| 			      service, msg->service_id); | ||||
| 		complete(&service->sm_msg_start_completion); | ||||
| 		break; | ||||
| 	case SM_MSG_STOP_CFM: | ||||
| 		SCSC_TAG_INFO(MXMAN, "Received SM_MSG_STOP_CFM message for service=%p with service_id=%d from the firmware\n", | ||||
| 			      service, msg->service_id); | ||||
| 		complete(&service->sm_msg_stop_completion); | ||||
| 		break; | ||||
| 	default: | ||||
| 		/* HERE: Unknown message, raise fault */ | ||||
| 		SCSC_TAG_WARNING(MXMAN, "Received unknown message for service=%p with service_id=%d from the firmware: msg->msg=%d\n", | ||||
| 				 service, msg->msg, msg->service_id); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| int scsc_mx_service_start(struct scsc_service *service, scsc_mifram_ref ref) | ||||
| { | ||||
| 	struct scsc_mx *mx = service->mx; | ||||
| 	struct srvman *srvman = scsc_mx_get_srvman(mx); | ||||
| #ifndef MAXWELL_SKIP_MANAGER | ||||
| 	int                 r; | ||||
| #endif | ||||
| 
 | ||||
| 	SCSC_TAG_INFO(MXMAN, "\n"); | ||||
| #ifdef CONFIG_SCSC_CHV_SUPPORT | ||||
| 	if (chv_run) | ||||
| 		return 0; | ||||
| #endif | ||||
| 	mutex_lock(&srvman->api_access_mutex); | ||||
| 	wake_lock(&srvman->sm_wake_lock); | ||||
| 	if (srvman->error) { | ||||
| 		SCSC_TAG_ERR(MXMAN, "error: refused due to previous f/w failure\n"); | ||||
| 		wake_unlock(&srvman->sm_wake_lock); | ||||
| 		mutex_unlock(&srvman->api_access_mutex); | ||||
| 		return -EILSEQ; | ||||
| 	} | ||||
| 
 | ||||
| #ifndef MAXWELL_SKIP_MANAGER | ||||
| 	r = send_sm_msg_start_blocking(service, ref); | ||||
| 	if (r) { | ||||
| 		SCSC_TAG_ERR(MXMAN, "send_sm_msg_start_blocking() failed: r=%d\n", r); | ||||
| 		wake_unlock(&srvman->sm_wake_lock); | ||||
| 		mutex_unlock(&srvman->api_access_mutex); | ||||
| 		return r; | ||||
| 	} | ||||
| #endif | ||||
| 	wake_unlock(&srvman->sm_wake_lock); | ||||
| 	mutex_unlock(&srvman->api_access_mutex); | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_mx_service_start); | ||||
| 
 | ||||
| int scsc_mx_service_stop(struct scsc_service *service) | ||||
| { | ||||
| 	struct scsc_mx *mx = service->mx; | ||||
| 	struct srvman *srvman = scsc_mx_get_srvman(mx); | ||||
| 	int r; | ||||
| 
 | ||||
| 	SCSC_TAG_INFO(MXMAN, "\n"); | ||||
| #ifndef MAXWELL_SKIP_MANAGER | ||||
| #ifdef CONFIG_SCSC_CHV_SUPPORT | ||||
| 	if (chv_run) | ||||
| 		return 0; | ||||
| #endif | ||||
| 	mutex_lock(&srvman->api_access_mutex); | ||||
| 	wake_lock(&srvman->sm_wake_lock); | ||||
| 	if (srvman->error) { | ||||
| 		SCSC_TAG_ERR(MXMAN, "error: refused due to previous f/w failure\n"); | ||||
| 		wake_unlock(&srvman->sm_wake_lock); | ||||
| 		mutex_unlock(&srvman->api_access_mutex); | ||||
| 		return -EILSEQ; | ||||
| 	} | ||||
| 
 | ||||
| 	r = send_sm_msg_stop_blocking(service); | ||||
| 	if (r) { | ||||
| 		SCSC_TAG_ERR(MXMAN, "send_sm_msg_stop_blocking() failed: r=%d\n", r); | ||||
| 		wake_unlock(&srvman->sm_wake_lock); | ||||
| 		mutex_unlock(&srvman->api_access_mutex); | ||||
| 		return -EIO; | ||||
| 	} | ||||
| 	wake_unlock(&srvman->sm_wake_lock); | ||||
| 	mutex_unlock(&srvman->api_access_mutex); | ||||
| #endif /* MAXWELL_SKIP_MANAGER */ | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_mx_service_stop); | ||||
| 
 | ||||
| 
 | ||||
| void srvman_freeze_services(struct srvman *srvman) | ||||
| { | ||||
| 	struct scsc_service *service; | ||||
| 	struct mxman        *mxman = scsc_mx_get_mxman(srvman->mx); | ||||
| 
 | ||||
| 	SCSC_TAG_INFO(MXMAN, "\n"); | ||||
| 	mutex_lock(&srvman->service_list_mutex); | ||||
| 	list_for_each_entry(service, &srvman->service_list, list) { | ||||
| 		service->client->stop_on_failure(service->client); | ||||
| 	} | ||||
| 
 | ||||
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) | ||||
| 	reinit_completion(&mxman->recovery_completion); | ||||
| #else | ||||
| 	INIT_COMPLETION(mxman->recovery_completion); | ||||
| #endif | ||||
| 	mutex_unlock(&srvman->service_list_mutex); | ||||
| 	SCSC_TAG_INFO(MXMAN, "OK\n"); | ||||
| } | ||||
| 
 | ||||
| void srvman_unfreeze_services(struct srvman *srvman, u16 scsc_panic_code) | ||||
| { | ||||
| 	struct scsc_service *service; | ||||
| 
 | ||||
| 	SCSC_TAG_INFO(MXMAN, "\n"); | ||||
| 	mutex_lock(&srvman->service_list_mutex); | ||||
| 	list_for_each_entry(service, &srvman->service_list, list) { | ||||
| 		service->client->failure_reset(service->client, scsc_panic_code); | ||||
| 	} | ||||
| 	mutex_unlock(&srvman->service_list_mutex); | ||||
| 	SCSC_TAG_INFO(MXMAN, "OK\n"); | ||||
| } | ||||
| 
 | ||||
| /** Signal a failure detected by the Client. This will trigger the systemwide
 | ||||
|  * failure handling procedure: _All_ Clients will be called back via | ||||
|  * their stop_on_failure() handler as a side-effect. | ||||
|  */ | ||||
| void scsc_mx_service_service_failed(struct scsc_service *service) | ||||
| { | ||||
| 	struct scsc_mx *mx = service->mx; | ||||
| 	struct srvman  *srvman = scsc_mx_get_srvman(mx); | ||||
| 
 | ||||
| 	SCSC_TAG_INFO(MXMAN, "\n"); | ||||
| 	srvman_set_error(srvman); | ||||
| 	mxman_fail(scsc_mx_get_mxman(mx), SCSC_PANIC_CODE_HOST << 15); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_mx_service_service_failed); | ||||
| 
 | ||||
| 
 | ||||
| void scsc_mx_service_close(struct scsc_service *service) | ||||
| { | ||||
| 	struct mxman   *mxman = scsc_mx_get_mxman(service->mx); | ||||
| 	struct scsc_mx *mx = service->mx; | ||||
| 	struct srvman  *srvman = scsc_mx_get_srvman(mx); | ||||
| #ifndef MAXWELL_SKIP_MANAGER | ||||
| 	bool           empty; | ||||
| #endif | ||||
| 
 | ||||
| 	SCSC_TAG_INFO(MXMAN, "\n"); | ||||
| 	mutex_lock(&srvman->api_access_mutex); | ||||
| 	wake_lock(&srvman->sm_wake_lock); | ||||
| 	if (srvman->error) { | ||||
| 		SCSC_TAG_ERR(MXMAN, "error: refused due to previous f/w failure\n"); | ||||
| 		mutex_unlock(&srvman->api_access_mutex); | ||||
| 		wake_unlock(&srvman->sm_wake_lock); | ||||
| 		return; | ||||
| 	} | ||||
| 	/* remove the service from the list and deallocate the service memory */ | ||||
| 	mutex_lock(&srvman->service_list_mutex); | ||||
| 	list_del(&service->list); | ||||
| #ifndef MAXWELL_SKIP_MANAGER | ||||
| 	empty = list_empty(&srvman->service_list); | ||||
| #endif | ||||
| 	mutex_unlock(&srvman->service_list_mutex); | ||||
| #ifndef MAXWELL_SKIP_MANAGER | ||||
| 	if (empty) | ||||
| 		/* unregister channel handler */ | ||||
| 		mxmgmt_transport_register_channel_handler(scsc_mx_get_mxmgmt_transport(mx), MMTRANS_CHAN_ID_SERVICE_MANAGEMENT, | ||||
| 							  NULL, NULL); | ||||
| #endif | ||||
| 	kfree(service); | ||||
| 	mxman_close(mxman); | ||||
| 	wake_unlock(&srvman->sm_wake_lock); | ||||
| 	mutex_unlock(&srvman->api_access_mutex); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_mx_service_close); | ||||
| 
 | ||||
| /* Consider move to a public scsc_mx interface */ | ||||
| struct scsc_service *scsc_mx_service_open(struct scsc_mx *mx, enum scsc_service_id id, struct scsc_service_client *client, int *status) | ||||
| { | ||||
| 	int                 ret; | ||||
| 	struct scsc_service *service; | ||||
| 	struct srvman       *srvman = scsc_mx_get_srvman(mx); | ||||
| 	struct mxman        *mxman = scsc_mx_get_mxman(mx); | ||||
| #ifndef MAXWELL_SKIP_MANAGER | ||||
| 	bool                empty; | ||||
| #endif | ||||
| 
 | ||||
| 	SCSC_TAG_INFO(MXMAN, "\n"); | ||||
| 
 | ||||
| 	mutex_lock(&srvman->api_access_mutex); | ||||
| 	wake_lock(&srvman->sm_wake_lock); | ||||
| 	if (srvman->error) { | ||||
| 		SCSC_TAG_ERR(MXMAN, "error: refused due to previous f/w failure\n"); | ||||
| 		wake_unlock(&srvman->sm_wake_lock); | ||||
| 		mutex_unlock(&srvman->api_access_mutex); | ||||
| 		*status = -EILSEQ; | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (mxman->mxman_state == MXMAN_STATE_FAILED) { | ||||
| 		int r; | ||||
| 
 | ||||
| 		mutex_unlock(&srvman->api_access_mutex); | ||||
| 		r = wait_for_completion_timeout(&mxman->recovery_completion, | ||||
| 						msecs_to_jiffies(SCSC_MX_SERVICE_RECOVERY_TIMEOUT)); | ||||
| 		if (r == 0) { | ||||
| 			SCSC_TAG_ERR(MXMAN, "Recovery timeout\n"); | ||||
| 			wake_unlock(&srvman->sm_wake_lock); | ||||
| 			*status = -EIO; | ||||
| 			return NULL; | ||||
| 		} | ||||
| 
 | ||||
| 		mutex_lock(&srvman->api_access_mutex); | ||||
| 	} | ||||
| 
 | ||||
| 	service = kmalloc(sizeof(struct scsc_service), GFP_KERNEL); | ||||
| 	if (service) { | ||||
| 		/* MaxwellManager Should allocate Mem and download FW */ | ||||
| 		ret = mxman_open(mxman); | ||||
| 		if (ret) { | ||||
| 			kfree(service); | ||||
| 			wake_unlock(&srvman->sm_wake_lock); | ||||
| 			mutex_unlock(&srvman->api_access_mutex); | ||||
| 			*status = ret; | ||||
| 			return NULL; | ||||
| 		} | ||||
| 		/* Initialise service struct here */ | ||||
| 		service->mx = mx; | ||||
| 		service->id = id; | ||||
| 		service->client = client; | ||||
| 		init_completion(&service->sm_msg_start_completion); | ||||
| 		init_completion(&service->sm_msg_stop_completion); | ||||
| 		mutex_lock(&srvman->service_list_mutex); | ||||
| #ifndef MAXWELL_SKIP_MANAGER | ||||
| 		empty = list_empty(&srvman->service_list); | ||||
| #endif | ||||
| 		mutex_unlock(&srvman->service_list_mutex); | ||||
| #ifndef MAXWELL_SKIP_MANAGER | ||||
| 		if (empty) | ||||
| 			mxmgmt_transport_register_channel_handler(scsc_mx_get_mxmgmt_transport(mx), MMTRANS_CHAN_ID_SERVICE_MANAGEMENT, | ||||
| 								  &srv_message_handler, srvman); | ||||
| #endif | ||||
| 		mutex_lock(&srvman->service_list_mutex); | ||||
| 		list_add_tail(&service->list, &srvman->service_list); | ||||
| 		mutex_unlock(&srvman->service_list_mutex); | ||||
| 	} else | ||||
| 		*status = -ENOMEM; | ||||
| 
 | ||||
| 	wake_unlock(&srvman->sm_wake_lock); | ||||
| 	mutex_unlock(&srvman->api_access_mutex); | ||||
| 
 | ||||
| 	return service; | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_mx_service_open); | ||||
| 
 | ||||
| 
 | ||||
| /** Allocate a contiguous block of SDRAM accessible to Client Driver */ | ||||
| int scsc_mx_service_mifram_alloc(struct scsc_service *service, size_t nbytes, scsc_mifram_ref *ref, u32 align) | ||||
| { | ||||
| 	struct scsc_mx      *mx = service->mx; | ||||
| 	void                *mem; | ||||
| 	int                 ret; | ||||
| 
 | ||||
| 	mem = miframman_alloc(scsc_mx_get_ramman(mx), nbytes, align); | ||||
| 
 | ||||
| 	if (!mem) { | ||||
| 		SCSC_TAG_ERR(MXMAN, "miframman_alloc() failed\n"); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	SCSC_TAG_DEBUG(MXMAN, "Allocated mem %p\n", mem); | ||||
| 
 | ||||
| 	/* Transform native pointer and get mifram_ref type */ | ||||
| 	ret = scsc_mx_service_mif_ptr_to_addr(service, mem, ref); | ||||
| 	if (ret) { | ||||
| 		SCSC_TAG_ERR(MXMAN, "scsc_mx_service_mif_ptr_to_addr() failed: ret=%d", ret); | ||||
| 		miframman_free(scsc_mx_get_ramman(mx), mem); | ||||
| 	} else | ||||
| 		SCSC_TAG_DEBUG(MXMAN, "mem %p ref %d\n", mem, *ref); | ||||
| 	return ret; | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_mx_service_mifram_alloc); | ||||
| 
 | ||||
| /** Free a contiguous block of SDRAM */ | ||||
| void scsc_mx_service_mifram_free(struct scsc_service *service, scsc_mifram_ref ref) | ||||
| { | ||||
| 	struct scsc_mx *mx = service->mx; | ||||
| 	void           *mem; | ||||
| 
 | ||||
| 	mem = scsc_mx_service_mif_addr_to_ptr(service, ref); | ||||
| 
 | ||||
| 	SCSC_TAG_DEBUG(MXMAN, "**** Freeing %p\n", mem); | ||||
| 
 | ||||
| 	miframman_free(scsc_mx_get_ramman(mx), mem); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_mx_service_mifram_free); | ||||
| 
 | ||||
| /* MIF ALLOCATIONS */ | ||||
| bool scsc_mx_service_alloc_mboxes(struct scsc_service *service, int n, int *first_mbox_index) | ||||
| { | ||||
| 	struct scsc_mx *mx = service->mx; | ||||
| 
 | ||||
| 	return mifmboxman_alloc_mboxes(scsc_mx_get_mboxman(mx), n, first_mbox_index); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_mx_service_alloc_mboxes); | ||||
| 
 | ||||
| void scsc_service_free_mboxes(struct scsc_service *service, int n, int first_mbox_index) | ||||
| { | ||||
| 	struct scsc_mx *mx = service->mx; | ||||
| 
 | ||||
| 	return mifmboxman_free_mboxes(scsc_mx_get_mboxman(mx), first_mbox_index, n); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_service_free_mboxes); | ||||
| 
 | ||||
| u32 *scsc_mx_service_get_mbox_ptr(struct scsc_service *service, int mbox_index) | ||||
| { | ||||
| 	struct scsc_mx      *mx = service->mx; | ||||
| 	struct scsc_mif_abs *mif_abs; | ||||
| 
 | ||||
| 	mif_abs = scsc_mx_get_mif_abs(mx); | ||||
| 
 | ||||
| 	return mifmboxman_get_mbox_ptr(scsc_mx_get_mboxman(mx), mif_abs, mbox_index); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_mx_service_get_mbox_ptr); | ||||
| 
 | ||||
| int scsc_service_mifintrbit_bit_mask_status_get(struct scsc_service *service) | ||||
| { | ||||
| 	struct scsc_mx      *mx = service->mx; | ||||
| 	struct scsc_mif_abs *mif_abs; | ||||
| 
 | ||||
| 	mif_abs = scsc_mx_get_mif_abs(mx); | ||||
| 
 | ||||
| 	return mif_abs->irq_bit_mask_status_get(mif_abs); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_service_mifintrbit_bit_mask_status_get); | ||||
| 
 | ||||
| int scsc_service_mifintrbit_get(struct scsc_service *service) | ||||
| { | ||||
| 	struct scsc_mx      *mx = service->mx; | ||||
| 	struct scsc_mif_abs *mif_abs; | ||||
| 
 | ||||
| 	mif_abs = scsc_mx_get_mif_abs(mx); | ||||
| 
 | ||||
| 	return mif_abs->irq_get(mif_abs); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_service_mifintrbit_get); | ||||
| 
 | ||||
| void scsc_service_mifintrbit_bit_set(struct scsc_service *service, int which_bit, enum scsc_mifintr_target dir) | ||||
| { | ||||
| 	struct scsc_mx      *mx = service->mx; | ||||
| 	struct scsc_mif_abs *mif_abs; | ||||
| 
 | ||||
| 	mif_abs = scsc_mx_get_mif_abs(mx); | ||||
| 
 | ||||
| 	return mif_abs->irq_bit_set(mif_abs, which_bit, dir); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_service_mifintrbit_bit_set); | ||||
| 
 | ||||
| void scsc_service_mifintrbit_bit_clear(struct scsc_service *service, int which_bit) | ||||
| { | ||||
| 	struct scsc_mx      *mx = service->mx; | ||||
| 	struct scsc_mif_abs *mif_abs; | ||||
| 
 | ||||
| 	mif_abs = scsc_mx_get_mif_abs(mx); | ||||
| 
 | ||||
| 	return mif_abs->irq_bit_clear(mif_abs, which_bit); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_service_mifintrbit_bit_clear); | ||||
| 
 | ||||
| void scsc_service_mifintrbit_bit_mask(struct scsc_service *service, int which_bit) | ||||
| { | ||||
| 	struct scsc_mx      *mx = service->mx; | ||||
| 	struct scsc_mif_abs *mif_abs; | ||||
| 
 | ||||
| 	mif_abs = scsc_mx_get_mif_abs(mx); | ||||
| 
 | ||||
| 	return mif_abs->irq_bit_mask(mif_abs, which_bit); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_service_mifintrbit_bit_mask); | ||||
| 
 | ||||
| void scsc_service_mifintrbit_bit_unmask(struct scsc_service *service, int which_bit) | ||||
| { | ||||
| 	struct scsc_mx      *mx = service->mx; | ||||
| 	struct scsc_mif_abs *mif_abs; | ||||
| 
 | ||||
| 	mif_abs = scsc_mx_get_mif_abs(mx); | ||||
| 
 | ||||
| 	return mif_abs->irq_bit_unmask(mif_abs, which_bit); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_service_mifintrbit_bit_unmask); | ||||
| 
 | ||||
| int scsc_service_mifintrbit_alloc_fromhost(struct scsc_service *service, enum scsc_mifintr_target dir) | ||||
| { | ||||
| 	struct scsc_mx *mx = service->mx; | ||||
| 
 | ||||
| 	return mifintrbit_alloc_fromhost(scsc_mx_get_intrbit(mx), dir); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_service_mifintrbit_alloc_fromhost); | ||||
| 
 | ||||
| int scsc_service_mifintrbit_free_fromhost(struct scsc_service *service, int which_bit, enum scsc_mifintr_target dir) | ||||
| { | ||||
| 	struct scsc_mx *mx = service->mx; | ||||
| 
 | ||||
| 	return mifintrbit_free_fromhost(scsc_mx_get_intrbit(mx), which_bit, dir); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_service_mifintrbit_free_fromhost); | ||||
| 
 | ||||
| int scsc_service_mifintrbit_register_tohost(struct scsc_service *service, void (*handler)(int irq, void *data), void *data) | ||||
| { | ||||
| 	struct scsc_mx *mx = service->mx; | ||||
| 
 | ||||
| 	SCSC_TAG_DEBUG(MXMAN, "Registering %pS\n", handler); | ||||
| 
 | ||||
| 	return mifintrbit_alloc_tohost(scsc_mx_get_intrbit(mx), handler, data); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_service_mifintrbit_register_tohost); | ||||
| 
 | ||||
| int scsc_service_mifintrbit_unregister_tohost(struct scsc_service *service, int which_bit) | ||||
| { | ||||
| 	struct scsc_mx *mx = service->mx; | ||||
| 
 | ||||
| 	SCSC_TAG_DEBUG(MXMAN, "Deregistering int for bit %d\n", which_bit); | ||||
| 	return mifintrbit_free_tohost(scsc_mx_get_intrbit(mx), which_bit); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_service_mifintrbit_unregister_tohost); | ||||
| 
 | ||||
| void *scsc_mx_service_mif_addr_to_ptr(struct scsc_service *service, scsc_mifram_ref ref) | ||||
| { | ||||
| 	struct scsc_mx      *mx = service->mx; | ||||
| 
 | ||||
| 	struct scsc_mif_abs *mif_abs; | ||||
| 
 | ||||
| 	mif_abs = scsc_mx_get_mif_abs(mx); | ||||
| 
 | ||||
| 	return mif_abs->get_mifram_ptr(mif_abs, ref); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_mx_service_mif_addr_to_ptr); | ||||
| 
 | ||||
| int scsc_mx_service_mif_ptr_to_addr(struct scsc_service *service, void *mem_ptr, scsc_mifram_ref *ref) | ||||
| { | ||||
| 	struct scsc_mx      *mx = service->mx; | ||||
| 	struct scsc_mif_abs *mif_abs; | ||||
| 
 | ||||
| 	mif_abs = scsc_mx_get_mif_abs(mx); | ||||
| 
 | ||||
| 	/* Transform native pointer and get mifram_ref type */ | ||||
| 	if (mif_abs->get_mifram_ref(mif_abs, mem_ptr, ref)) { | ||||
| 		SCSC_TAG_ERR(MXMAN, "ooops somethig went wrong"); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_mx_service_mif_ptr_to_addr); | ||||
| 
 | ||||
| int scsc_mx_service_mif_dump_registers(struct scsc_service *service) | ||||
| { | ||||
| 	struct scsc_mx      *mx = service->mx; | ||||
| 	struct scsc_mif_abs *mif_abs; | ||||
| 
 | ||||
| 	mif_abs = scsc_mx_get_mif_abs(mx); | ||||
| 
 | ||||
| 	/* Dump registers */ | ||||
| 	mif_abs->mif_dump_registers(mif_abs); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_mx_service_mif_dump_registers); | ||||
| 
 | ||||
| struct device *scsc_service_get_device(struct scsc_service *service) | ||||
| { | ||||
| 	return scsc_mx_get_device(service->mx); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_service_get_device); | ||||
| 
 | ||||
| int scsc_service_force_panic(struct scsc_service *service) | ||||
| { | ||||
| 	struct mxman   *mxman = scsc_mx_get_mxman(service->mx); | ||||
| 
 | ||||
| 	return mxman_force_panic(mxman); | ||||
| } | ||||
| EXPORT_SYMBOL(scsc_service_force_panic); | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 awab228
						awab228