| /* |
| * dev.c |
| * |
| * DSP-BIOS Bridge driver support functions for TI OMAP processors. |
| * |
| * Implementation of Bridge Bridge driver device operations. |
| * |
| * Copyright (C) 2005-2006 Texas Instruments, Inc. |
| * |
| * This package is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| * |
| * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
| * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
| * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
| */ |
| #include <linux/types.h> |
| |
| /* ----------------------------------- Host OS */ |
| #include <dspbridge/host_os.h> |
| |
| /* ----------------------------------- DSP/BIOS Bridge */ |
| #include <dspbridge/dbdefs.h> |
| |
| /* ----------------------------------- Trace & Debug */ |
| #include <dspbridge/dbc.h> |
| |
| /* ----------------------------------- OS Adaptation Layer */ |
| #include <dspbridge/cfg.h> |
| #include <dspbridge/ldr.h> |
| #include <dspbridge/list.h> |
| |
| /* ----------------------------------- Platform Manager */ |
| #include <dspbridge/cod.h> |
| #include <dspbridge/drv.h> |
| #include <dspbridge/proc.h> |
| #include <dspbridge/dmm.h> |
| |
| /* ----------------------------------- Resource Manager */ |
| #include <dspbridge/mgr.h> |
| #include <dspbridge/node.h> |
| |
| /* ----------------------------------- Others */ |
| #include <dspbridge/dspapi.h> /* DSP API version info. */ |
| |
| #include <dspbridge/chnl.h> |
| #include <dspbridge/io.h> |
| #include <dspbridge/msg.h> |
| #include <dspbridge/cmm.h> |
| #include <dspbridge/dspdeh.h> |
| |
| /* ----------------------------------- This */ |
| #include <dspbridge/dev.h> |
| |
| /* ----------------------------------- Defines, Data Structures, Typedefs */ |
| |
| #define MAKEVERSION(major, minor) (major * 10 + minor) |
| #define BRD_API_VERSION MAKEVERSION(BRD_API_MAJOR_VERSION, \ |
| BRD_API_MINOR_VERSION) |
| |
| /* The Bridge device object: */ |
| struct dev_object { |
| /* LST requires "link" to be first field! */ |
| struct list_head link; /* Link to next dev_object. */ |
| u8 dev_type; /* Device Type */ |
| struct cfg_devnode *dev_node_obj; /* Platform specific dev id */ |
| /* Bridge Context Handle */ |
| struct bridge_dev_context *hbridge_context; |
| /* Function interface to Bridge driver. */ |
| struct bridge_drv_interface bridge_interface; |
| struct brd_object *lock_owner; /* Client with exclusive access. */ |
| struct cod_manager *cod_mgr; /* Code manager handle. */ |
| struct chnl_mgr *hchnl_mgr; /* Channel manager. */ |
| struct deh_mgr *hdeh_mgr; /* DEH manager. */ |
| struct msg_mgr *hmsg_mgr; /* Message manager. */ |
| struct io_mgr *hio_mgr; /* IO manager (CHNL, msg_ctrl) */ |
| struct cmm_object *hcmm_mgr; /* SM memory manager. */ |
| struct dmm_object *dmm_mgr; /* Dynamic memory manager. */ |
| struct ldr_module *module_obj; /* Bridge Module handle. */ |
| u32 word_size; /* DSP word size: quick access. */ |
| struct drv_object *hdrv_obj; /* Driver Object */ |
| struct lst_list *proc_list; /* List of Proceeosr attached to |
| * this device */ |
| struct node_mgr *hnode_mgr; |
| }; |
| |
| /* ----------------------------------- Globals */ |
| static u32 refs; /* Module reference count */ |
| |
| /* ----------------------------------- Function Prototypes */ |
| static int fxn_not_implemented(int arg, ...); |
| static int init_cod_mgr(struct dev_object *dev_obj); |
| static void store_interface_fxns(struct bridge_drv_interface *drv_fxns, |
| OUT struct bridge_drv_interface *intf_fxns); |
| /* |
| * ======== dev_brd_write_fxn ======== |
| * Purpose: |
| * Exported function to be used as the COD write function. This function |
| * is passed a handle to a DEV_hObject, then calls the |
| * device's bridge_brd_write() function. |
| */ |
| u32 dev_brd_write_fxn(void *arb, u32 dsp_add, void *host_buf, |
| u32 ul_num_bytes, u32 mem_space) |
| { |
| struct dev_object *dev_obj = (struct dev_object *)arb; |
| u32 ul_written = 0; |
| int status; |
| |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(host_buf != NULL); /* Required of BrdWrite(). */ |
| if (dev_obj) { |
| /* Require of BrdWrite() */ |
| DBC_ASSERT(dev_obj->hbridge_context != NULL); |
| status = (*dev_obj->bridge_interface.pfn_brd_write) ( |
| dev_obj->hbridge_context, host_buf, |
| dsp_add, ul_num_bytes, mem_space); |
| /* Special case of getting the address only */ |
| if (ul_num_bytes == 0) |
| ul_num_bytes = 1; |
| if (DSP_SUCCEEDED(status)) |
| ul_written = ul_num_bytes; |
| |
| } |
| return ul_written; |
| } |
| |
| /* |
| * ======== dev_create_device ======== |
| * Purpose: |
| * Called by the operating system to load the PM Bridge Driver for a |
| * PM board (device). |
| */ |
| int dev_create_device(OUT struct dev_object **device_obj, |
| IN CONST char *driver_file_name, |
| struct cfg_devnode *dev_node_obj) |
| { |
| struct cfg_hostres *host_res; |
| struct ldr_module *module_obj = NULL; |
| struct bridge_drv_interface *drv_fxns = NULL; |
| struct dev_object *dev_obj = NULL; |
| struct chnl_mgrattrs mgr_attrs; |
| struct io_attrs io_mgr_attrs; |
| u32 num_windows; |
| struct drv_object *hdrv_obj = NULL; |
| int status = 0; |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(device_obj != NULL); |
| DBC_REQUIRE(driver_file_name != NULL); |
| |
| status = drv_request_bridge_res_dsp((void *)&host_res); |
| |
| if (DSP_FAILED(status)) { |
| dev_dbg(bridge, "%s: Failed to reserve bridge resources\n", |
| __func__); |
| goto leave; |
| } |
| |
| /* Get the Bridge driver interface functions */ |
| bridge_drv_entry(&drv_fxns, driver_file_name); |
| if (DSP_FAILED(cfg_get_object((u32 *) &hdrv_obj, REG_DRV_OBJECT))) { |
| /* don't propogate CFG errors from this PROC function */ |
| status = -EPERM; |
| } |
| /* Create the device object, and pass a handle to the Bridge driver for |
| * storage. */ |
| if (DSP_SUCCEEDED(status)) { |
| DBC_ASSERT(drv_fxns); |
| dev_obj = kzalloc(sizeof(struct dev_object), GFP_KERNEL); |
| if (dev_obj) { |
| /* Fill out the rest of the Dev Object structure: */ |
| dev_obj->dev_node_obj = dev_node_obj; |
| dev_obj->module_obj = module_obj; |
| dev_obj->cod_mgr = NULL; |
| dev_obj->hchnl_mgr = NULL; |
| dev_obj->hdeh_mgr = NULL; |
| dev_obj->lock_owner = NULL; |
| dev_obj->word_size = DSPWORDSIZE; |
| dev_obj->hdrv_obj = hdrv_obj; |
| dev_obj->dev_type = DSP_UNIT; |
| /* Store this Bridge's interface functions, based on its |
| * version. */ |
| store_interface_fxns(drv_fxns, |
| &dev_obj->bridge_interface); |
| |
| /* Call fxn_dev_create() to get the Bridge's device |
| * context handle. */ |
| status = (dev_obj->bridge_interface.pfn_dev_create) |
| (&dev_obj->hbridge_context, dev_obj, |
| host_res); |
| /* Assert bridge_dev_create()'s ensure clause: */ |
| DBC_ASSERT(DSP_FAILED(status) |
| || (dev_obj->hbridge_context != NULL)); |
| } else { |
| status = -ENOMEM; |
| } |
| } |
| /* Attempt to create the COD manager for this device: */ |
| if (DSP_SUCCEEDED(status)) |
| status = init_cod_mgr(dev_obj); |
| |
| /* Attempt to create the channel manager for this device: */ |
| if (DSP_SUCCEEDED(status)) { |
| mgr_attrs.max_channels = CHNL_MAXCHANNELS; |
| io_mgr_attrs.birq = host_res->birq_registers; |
| io_mgr_attrs.irq_shared = |
| (host_res->birq_attrib & CFG_IRQSHARED); |
| io_mgr_attrs.word_size = DSPWORDSIZE; |
| mgr_attrs.word_size = DSPWORDSIZE; |
| num_windows = host_res->num_mem_windows; |
| if (num_windows) { |
| /* Assume last memory window is for CHNL */ |
| io_mgr_attrs.shm_base = host_res->dw_mem_base[1] + |
| host_res->dw_offset_for_monitor; |
| io_mgr_attrs.usm_length = |
| host_res->dw_mem_length[1] - |
| host_res->dw_offset_for_monitor; |
| } else { |
| io_mgr_attrs.shm_base = 0; |
| io_mgr_attrs.usm_length = 0; |
| pr_err("%s: No memory reserved for shared structures\n", |
| __func__); |
| } |
| status = chnl_create(&dev_obj->hchnl_mgr, dev_obj, &mgr_attrs); |
| if (status == -ENOSYS) { |
| /* It's OK for a device not to have a channel |
| * manager: */ |
| status = 0; |
| } |
| /* Create CMM mgr even if Msg Mgr not impl. */ |
| status = cmm_create(&dev_obj->hcmm_mgr, |
| (struct dev_object *)dev_obj, NULL); |
| /* Only create IO manager if we have a channel manager */ |
| if (DSP_SUCCEEDED(status) && dev_obj->hchnl_mgr) { |
| status = io_create(&dev_obj->hio_mgr, dev_obj, |
| &io_mgr_attrs); |
| } |
| /* Only create DEH manager if we have an IO manager */ |
| if (DSP_SUCCEEDED(status)) { |
| /* Instantiate the DEH module */ |
| status = bridge_deh_create(&dev_obj->hdeh_mgr, dev_obj); |
| } |
| /* Create DMM mgr . */ |
| status = dmm_create(&dev_obj->dmm_mgr, |
| (struct dev_object *)dev_obj, NULL); |
| } |
| /* Add the new DEV_Object to the global list: */ |
| if (DSP_SUCCEEDED(status)) { |
| lst_init_elem(&dev_obj->link); |
| status = drv_insert_dev_object(hdrv_obj, dev_obj); |
| } |
| /* Create the Processor List */ |
| if (DSP_SUCCEEDED(status)) { |
| dev_obj->proc_list = kzalloc(sizeof(struct lst_list), |
| GFP_KERNEL); |
| if (!(dev_obj->proc_list)) |
| status = -EPERM; |
| else |
| INIT_LIST_HEAD(&dev_obj->proc_list->head); |
| } |
| leave: |
| /* If all went well, return a handle to the dev object; |
| * else, cleanup and return NULL in the OUT parameter. */ |
| if (DSP_SUCCEEDED(status)) { |
| *device_obj = dev_obj; |
| } else { |
| if (dev_obj) { |
| kfree(dev_obj->proc_list); |
| if (dev_obj->cod_mgr) |
| cod_delete(dev_obj->cod_mgr); |
| if (dev_obj->dmm_mgr) |
| dmm_destroy(dev_obj->dmm_mgr); |
| kfree(dev_obj); |
| } |
| |
| *device_obj = NULL; |
| } |
| |
| DBC_ENSURE((DSP_SUCCEEDED(status) && *device_obj) || |
| (DSP_FAILED(status) && !*device_obj)); |
| return status; |
| } |
| |
| /* |
| * ======== dev_create2 ======== |
| * Purpose: |
| * After successful loading of the image from api_init_complete2 |
| * (PROC Auto_Start) or proc_load this fxn is called. This creates |
| * the Node Manager and updates the DEV Object. |
| */ |
| int dev_create2(struct dev_object *hdev_obj) |
| { |
| int status = 0; |
| struct dev_object *dev_obj = hdev_obj; |
| |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(hdev_obj); |
| |
| /* There can be only one Node Manager per DEV object */ |
| DBC_ASSERT(!dev_obj->hnode_mgr); |
| status = node_create_mgr(&dev_obj->hnode_mgr, hdev_obj); |
| if (DSP_FAILED(status)) |
| dev_obj->hnode_mgr = NULL; |
| |
| DBC_ENSURE((DSP_SUCCEEDED(status) && dev_obj->hnode_mgr != NULL) |
| || (DSP_FAILED(status) && dev_obj->hnode_mgr == NULL)); |
| return status; |
| } |
| |
| /* |
| * ======== dev_destroy2 ======== |
| * Purpose: |
| * Destroys the Node manager for this device. |
| */ |
| int dev_destroy2(struct dev_object *hdev_obj) |
| { |
| int status = 0; |
| struct dev_object *dev_obj = hdev_obj; |
| |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(hdev_obj); |
| |
| if (dev_obj->hnode_mgr) { |
| if (DSP_FAILED(node_delete_mgr(dev_obj->hnode_mgr))) |
| status = -EPERM; |
| else |
| dev_obj->hnode_mgr = NULL; |
| |
| } |
| |
| DBC_ENSURE((DSP_SUCCEEDED(status) && dev_obj->hnode_mgr == NULL) || |
| DSP_FAILED(status)); |
| return status; |
| } |
| |
| /* |
| * ======== dev_destroy_device ======== |
| * Purpose: |
| * Destroys the channel manager for this device, if any, calls |
| * bridge_dev_destroy(), and then attempts to unload the Bridge module. |
| */ |
| int dev_destroy_device(struct dev_object *hdev_obj) |
| { |
| int status = 0; |
| struct dev_object *dev_obj = hdev_obj; |
| |
| DBC_REQUIRE(refs > 0); |
| |
| if (hdev_obj) { |
| if (dev_obj->cod_mgr) { |
| cod_delete(dev_obj->cod_mgr); |
| dev_obj->cod_mgr = NULL; |
| } |
| |
| if (dev_obj->hnode_mgr) { |
| node_delete_mgr(dev_obj->hnode_mgr); |
| dev_obj->hnode_mgr = NULL; |
| } |
| |
| /* Free the io, channel, and message managers for this board: */ |
| if (dev_obj->hio_mgr) { |
| io_destroy(dev_obj->hio_mgr); |
| dev_obj->hio_mgr = NULL; |
| } |
| if (dev_obj->hchnl_mgr) { |
| chnl_destroy(dev_obj->hchnl_mgr); |
| dev_obj->hchnl_mgr = NULL; |
| } |
| if (dev_obj->hmsg_mgr) { |
| msg_delete(dev_obj->hmsg_mgr); |
| dev_obj->hmsg_mgr = NULL; |
| } |
| |
| if (dev_obj->hdeh_mgr) { |
| /* Uninitialize DEH module. */ |
| bridge_deh_destroy(dev_obj->hdeh_mgr); |
| dev_obj->hdeh_mgr = NULL; |
| } |
| if (dev_obj->hcmm_mgr) { |
| cmm_destroy(dev_obj->hcmm_mgr, true); |
| dev_obj->hcmm_mgr = NULL; |
| } |
| |
| if (dev_obj->dmm_mgr) { |
| dmm_destroy(dev_obj->dmm_mgr); |
| dev_obj->dmm_mgr = NULL; |
| } |
| |
| /* Call the driver's bridge_dev_destroy() function: */ |
| /* Require of DevDestroy */ |
| if (dev_obj->hbridge_context) { |
| status = (*dev_obj->bridge_interface.pfn_dev_destroy) |
| (dev_obj->hbridge_context); |
| dev_obj->hbridge_context = NULL; |
| } else |
| status = -EPERM; |
| if (DSP_SUCCEEDED(status)) { |
| kfree(dev_obj->proc_list); |
| dev_obj->proc_list = NULL; |
| |
| /* Remove this DEV_Object from the global list: */ |
| drv_remove_dev_object(dev_obj->hdrv_obj, dev_obj); |
| /* Free The library * LDR_FreeModule |
| * (dev_obj->module_obj); */ |
| /* Free this dev object: */ |
| kfree(dev_obj); |
| dev_obj = NULL; |
| } |
| } else { |
| status = -EFAULT; |
| } |
| |
| return status; |
| } |
| |
| /* |
| * ======== dev_get_chnl_mgr ======== |
| * Purpose: |
| * Retrieve the handle to the channel manager handle created for this |
| * device. |
| */ |
| int dev_get_chnl_mgr(struct dev_object *hdev_obj, |
| OUT struct chnl_mgr **mgr) |
| { |
| int status = 0; |
| struct dev_object *dev_obj = hdev_obj; |
| |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(mgr != NULL); |
| |
| if (hdev_obj) { |
| *mgr = dev_obj->hchnl_mgr; |
| } else { |
| *mgr = NULL; |
| status = -EFAULT; |
| } |
| |
| DBC_ENSURE(DSP_SUCCEEDED(status) || ((mgr != NULL) && |
| (*mgr == NULL))); |
| return status; |
| } |
| |
| /* |
| * ======== dev_get_cmm_mgr ======== |
| * Purpose: |
| * Retrieve the handle to the shared memory manager created for this |
| * device. |
| */ |
| int dev_get_cmm_mgr(struct dev_object *hdev_obj, |
| OUT struct cmm_object **mgr) |
| { |
| int status = 0; |
| struct dev_object *dev_obj = hdev_obj; |
| |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(mgr != NULL); |
| |
| if (hdev_obj) { |
| *mgr = dev_obj->hcmm_mgr; |
| } else { |
| *mgr = NULL; |
| status = -EFAULT; |
| } |
| |
| DBC_ENSURE(DSP_SUCCEEDED(status) || ((mgr != NULL) && |
| (*mgr == NULL))); |
| return status; |
| } |
| |
| /* |
| * ======== dev_get_dmm_mgr ======== |
| * Purpose: |
| * Retrieve the handle to the dynamic memory manager created for this |
| * device. |
| */ |
| int dev_get_dmm_mgr(struct dev_object *hdev_obj, |
| OUT struct dmm_object **mgr) |
| { |
| int status = 0; |
| struct dev_object *dev_obj = hdev_obj; |
| |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(mgr != NULL); |
| |
| if (hdev_obj) { |
| *mgr = dev_obj->dmm_mgr; |
| } else { |
| *mgr = NULL; |
| status = -EFAULT; |
| } |
| |
| DBC_ENSURE(DSP_SUCCEEDED(status) || ((mgr != NULL) && |
| (*mgr == NULL))); |
| return status; |
| } |
| |
| /* |
| * ======== dev_get_cod_mgr ======== |
| * Purpose: |
| * Retrieve the COD manager create for this device. |
| */ |
| int dev_get_cod_mgr(struct dev_object *hdev_obj, |
| OUT struct cod_manager **cod_mgr) |
| { |
| int status = 0; |
| struct dev_object *dev_obj = hdev_obj; |
| |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(cod_mgr != NULL); |
| |
| if (hdev_obj) { |
| *cod_mgr = dev_obj->cod_mgr; |
| } else { |
| *cod_mgr = NULL; |
| status = -EFAULT; |
| } |
| |
| DBC_ENSURE(DSP_SUCCEEDED(status) || ((cod_mgr != NULL) && |
| (*cod_mgr == NULL))); |
| return status; |
| } |
| |
| /* |
| * ========= dev_get_deh_mgr ======== |
| */ |
| int dev_get_deh_mgr(struct dev_object *hdev_obj, |
| OUT struct deh_mgr **deh_manager) |
| { |
| int status = 0; |
| |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(deh_manager != NULL); |
| DBC_REQUIRE(hdev_obj); |
| if (hdev_obj) { |
| *deh_manager = hdev_obj->hdeh_mgr; |
| } else { |
| *deh_manager = NULL; |
| status = -EFAULT; |
| } |
| return status; |
| } |
| |
| /* |
| * ======== dev_get_dev_node ======== |
| * Purpose: |
| * Retrieve the platform specific device ID for this device. |
| */ |
| int dev_get_dev_node(struct dev_object *hdev_obj, |
| OUT struct cfg_devnode **dev_nde) |
| { |
| int status = 0; |
| struct dev_object *dev_obj = hdev_obj; |
| |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(dev_nde != NULL); |
| |
| if (hdev_obj) { |
| *dev_nde = dev_obj->dev_node_obj; |
| } else { |
| *dev_nde = NULL; |
| status = -EFAULT; |
| } |
| |
| DBC_ENSURE(DSP_SUCCEEDED(status) || ((dev_nde != NULL) && |
| (*dev_nde == NULL))); |
| return status; |
| } |
| |
| /* |
| * ======== dev_get_first ======== |
| * Purpose: |
| * Retrieve the first Device Object handle from an internal linked list |
| * DEV_OBJECTs maintained by DEV. |
| */ |
| struct dev_object *dev_get_first(void) |
| { |
| struct dev_object *dev_obj = NULL; |
| |
| dev_obj = (struct dev_object *)drv_get_first_dev_object(); |
| |
| return dev_obj; |
| } |
| |
| /* |
| * ======== dev_get_intf_fxns ======== |
| * Purpose: |
| * Retrieve the Bridge interface function structure for the loaded driver. |
| * if_fxns != NULL. |
| */ |
| int dev_get_intf_fxns(struct dev_object *hdev_obj, |
| OUT struct bridge_drv_interface **if_fxns) |
| { |
| int status = 0; |
| struct dev_object *dev_obj = hdev_obj; |
| |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(if_fxns != NULL); |
| |
| if (hdev_obj) { |
| *if_fxns = &dev_obj->bridge_interface; |
| } else { |
| *if_fxns = NULL; |
| status = -EFAULT; |
| } |
| |
| DBC_ENSURE(DSP_SUCCEEDED(status) || ((if_fxns != NULL) && |
| (*if_fxns == NULL))); |
| return status; |
| } |
| |
| /* |
| * ========= dev_get_io_mgr ======== |
| */ |
| int dev_get_io_mgr(struct dev_object *hdev_obj, |
| OUT struct io_mgr **io_man) |
| { |
| int status = 0; |
| |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(io_man != NULL); |
| DBC_REQUIRE(hdev_obj); |
| |
| if (hdev_obj) { |
| *io_man = hdev_obj->hio_mgr; |
| } else { |
| *io_man = NULL; |
| status = -EFAULT; |
| } |
| |
| return status; |
| } |
| |
| /* |
| * ======== dev_get_next ======== |
| * Purpose: |
| * Retrieve the next Device Object handle from an internal linked list |
| * of DEV_OBJECTs maintained by DEV, after having previously called |
| * dev_get_first() and zero or more dev_get_next |
| */ |
| struct dev_object *dev_get_next(struct dev_object *hdev_obj) |
| { |
| struct dev_object *next_dev_object = NULL; |
| |
| if (hdev_obj) { |
| next_dev_object = (struct dev_object *) |
| drv_get_next_dev_object((u32) hdev_obj); |
| } |
| |
| return next_dev_object; |
| } |
| |
| /* |
| * ========= dev_get_msg_mgr ======== |
| */ |
| void dev_get_msg_mgr(struct dev_object *hdev_obj, OUT struct msg_mgr **msg_man) |
| { |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(msg_man != NULL); |
| DBC_REQUIRE(hdev_obj); |
| |
| *msg_man = hdev_obj->hmsg_mgr; |
| } |
| |
| /* |
| * ======== dev_get_node_manager ======== |
| * Purpose: |
| * Retrieve the Node Manager Handle |
| */ |
| int dev_get_node_manager(struct dev_object *hdev_obj, |
| OUT struct node_mgr **node_man) |
| { |
| int status = 0; |
| struct dev_object *dev_obj = hdev_obj; |
| |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(node_man != NULL); |
| |
| if (hdev_obj) { |
| *node_man = dev_obj->hnode_mgr; |
| } else { |
| *node_man = NULL; |
| status = -EFAULT; |
| } |
| |
| DBC_ENSURE(DSP_SUCCEEDED(status) || ((node_man != NULL) && |
| (*node_man == NULL))); |
| return status; |
| } |
| |
| /* |
| * ======== dev_get_symbol ======== |
| */ |
| int dev_get_symbol(struct dev_object *hdev_obj, |
| IN CONST char *str_sym, OUT u32 * pul_value) |
| { |
| int status = 0; |
| struct cod_manager *cod_mgr; |
| |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(str_sym != NULL && pul_value != NULL); |
| |
| if (hdev_obj) { |
| status = dev_get_cod_mgr(hdev_obj, &cod_mgr); |
| if (cod_mgr) |
| status = cod_get_sym_value(cod_mgr, (char *)str_sym, |
| pul_value); |
| else |
| status = -EFAULT; |
| } |
| |
| return status; |
| } |
| |
| /* |
| * ======== dev_get_bridge_context ======== |
| * Purpose: |
| * Retrieve the Bridge Context handle, as returned by the |
| * bridge_dev_create fxn. |
| */ |
| int dev_get_bridge_context(struct dev_object *hdev_obj, |
| OUT struct bridge_dev_context **phbridge_context) |
| { |
| int status = 0; |
| struct dev_object *dev_obj = hdev_obj; |
| |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(phbridge_context != NULL); |
| |
| if (hdev_obj) { |
| *phbridge_context = dev_obj->hbridge_context; |
| } else { |
| *phbridge_context = NULL; |
| status = -EFAULT; |
| } |
| |
| DBC_ENSURE(DSP_SUCCEEDED(status) || ((phbridge_context != NULL) && |
| (*phbridge_context == NULL))); |
| return status; |
| } |
| |
| /* |
| * ======== dev_exit ======== |
| * Purpose: |
| * Decrement reference count, and free resources when reference count is |
| * 0. |
| */ |
| void dev_exit(void) |
| { |
| DBC_REQUIRE(refs > 0); |
| |
| refs--; |
| |
| if (refs == 0) { |
| cmm_exit(); |
| dmm_exit(); |
| } |
| |
| DBC_ENSURE(refs >= 0); |
| } |
| |
| /* |
| * ======== dev_init ======== |
| * Purpose: |
| * Initialize DEV's private state, keeping a reference count on each call. |
| */ |
| bool dev_init(void) |
| { |
| bool cmm_ret, dmm_ret, ret = true; |
| |
| DBC_REQUIRE(refs >= 0); |
| |
| if (refs == 0) { |
| cmm_ret = cmm_init(); |
| dmm_ret = dmm_init(); |
| |
| ret = cmm_ret && dmm_ret; |
| |
| if (!ret) { |
| if (cmm_ret) |
| cmm_exit(); |
| |
| if (dmm_ret) |
| dmm_exit(); |
| |
| } |
| } |
| |
| if (ret) |
| refs++; |
| |
| DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0))); |
| |
| return ret; |
| } |
| |
| /* |
| * ======== dev_notify_clients ======== |
| * Purpose: |
| * Notify all clients of this device of a change in device status. |
| */ |
| int dev_notify_clients(struct dev_object *hdev_obj, u32 ret) |
| { |
| int status = 0; |
| |
| struct dev_object *dev_obj = hdev_obj; |
| void *proc_obj; |
| |
| for (proc_obj = (void *)lst_first(dev_obj->proc_list); |
| proc_obj != NULL; |
| proc_obj = (void *)lst_next(dev_obj->proc_list, |
| (struct list_head *)proc_obj)) |
| proc_notify_clients(proc_obj, (u32) ret); |
| |
| return status; |
| } |
| |
| /* |
| * ======== dev_remove_device ======== |
| */ |
| int dev_remove_device(struct cfg_devnode *dev_node_obj) |
| { |
| struct dev_object *hdev_obj; /* handle to device object */ |
| int status = 0; |
| struct dev_object *dev_obj; |
| |
| /* Retrieve the device object handle originaly stored with |
| * the dev_node: */ |
| status = cfg_get_dev_object(dev_node_obj, (u32 *) &hdev_obj); |
| if (DSP_SUCCEEDED(status)) { |
| /* Remove the Processor List */ |
| dev_obj = (struct dev_object *)hdev_obj; |
| /* Destroy the device object. */ |
| status = dev_destroy_device(hdev_obj); |
| } |
| |
| return status; |
| } |
| |
| /* |
| * ======== dev_set_chnl_mgr ======== |
| * Purpose: |
| * Set the channel manager for this device. |
| */ |
| int dev_set_chnl_mgr(struct dev_object *hdev_obj, |
| struct chnl_mgr *hmgr) |
| { |
| int status = 0; |
| struct dev_object *dev_obj = hdev_obj; |
| |
| DBC_REQUIRE(refs > 0); |
| |
| if (hdev_obj) |
| dev_obj->hchnl_mgr = hmgr; |
| else |
| status = -EFAULT; |
| |
| DBC_ENSURE(DSP_FAILED(status) || (dev_obj->hchnl_mgr == hmgr)); |
| return status; |
| } |
| |
| /* |
| * ======== dev_set_msg_mgr ======== |
| * Purpose: |
| * Set the message manager for this device. |
| */ |
| void dev_set_msg_mgr(struct dev_object *hdev_obj, struct msg_mgr *hmgr) |
| { |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(hdev_obj); |
| |
| hdev_obj->hmsg_mgr = hmgr; |
| } |
| |
| /* |
| * ======== dev_start_device ======== |
| * Purpose: |
| * Initializes the new device with the BRIDGE environment. |
| */ |
| int dev_start_device(struct cfg_devnode *dev_node_obj) |
| { |
| struct dev_object *hdev_obj = NULL; /* handle to 'Bridge Device */ |
| /* Bridge driver filename */ |
| char bridge_file_name[CFG_MAXSEARCHPATHLEN] = "UMA"; |
| int status; |
| struct mgr_object *hmgr_obj = NULL; |
| |
| DBC_REQUIRE(refs > 0); |
| |
| /* Given all resources, create a device object. */ |
| status = dev_create_device(&hdev_obj, bridge_file_name, |
| dev_node_obj); |
| if (DSP_SUCCEEDED(status)) { |
| /* Store away the hdev_obj with the DEVNODE */ |
| status = cfg_set_dev_object(dev_node_obj, (u32) hdev_obj); |
| if (DSP_FAILED(status)) { |
| /* Clean up */ |
| dev_destroy_device(hdev_obj); |
| hdev_obj = NULL; |
| } |
| } |
| if (DSP_SUCCEEDED(status)) { |
| /* Create the Manager Object */ |
| status = mgr_create(&hmgr_obj, dev_node_obj); |
| } |
| if (DSP_FAILED(status)) { |
| if (hdev_obj) |
| dev_destroy_device(hdev_obj); |
| |
| /* Ensure the device extension is NULL */ |
| cfg_set_dev_object(dev_node_obj, 0L); |
| } |
| |
| return status; |
| } |
| |
| /* |
| * ======== fxn_not_implemented ======== |
| * Purpose: |
| * Takes the place of a Bridge Null Function. |
| * Parameters: |
| * Multiple, optional. |
| * Returns: |
| * -ENOSYS: Always. |
| */ |
| static int fxn_not_implemented(int arg, ...) |
| { |
| return -ENOSYS; |
| } |
| |
| /* |
| * ======== init_cod_mgr ======== |
| * Purpose: |
| * Create a COD manager for this device. |
| * Parameters: |
| * dev_obj: Pointer to device object created with |
| * dev_create_device() |
| * Returns: |
| * 0: Success. |
| * -EFAULT: Invalid hdev_obj. |
| * Requires: |
| * Should only be called once by dev_create_device() for a given DevObject. |
| * Ensures: |
| */ |
| static int init_cod_mgr(struct dev_object *dev_obj) |
| { |
| int status = 0; |
| char *sz_dummy_file = "dummy"; |
| |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(!dev_obj || (dev_obj->cod_mgr == NULL)); |
| |
| status = cod_create(&dev_obj->cod_mgr, sz_dummy_file, NULL); |
| |
| return status; |
| } |
| |
| /* |
| * ======== dev_insert_proc_object ======== |
| * Purpose: |
| * Insert a ProcObject into the list maintained by DEV. |
| * Parameters: |
| * p_proc_object: Ptr to ProcObject to insert. |
| * dev_obj: Ptr to Dev Object where the list is. |
| * already_attached: Ptr to return the bool |
| * Returns: |
| * 0: If successful. |
| * Requires: |
| * List Exists |
| * hdev_obj is Valid handle |
| * DEV Initialized |
| * already_attached != NULL |
| * proc_obj != 0 |
| * Ensures: |
| * 0 and List is not Empty. |
| */ |
| int dev_insert_proc_object(struct dev_object *hdev_obj, |
| u32 proc_obj, OUT bool *already_attached) |
| { |
| int status = 0; |
| struct dev_object *dev_obj = (struct dev_object *)hdev_obj; |
| |
| DBC_REQUIRE(refs > 0); |
| DBC_REQUIRE(dev_obj); |
| DBC_REQUIRE(proc_obj != 0); |
| DBC_REQUIRE(dev_obj->proc_list != NULL); |
| DBC_REQUIRE(already_attached != NULL); |
| if (!LST_IS_EMPTY(dev_obj->proc_list)) |
| *already_attached = true; |
| |
| /* Add DevObject to tail. */ |
| lst_put_tail(dev_obj->proc_list, (struct list_head *)proc_obj); |
| |
| DBC_ENSURE(DSP_SUCCEEDED(status) && !LST_IS_EMPTY(dev_obj->proc_list)); |
| |
| return status; |
| } |
| |
| /* |
| * ======== dev_remove_proc_object ======== |
| * Purpose: |
| * Search for and remove a Proc object from the given list maintained |
| * by the DEV |
| * Parameters: |
| * p_proc_object: Ptr to ProcObject to insert. |
| * dev_obj Ptr to Dev Object where the list is. |
| * Returns: |
| * 0: If successful. |
| * Requires: |
| * List exists and is not empty |
| * proc_obj != 0 |
| * hdev_obj is a valid Dev handle. |
| * Ensures: |
| * Details: |
| * List will be deleted when the DEV is destroyed. |
| */ |
| int dev_remove_proc_object(struct dev_object *hdev_obj, u32 proc_obj) |
| { |
| int status = -EPERM; |
| struct list_head *cur_elem; |
| struct dev_object *dev_obj = (struct dev_object *)hdev_obj; |
| |
| DBC_REQUIRE(dev_obj); |
| DBC_REQUIRE(proc_obj != 0); |
| DBC_REQUIRE(dev_obj->proc_list != NULL); |
| DBC_REQUIRE(!LST_IS_EMPTY(dev_obj->proc_list)); |
| |
| /* Search list for dev_obj: */ |
| for (cur_elem = lst_first(dev_obj->proc_list); cur_elem != NULL; |
| cur_elem = lst_next(dev_obj->proc_list, cur_elem)) { |
| /* If found, remove it. */ |
| if ((u32) cur_elem == proc_obj) { |
| lst_remove_elem(dev_obj->proc_list, cur_elem); |
| status = 0; |
| break; |
| } |
| } |
| |
| return status; |
| } |
| |
| int dev_get_dev_type(struct dev_object *device_obj, u8 *dev_type) |
| { |
| int status = 0; |
| struct dev_object *dev_obj = (struct dev_object *)device_obj; |
| |
| *dev_type = dev_obj->dev_type; |
| |
| return status; |
| } |
| |
| /* |
| * ======== store_interface_fxns ======== |
| * Purpose: |
| * Copy the Bridge's interface functions into the device object, |
| * ensuring that fxn_not_implemented() is set for: |
| * |
| * 1. All Bridge function pointers which are NULL; and |
| * 2. All function slots in the struct dev_object structure which have no |
| * corresponding slots in the the Bridge's interface, because the Bridge |
| * is of an *older* version. |
| * Parameters: |
| * intf_fxns: Interface fxn Structure of the Bridge's Dev Object. |
| * drv_fxns: Interface Fxns offered by the Bridge during DEV_Create(). |
| * Returns: |
| * Requires: |
| * Input pointers are valid. |
| * Bridge driver is *not* written for a newer DSP API. |
| * Ensures: |
| * All function pointers in the dev object's fxn interface are not NULL. |
| */ |
| static void store_interface_fxns(struct bridge_drv_interface *drv_fxns, |
| OUT struct bridge_drv_interface *intf_fxns) |
| { |
| u32 bridge_version; |
| |
| /* Local helper macro: */ |
| #define STORE_FXN(cast, pfn) \ |
| (intf_fxns->pfn = ((drv_fxns->pfn != NULL) ? drv_fxns->pfn : \ |
| (cast)fxn_not_implemented)) |
| |
| DBC_REQUIRE(intf_fxns != NULL); |
| DBC_REQUIRE(drv_fxns != NULL); |
| DBC_REQUIRE(MAKEVERSION(drv_fxns->brd_api_major_version, |
| drv_fxns->brd_api_minor_version) <= BRD_API_VERSION); |
| bridge_version = MAKEVERSION(drv_fxns->brd_api_major_version, |
| drv_fxns->brd_api_minor_version); |
| intf_fxns->brd_api_major_version = drv_fxns->brd_api_major_version; |
| intf_fxns->brd_api_minor_version = drv_fxns->brd_api_minor_version; |
| /* Install functions up to DSP API version .80 (first alpha): */ |
| if (bridge_version > 0) { |
| STORE_FXN(fxn_dev_create, pfn_dev_create); |
| STORE_FXN(fxn_dev_destroy, pfn_dev_destroy); |
| STORE_FXN(fxn_dev_ctrl, pfn_dev_cntrl); |
| STORE_FXN(fxn_brd_monitor, pfn_brd_monitor); |
| STORE_FXN(fxn_brd_start, pfn_brd_start); |
| STORE_FXN(fxn_brd_stop, pfn_brd_stop); |
| STORE_FXN(fxn_brd_status, pfn_brd_status); |
| STORE_FXN(fxn_brd_read, pfn_brd_read); |
| STORE_FXN(fxn_brd_write, pfn_brd_write); |
| STORE_FXN(fxn_brd_setstate, pfn_brd_set_state); |
| STORE_FXN(fxn_brd_memcopy, pfn_brd_mem_copy); |
| STORE_FXN(fxn_brd_memwrite, pfn_brd_mem_write); |
| STORE_FXN(fxn_brd_memmap, pfn_brd_mem_map); |
| STORE_FXN(fxn_brd_memunmap, pfn_brd_mem_un_map); |
| STORE_FXN(fxn_chnl_create, pfn_chnl_create); |
| STORE_FXN(fxn_chnl_destroy, pfn_chnl_destroy); |
| STORE_FXN(fxn_chnl_open, pfn_chnl_open); |
| STORE_FXN(fxn_chnl_close, pfn_chnl_close); |
| STORE_FXN(fxn_chnl_addioreq, pfn_chnl_add_io_req); |
| STORE_FXN(fxn_chnl_getioc, pfn_chnl_get_ioc); |
| STORE_FXN(fxn_chnl_cancelio, pfn_chnl_cancel_io); |
| STORE_FXN(fxn_chnl_flushio, pfn_chnl_flush_io); |
| STORE_FXN(fxn_chnl_getinfo, pfn_chnl_get_info); |
| STORE_FXN(fxn_chnl_getmgrinfo, pfn_chnl_get_mgr_info); |
| STORE_FXN(fxn_chnl_idle, pfn_chnl_idle); |
| STORE_FXN(fxn_chnl_registernotify, pfn_chnl_register_notify); |
| STORE_FXN(fxn_io_create, pfn_io_create); |
| STORE_FXN(fxn_io_destroy, pfn_io_destroy); |
| STORE_FXN(fxn_io_onloaded, pfn_io_on_loaded); |
| STORE_FXN(fxn_io_getprocload, pfn_io_get_proc_load); |
| STORE_FXN(fxn_msg_create, pfn_msg_create); |
| STORE_FXN(fxn_msg_createqueue, pfn_msg_create_queue); |
| STORE_FXN(fxn_msg_delete, pfn_msg_delete); |
| STORE_FXN(fxn_msg_deletequeue, pfn_msg_delete_queue); |
| STORE_FXN(fxn_msg_get, pfn_msg_get); |
| STORE_FXN(fxn_msg_put, pfn_msg_put); |
| STORE_FXN(fxn_msg_registernotify, pfn_msg_register_notify); |
| STORE_FXN(fxn_msg_setqueueid, pfn_msg_set_queue_id); |
| } |
| /* Add code for any additional functions in newerBridge versions here */ |
| /* Ensure postcondition: */ |
| DBC_ENSURE(intf_fxns->pfn_dev_create != NULL); |
| DBC_ENSURE(intf_fxns->pfn_dev_destroy != NULL); |
| DBC_ENSURE(intf_fxns->pfn_dev_cntrl != NULL); |
| DBC_ENSURE(intf_fxns->pfn_brd_monitor != NULL); |
| DBC_ENSURE(intf_fxns->pfn_brd_start != NULL); |
| DBC_ENSURE(intf_fxns->pfn_brd_stop != NULL); |
| DBC_ENSURE(intf_fxns->pfn_brd_status != NULL); |
| DBC_ENSURE(intf_fxns->pfn_brd_read != NULL); |
| DBC_ENSURE(intf_fxns->pfn_brd_write != NULL); |
| DBC_ENSURE(intf_fxns->pfn_chnl_create != NULL); |
| DBC_ENSURE(intf_fxns->pfn_chnl_destroy != NULL); |
| DBC_ENSURE(intf_fxns->pfn_chnl_open != NULL); |
| DBC_ENSURE(intf_fxns->pfn_chnl_close != NULL); |
| DBC_ENSURE(intf_fxns->pfn_chnl_add_io_req != NULL); |
| DBC_ENSURE(intf_fxns->pfn_chnl_get_ioc != NULL); |
| DBC_ENSURE(intf_fxns->pfn_chnl_cancel_io != NULL); |
| DBC_ENSURE(intf_fxns->pfn_chnl_flush_io != NULL); |
| DBC_ENSURE(intf_fxns->pfn_chnl_get_info != NULL); |
| DBC_ENSURE(intf_fxns->pfn_chnl_get_mgr_info != NULL); |
| DBC_ENSURE(intf_fxns->pfn_chnl_idle != NULL); |
| DBC_ENSURE(intf_fxns->pfn_chnl_register_notify != NULL); |
| DBC_ENSURE(intf_fxns->pfn_io_create != NULL); |
| DBC_ENSURE(intf_fxns->pfn_io_destroy != NULL); |
| DBC_ENSURE(intf_fxns->pfn_io_on_loaded != NULL); |
| DBC_ENSURE(intf_fxns->pfn_io_get_proc_load != NULL); |
| DBC_ENSURE(intf_fxns->pfn_msg_set_queue_id != NULL); |
| |
| #undef STORE_FXN |
| } |