|  | /** | 
|  | * 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) | 
|  | { | 
|  | int i, j, k, n; | 
|  |  | 
|  | /* 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) | 
|  | { | 
|  | unsigned int i, j, k, n; | 
|  |  | 
|  | /* 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) | 
|  | { | 
|  | int err; | 
|  |  | 
|  | 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; | 
|  | if (!hw) { | 
|  | 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: | 
|  | printk(KERN_ERR | 
|  | "ctxfi: Invalid resource type value %d!\n", type); | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | if (err) { | 
|  | printk(KERN_ERR | 
|  | "ctxfi: Failed to get resource control block!\n"); | 
|  | 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: | 
|  | printk(KERN_ERR "ctxfi: " | 
|  | "Invalid resource type value %d!\n", rsc->type); | 
|  | 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); | 
|  | if (!mgr->rscs) | 
|  | 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: | 
|  | printk(KERN_ERR | 
|  | "ctxfi: Invalid resource type value %d!\n", type); | 
|  | err = -EINVAL; | 
|  | goto error; | 
|  | } | 
|  |  | 
|  | if (err) { | 
|  | printk(KERN_ERR | 
|  | "ctxfi: Failed to get manager control block!\n"); | 
|  | 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: | 
|  | printk(KERN_ERR "ctxfi: " | 
|  | "Invalid resource type value %d!\n", mgr->type); | 
|  | break; | 
|  | } | 
|  |  | 
|  | mgr->hw = mgr->ctrl_blk = NULL; | 
|  | } | 
|  |  | 
|  | mgr->type = NUM_RSCTYP; | 
|  | mgr->avail = mgr->amount = 0; | 
|  |  | 
|  | return 0; | 
|  | } |