| 
									
										
										
										
											2009-05-14 08:05:58 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This source file is released under GPL v2 license (no other versions). | 
					
						
							|  |  |  |  * See the COPYING file included in the main directory of this source | 
					
						
							|  |  |  |  * distribution for the license terms and conditions. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @File	ctresource.c | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @Brief | 
					
						
							|  |  |  |  * This file contains the implementation of some generic helper functions. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @Author	Liu Chun | 
					
						
							|  |  |  |  * @Date 	May 15 2008 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "ctresource.h"
 | 
					
						
							|  |  |  | #include "cthardware.h"
 | 
					
						
							|  |  |  | #include <linux/err.h>
 | 
					
						
							|  |  |  | #include <linux/slab.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define AUDIO_SLOT_BLOCK_NUM 	256
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Resource allocation based on bit-map management mechanism */ | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | get_resource(u8 *rscs, unsigned int amount, | 
					
						
							|  |  |  | 	     unsigned int multi, unsigned int *ridx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-06-08 14:57:57 +02:00
										 |  |  | 	int i, j, k, n; | 
					
						
							| 
									
										
										
										
											2009-05-14 08:05:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Check whether there are sufficient resources to meet request. */ | 
					
						
							|  |  |  | 	for (i = 0, n = multi; i < amount; i++) { | 
					
						
							|  |  |  | 		j = i / 8; | 
					
						
							|  |  |  | 		k = i % 8; | 
					
						
							|  |  |  | 		if (rscs[j] & ((u8)1 << k)) { | 
					
						
							|  |  |  | 			n = multi; | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (!(--n)) | 
					
						
							|  |  |  | 			break; /* found sufficient contiguous resources */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (i >= amount) { | 
					
						
							|  |  |  | 		/* Can not find sufficient contiguous resources */ | 
					
						
							|  |  |  | 		return -ENOENT; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Mark the contiguous bits in resource bit-map as used */ | 
					
						
							|  |  |  | 	for (n = multi; n > 0; n--) { | 
					
						
							|  |  |  | 		j = i / 8; | 
					
						
							|  |  |  | 		k = i % 8; | 
					
						
							|  |  |  | 		rscs[j] |= ((u8)1 << k); | 
					
						
							|  |  |  | 		i--; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*ridx = i + 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int put_resource(u8 *rscs, unsigned int multi, unsigned int idx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-06-08 14:57:57 +02:00
										 |  |  | 	unsigned int i, j, k, n; | 
					
						
							| 
									
										
										
										
											2009-05-14 08:05:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Mark the contiguous bits in resource bit-map as used */ | 
					
						
							|  |  |  | 	for (n = multi, i = idx; n > 0; n--) { | 
					
						
							|  |  |  | 		j = i / 8; | 
					
						
							|  |  |  | 		k = i % 8; | 
					
						
							|  |  |  | 		rscs[j] &= ~((u8)1 << k); | 
					
						
							|  |  |  | 		i++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-06-08 14:57:57 +02:00
										 |  |  | 	int err; | 
					
						
							| 
									
										
										
										
											2009-05-14 08:05:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (n > mgr->avail) | 
					
						
							|  |  |  | 		return -ENOENT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = get_resource(mgr->rscs, mgr->amount, n, ridx); | 
					
						
							|  |  |  | 	if (!err) | 
					
						
							|  |  |  | 		mgr->avail -= n; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	put_resource(mgr->rscs, n, idx); | 
					
						
							|  |  |  | 	mgr->avail += n; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static unsigned char offset_in_audio_slot_block[NUM_RSCTYP] = { | 
					
						
							|  |  |  | 	/* SRC channel is at Audio Ring slot 1 every 16 slots. */ | 
					
						
							|  |  |  | 	[SRC]		= 0x1, | 
					
						
							|  |  |  | 	[AMIXER]	= 0x4, | 
					
						
							|  |  |  | 	[SUM]		= 0xc, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int rsc_index(const struct rsc *rsc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return rsc->conj; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int audio_ring_slot(const struct rsc *rsc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return (rsc->conj << 4) + offset_in_audio_slot_block[rsc->type]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int rsc_next_conj(struct rsc *rsc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int i; | 
					
						
							|  |  |  | 	for (i = 0; (i < 8) && (!(rsc->msr & (0x1 << i))); ) | 
					
						
							|  |  |  | 		i++; | 
					
						
							|  |  |  | 	rsc->conj += (AUDIO_SLOT_BLOCK_NUM >> i); | 
					
						
							|  |  |  | 	return rsc->conj; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int rsc_master(struct rsc *rsc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return rsc->conj = rsc->idx; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct rsc_ops rsc_generic_ops = { | 
					
						
							|  |  |  | 	.index		= rsc_index, | 
					
						
							|  |  |  | 	.output_slot	= audio_ring_slot, | 
					
						
							|  |  |  | 	.master		= rsc_master, | 
					
						
							|  |  |  | 	.next_conj	= rsc_next_conj, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int err = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rsc->idx = idx; | 
					
						
							|  |  |  | 	rsc->conj = idx; | 
					
						
							|  |  |  | 	rsc->type = type; | 
					
						
							|  |  |  | 	rsc->msr = msr; | 
					
						
							|  |  |  | 	rsc->hw = hw; | 
					
						
							|  |  |  | 	rsc->ops = &rsc_generic_ops; | 
					
						
							| 
									
										
										
										
											2009-07-22 17:12:34 +02:00
										 |  |  | 	if (!hw) { | 
					
						
							| 
									
										
										
										
											2009-05-14 08:05:58 +02:00
										 |  |  | 		rsc->ctrl_blk = NULL; | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (type) { | 
					
						
							|  |  |  | 	case SRC: | 
					
						
							|  |  |  | 		err = ((struct hw *)hw)->src_rsc_get_ctrl_blk(&rsc->ctrl_blk); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case AMIXER: | 
					
						
							|  |  |  | 		err = ((struct hw *)hw)-> | 
					
						
							|  |  |  | 				amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case SRCIMP: | 
					
						
							|  |  |  | 	case SUM: | 
					
						
							|  |  |  | 	case DAIO: | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2009-05-14 15:19:30 +02:00
										 |  |  | 		printk(KERN_ERR | 
					
						
							|  |  |  | 		       "ctxfi: Invalid resource type value %d!\n", type); | 
					
						
							| 
									
										
										
										
											2009-05-14 08:05:58 +02:00
										 |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (err) { | 
					
						
							| 
									
										
										
										
											2009-05-14 15:19:30 +02:00
										 |  |  | 		printk(KERN_ERR | 
					
						
							|  |  |  | 		       "ctxfi: Failed to get resource control block!\n"); | 
					
						
							| 
									
										
										
										
											2009-05-14 08:05:58 +02:00
										 |  |  | 		return err; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int rsc_uninit(struct rsc *rsc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) { | 
					
						
							|  |  |  | 		switch (rsc->type) { | 
					
						
							|  |  |  | 		case SRC: | 
					
						
							|  |  |  | 			((struct hw *)rsc->hw)-> | 
					
						
							|  |  |  | 				src_rsc_put_ctrl_blk(rsc->ctrl_blk); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case AMIXER: | 
					
						
							|  |  |  | 			((struct hw *)rsc->hw)-> | 
					
						
							|  |  |  | 				amixer_rsc_put_ctrl_blk(rsc->ctrl_blk); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case SUM: | 
					
						
							|  |  |  | 		case DAIO: | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2009-05-14 15:19:30 +02:00
										 |  |  | 			printk(KERN_ERR "ctxfi: " | 
					
						
							|  |  |  | 			       "Invalid resource type value %d!\n", rsc->type); | 
					
						
							| 
									
										
										
										
											2009-05-14 08:05:58 +02:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		rsc->hw = rsc->ctrl_blk = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rsc->idx = rsc->conj = 0; | 
					
						
							|  |  |  | 	rsc->type = NUM_RSCTYP; | 
					
						
							|  |  |  | 	rsc->msr = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, | 
					
						
							|  |  |  | 		 unsigned int amount, void *hw_obj) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int err = 0; | 
					
						
							|  |  |  | 	struct hw *hw = hw_obj; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mgr->type = NUM_RSCTYP; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mgr->rscs = kzalloc(((amount + 8 - 1) / 8), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2009-07-22 17:12:34 +02:00
										 |  |  | 	if (!mgr->rscs) | 
					
						
							| 
									
										
										
										
											2009-05-14 08:05:58 +02:00
										 |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (type) { | 
					
						
							|  |  |  | 	case SRC: | 
					
						
							|  |  |  | 		err = hw->src_mgr_get_ctrl_blk(&mgr->ctrl_blk); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case SRCIMP: | 
					
						
							|  |  |  | 		err = hw->srcimp_mgr_get_ctrl_blk(&mgr->ctrl_blk); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case AMIXER: | 
					
						
							|  |  |  | 		err = hw->amixer_mgr_get_ctrl_blk(&mgr->ctrl_blk); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DAIO: | 
					
						
							|  |  |  | 		err = hw->daio_mgr_get_ctrl_blk(hw, &mgr->ctrl_blk); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case SUM: | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2009-05-14 15:19:30 +02:00
										 |  |  | 		printk(KERN_ERR | 
					
						
							|  |  |  | 		       "ctxfi: Invalid resource type value %d!\n", type); | 
					
						
							| 
									
										
										
										
											2009-05-14 08:05:58 +02:00
										 |  |  | 		err = -EINVAL; | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (err) { | 
					
						
							| 
									
										
										
										
											2009-05-14 15:19:30 +02:00
										 |  |  | 		printk(KERN_ERR | 
					
						
							|  |  |  | 		       "ctxfi: Failed to get manager control block!\n"); | 
					
						
							| 
									
										
										
										
											2009-05-14 08:05:58 +02:00
										 |  |  | 		goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mgr->type = type; | 
					
						
							|  |  |  | 	mgr->avail = mgr->amount = amount; | 
					
						
							|  |  |  | 	mgr->hw = hw; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | error: | 
					
						
							|  |  |  | 	kfree(mgr->rscs); | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int rsc_mgr_uninit(struct rsc_mgr *mgr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (NULL != mgr->rscs) { | 
					
						
							|  |  |  | 		kfree(mgr->rscs); | 
					
						
							|  |  |  | 		mgr->rscs = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) { | 
					
						
							|  |  |  | 		switch (mgr->type) { | 
					
						
							|  |  |  | 		case SRC: | 
					
						
							|  |  |  | 			((struct hw *)mgr->hw)-> | 
					
						
							|  |  |  | 				src_mgr_put_ctrl_blk(mgr->ctrl_blk); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case SRCIMP: | 
					
						
							|  |  |  | 			((struct hw *)mgr->hw)-> | 
					
						
							|  |  |  | 				srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case AMIXER: | 
					
						
							|  |  |  | 			((struct hw *)mgr->hw)-> | 
					
						
							|  |  |  | 				amixer_mgr_put_ctrl_blk(mgr->ctrl_blk); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case DAIO: | 
					
						
							|  |  |  | 			((struct hw *)mgr->hw)-> | 
					
						
							|  |  |  | 				daio_mgr_put_ctrl_blk(mgr->ctrl_blk); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case SUM: | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2009-05-14 15:19:30 +02:00
										 |  |  | 			printk(KERN_ERR "ctxfi: " | 
					
						
							|  |  |  | 			       "Invalid resource type value %d!\n", mgr->type); | 
					
						
							| 
									
										
										
										
											2009-05-14 08:05:58 +02:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		mgr->hw = mgr->ctrl_blk = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mgr->type = NUM_RSCTYP; | 
					
						
							|  |  |  | 	mgr->avail = mgr->amount = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } |