text: /* 
  * Copyright (C) ST-Ericsson AP Pte Ltd 2010 
  *
  * ISP1763 Linux HCD Controller driver : hal
  * 
  * This program is free software; you can redistribute it and/or modify it under the terms of 
  * the GNU General Public License as published by the Free Software Foundation; version 
  * 2 of the License. 
  * 
  * This program is distributed in the hope that it will be useful, but WITHOUT ANY  
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS  
  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more  
  * details. 
  * 
  * You should have received a copy of the GNU General Public License 
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
  * 
  * This is the main hardware abstraction layer file. Hardware initialization, interupt
  * processing and read/write routines are handled here.
  * 
  * Author : wired support <wired.support@stericsson.com>
  *
  */
  
  
  #include <linux/module.h>
  #include <linux/device.h>
  #include <linux/platform_device.h>
  #include <linux/kernel.h>
  #include <linux/delay.h>
  #include <linux/ioport.h>
  #include <linux/sched.h>
  #include <linux/completion.h>
  #include <linux/slab.h>
  #include <linux/smp_lock.h>
  #include <linux/errno.h>
  #include <linux/init.h>
  #include <linux/timer.h>
  #include <linux/list.h>
  #include <linux/interrupt.h>
  #include <linux/usb.h>
  #include <linux/gpio.h>
  #include <mach/board.h>
  #include <linux/poll.h>
  #include <asm/io.h>
  #include <asm/irq.h>
  #include <asm/system.h>
  #include <asm/unaligned.h>
  
  
  /*--------------------------------------------------------------*
   *               linux system include files
   *--------------------------------------------------------------*/
  #include "hal_msm.h"
  #include "../hal/hal_intf.h"
  #include "../hal/isp1763.h"
  
  
  /*--------------------------------------------------------------*
   *               Local variable Definitions
   *--------------------------------------------------------------*/
  struct isp1763_dev isp1763_loc_dev[ISP1763_LAST_DEV];
  
  
  /*--------------------------------------------------------------*
   *               Local # Definitions
   *--------------------------------------------------------------*/
  #define         PCI_ACCESS_RETRY_COUNT  20
  #define         ISP1763_DRIVER_NAME     "isp1763_usb"
  
  /*--------------------------------------------------------------*
   *               Local Function
   *--------------------------------------------------------------*/
  
  static int __devexit isp1763_remove(struct platform_device *pdev);
  static int __devinit isp1763_probe(struct platform_device *pdev);
  
  
  /*--------------------------------------------------------------*
   *               Platform Driver Interface Functions
   *--------------------------------------------------------------*/
  
  static struct platform_driver isp1763_usb_driver = {
  	.remove = __exit_p(isp1763_remove),
  	.driver = {
  		.name = ISP1763_DRIVER_NAME,
  		.owner = THIS_MODULE,
  	},
  };
  
  
  /*--------------------------------------------------------------*
   *               ISP1763 Read write routine
   *--------------------------------------------------------------*/
  /*
   * EBI2 on 8660 ignores the first bit and shifts the address by
   * one bit to the right.
   * Hence, shift left all the register addresses before accessing
   * them over EBI2.
   * This logic applies only for the register read/writes, for
   * read/write from ISP memory this conversion is not needed
   * as the ISP obtains the memory address from 'memory' register
   */
  
  /* Write a 32 bit Register of isp1763 */
  void
  isp1763_reg_write32(struct isp1763_dev *dev, u16 reg, u32 data)
  {
  	/* Write the 32bit to the register address given to us */
  
  	reg <<= 1;
  #ifdef DATABUS_WIDTH_16
  	writew((u16) data, dev->baseaddress + ((reg)));
  	writew((u16) (data >> 16), dev->baseaddress + (((reg + 4))));
  #else
  	writeb((u8) data, dev->baseaddress + (reg));
  	writeb((u8) (data >> 8), dev->baseaddress + ((reg + 1)));
  	writeb((u8) (data >> 16), dev->baseaddress + ((reg + 2)));
  	writeb((u8) (data >> 24), dev->baseaddress + ((reg + 3)));
  #endif
  
  }
  EXPORT_SYMBOL(isp1763_reg_write32);
  
  
  /* Read a 32 bit Register of isp1763 */
  u32
  isp1763_reg_read32(struct isp1763_dev *dev, u16 reg, u32 data)
  {
  
  #ifdef DATABUS_WIDTH_16
  	u16 wvalue1, wvalue2;
  #else
  	u8 bval1, bval2, bval3, bval4;
  #endif
  	data = 0;
  	reg <<= 1;
  #ifdef DATABUS_WIDTH_16
  	wvalue1 = readw(dev->baseaddress + ((reg)));
  	wvalue2 = readw(dev->baseaddress + (((reg + 4))));
  	data |= wvalue2;
  	data <<= 16;
  	data |= wvalue1;
  #else
  
  	bval1 = readb(dev->baseaddress + (reg));
  	bval2 = readb(dev->baseaddress + (reg + 1));
  	bval3 = readb(dev->baseaddress + (reg + 2));
  	bval4 = readb(dev->baseaddress + (reg + 3));
  	data = 0;
  	data |= bval4;
  	data <<= 8;
  	data |= bval3;
  	data <<= 8;
  	data |= bval2;
  	data <<= 8;
  	data |= bval1;
  
  #endif
  
  	return data;
  }
  EXPORT_SYMBOL(isp1763_reg_read32);
  
  
  /* Read a 16 bit Register of isp1763 */
  u16
  isp1763_reg_read16(struct isp1763_dev * dev, u16 reg, u16 data)
  {
  	reg <<= 1;
  #ifdef DATABUS_WIDTH_16
  	data = readw(dev->baseaddress + ((reg)));
  #else
  	u8 bval1, bval2;
  	bval1 = readb(dev->baseaddress + (reg));
  	if (reg == HC_DATA_REG){
  		bval2 = readb(dev->baseaddress + (reg));
  	} else {
  		bval2 = readb(dev->baseaddress + ((reg + 1)));
  	}
  	data = 0;
  	data |= bval2;
  	data <<= 8;
  	data |= bval1;
  
  #endif
  	return data;
  }
  EXPORT_SYMBOL(isp1763_reg_read16);
  
  /* Write a 16 bit Register of isp1763 */
  void
  isp1763_reg_write16(struct isp1763_dev *dev, u16 reg, u16 data)
  {
  	reg <<= 1;
  #ifdef DATABUS_WIDTH_16
  	writew(data, dev->baseaddress + ((reg)));
  #else
  	writeb((u8) data, dev->baseaddress + (reg));
  	if (reg == HC_DATA_REG){
  		writeb((u8) (data >> 8), dev->baseaddress + (reg));
  	}else{
  		writeb((u8) (data >> 8), dev->baseaddress + ((reg + 1)));
  	}
  
  #endif
  }
  EXPORT_SYMBOL(isp1763_reg_write16);
  
  /* Read a 8 bit Register of isp1763 */
  u8
  isp1763_reg_read8(struct isp1763_dev *dev, u16 reg, u8 data)
  {
  	reg <<= 1;
  	data = readb((dev->baseaddress + (reg)));
  	return data;
  }
  EXPORT_SYMBOL(isp1763_reg_read8);
  
  /* Write a 8 bit Register of isp1763 */
  void
  isp1763_reg_write8(struct isp1763_dev *dev, u16 reg, u8 data)
  {
  	reg <<= 1;
  	writeb(data, (dev->baseaddress + (reg)));
  }
  EXPORT_SYMBOL(isp1763_reg_write8);
  
  
  /*--------------------------------------------------------------*
   *
   * Module dtatils: isp1763_mem_read
   *
   * Memory read using PIO method.
   *
   *  Input: struct isp1763_driver *drv  -->  Driver structure.
   *                      u32 start_add     --> Starting address of memory
   *              u32 end_add     ---> End address
   *
   *              u32 * buffer      --> Buffer pointer.
   *              u32 length       ---> Length
   *              u16 dir          ---> Direction ( Inc or Dec)
   *
   *  Output     int Length  ----> Number of bytes read
   *
   *  Called by: system function
   *
   *
   *--------------------------------------------------------------*/
  /* Memory read function PIO */
  
  int
  isp1763_mem_read(struct isp1763_dev *dev, u32 start_add,
  	u32 end_add, u32 * buffer, u32 length, u16 dir)
  {
  	u8 *one = (u8 *) buffer;
  	u16 *two = (u16 *) buffer;
  	u32 a = (u32) length;
  	u32 w;
  	u32 w2;
  
  	if (buffer == 0) {
  		printk("Buffer address zero\n");
  		return 0;
  	}
  
  
  	isp1763_reg_write16(dev, HC_MEM_READ_REG, start_add);
  	/* This delay requirement comes from the ISP1763A programming guide */
  	ndelay(100);
  last:
  	w = isp1763_reg_read16(dev, HC_DATA_REG, w);
  	w2 = isp1763_reg_read16(dev, HC_DATA_REG, w);
  	w2 <<= 16;
  	w = w | w2;
  	if (a == 1) {
  		*one = (u8) w;
  		return 0;
  	}
  	if (a == 2) {
  		*two = (u16) w;
  		return 0;
  	}
  
  	if (a == 3) {
  		*two = (u16) w;
  		two += 1;
  		w >>= 16;
  		*two = (u8) (w);
  		return 0;
  
  	}
  	while (a > 0) {
  		*buffer = w;
  		a -= 4;
  		if (a <= 0) {
  			break;
  		}
  		if (a < 4) {
  			buffer += 1;
  			one = (u8 *) buffer;
  			two = (u16 *) buffer;
  			goto last;
  		}
  		buffer += 1;
  		w = isp1763_reg_read16(dev, HC_DATA_REG, w);
  		w2 = isp1763_reg_read16(dev, HC_DATA_REG, w);
  		w2 <<= 16;
  		w = w | w2;
  	}
  	return ((a < 0) || (a == 0)) ? 0 : (-1);
  
  }
  EXPORT_SYMBOL(isp1763_mem_read);
  
  
  /*--------------------------------------------------------------*
   *
   * Module dtatils: isp1763_mem_write
   *
   * Memory write using PIO method.
   *
   *  Input: struct isp1763_driver *drv  -->  Driver structure.
   *                      u32 start_add     --> Starting address of memory
   *              u32 end_add     ---> End address
   *
   *              u32 * buffer      --> Buffer pointer.
   *              u32 length       ---> Length
   *              u16 dir          ---> Direction ( Inc or Dec)
   *
   *  Output     int Length  ----> Number of bytes read
   *
   *  Called by: system function
   *
   *
   *--------------------------------------------------------------*/
  
  /* Memory read function IO */
  
  int
  isp1763_mem_write(struct isp1763_dev *dev,
  	u32 start_add, u32 end_add, u32 * buffer, u32 length, u16 dir)
  {
  	int a = length;
  	u8 one = (u8) (*buffer);
  	u16 two = (u16) (*buffer);
  
  
  	isp1763_reg_write16(dev, HC_MEM_READ_REG, start_add);
  	/* This delay requirement comes from the ISP1763A programming guide */
  	ndelay(100);
  
  	if (a == 1) {
  		isp1763_reg_write16(dev, HC_DATA_REG, one);
  		return 0;
  	}
  	if (a == 2) {
  		isp1763_reg_write16(dev, HC_DATA_REG, two);
  		return 0;
  	}
  
  	while (a > 0) {
  		isp1763_reg_write16(dev, HC_DATA_REG, (u16) (*buffer));
  		if (a >= 3)
  			isp1763_reg_write16(dev, HC_DATA_REG,
  					    (u16) ((*buffer) >> 16));
  		start_add += 4;
  		a -= 4;
  		if (a <= 0)
  			break;
  		buffer += 1;
  
  	}
  
  	return ((a < 0) || (a == 0)) ? 0 : (-1);
  
  }
  EXPORT_SYMBOL(isp1763_mem_write);
  
  
  /*--------------------------------------------------------------*
   *
   * Module dtatils: isp1763_register_driver
   *
   * This function is used by top driver (OTG, HCD, DCD) to register
   * their communication functions (probe, remove, suspend, resume) using
   * the drv data structure.
   * This function will call the probe function of the driver if the ISP1763
   * corresponding to the driver is enabled
   *
   *  Input: struct isp1763_driver *drv  --> Driver structure.
   *  Output result
   *         0= complete
   *         1= error.
   *
   *  Called by: system function module_init
   *
   *
   *--------------------------------------------------------------*/
  
  int
  isp1763_register_driver(struct isp1763_driver *drv)
  {
  	struct isp1763_dev *dev;
  	int result = -EINVAL;
  
  	hal_entry("%s: Entered\n", __FUNCTION__);
  	info("isp1763_register_driver(drv=%p)\n", drv);
  
  	if (!drv) {
  		return -EINVAL;
  	}
  
  	dev = &isp1763_loc_dev[drv->index];
  	if (!dev->baseaddress)
  		return -EINVAL;
  
  	dev->active = 1;	/* set the driver as active*/
  
  	if (drv->probe) {
  		result = drv->probe(dev, drv->id);
  	} else {
  		printk("%s no probe function for indes %d \n", __FUNCTION__,
  			(int)drv->index);
  	}
  
  	if (result >= 0) {
  		pr_debug(KERN_INFO __FILE__ ": Registered Driver %s\n",
  			drv->name);
  		dev->driver = drv;
  	}
  	hal_entry("%s: Exit\n", __FUNCTION__);
  	return result;
  }				/* End of isp1763_register_driver */
  EXPORT_SYMBOL(isp1763_register_driver);
  
  
  /*--------------------------------------------------------------*
   *
   * Module dtatils: isp1763_unregister_driver
   *
   * This function is used by top driver (OTG, HCD, DCD) to de-register
   * their communication functions (probe, remove, suspend, resume) using
   * the drv data structure.
   * This function will check whether the driver is registered or not and
   * call the remove function of the driver if registered
   *
   *  Input: struct isp1763_driver *drv  --> Driver structure.
   *  Output result
   *         0= complete
   *         1= error.
   *
   *  Called by: system function module_init
   *
   *
   *--------------------------------------------------------------*/
  
  void
  isp1763_unregister_driver(struct isp1763_driver *drv)
  {
  	struct isp1763_dev *dev;
  	hal_entry("%s: Entered\n", __FUNCTION__);
  
  	info("isp1763_unregister_driver(drv=%p)\n", drv);
  	dev = &isp1763_loc_dev[drv->index];
  	if (dev->driver == drv) {
  		/* driver registered is same as the requestig driver */
  		drv->remove(dev);
  		dev->driver = NULL;
  		info(": De-registered Driver %s\n", drv->name);
  		return;
  	}
  	hal_entry("%s: Exit\n", __FUNCTION__);
  }				/* End of isp1763_unregister_driver */
  EXPORT_SYMBOL(isp1763_unregister_driver);
  
  
  /*--------------------------------------------------------------*
   *               ISP1763 Platform driver interface routine.
   *--------------------------------------------------------------*/
  
  
  /*--------------------------------------------------------------*
   *
   *  Module dtatils: isp1763_module_init
   *
   *  This  is the module initialization function. It registers to
   *  driver for a isp1763 platform device. And also resets the
   *  internal data structures.
   *
   *  Input: void
   *  Output result
   *         0= complete
   *         1= error.
   *
   *  Called by: system function module_init
   *
   *
   *
   -------------------------------------------------------------------*/
  static int __init
  isp1763_module_init(void)
  {
  	int result = 0;
  	hal_entry("%s: Entered\n", __FUNCTION__);
  	pr_debug(KERN_NOTICE "+isp1763_module_init\n");
  	memset(isp1763_loc_dev, 0, sizeof(isp1763_loc_dev));
  
  	result = platform_driver_probe(&isp1763_usb_driver, isp1763_probe);
  
  	pr_debug(KERN_NOTICE "-isp1763_module_init\n");
  	hal_entry("%s: Exit\n", __FUNCTION__);
  	return result;
  }
  
  /*--------------------------------------------------------------*
   *
   *  Module dtatils: isp1763_module_cleanup
   *
   * This  is the module cleanup function. It de-registers the
   * Platform driver and resets the internal data structures.
   *
   *  Input: void
   *  Output void
   *
   *  Called by: system function module_cleanup
   *
   *
   *
   --------------------------------------------------------------*/
  
  static void __exit
  isp1763_module_cleanup(void)
  {
  	pr_debug("Hal Module Cleanup\n");
  	platform_driver_unregister(&isp1763_usb_driver);
  
  	memset(isp1763_loc_dev, 0, sizeof(isp1763_loc_dev));
  }
  
  void dummy_mem_read(struct isp1763_dev *dev)
  {
  	u32 w = 0;
  	isp1763_reg_write16(dev, HC_MEM_READ_REG, 0x0400);
  	w = isp1763_reg_read16(dev, HC_DATA_REG, w);
  
  	pr_debug("dummy_read DONE: %x\n", w);
  	msleep(10);
  }
  /*--------------------------------------------------------------*
   *
   *  Module dtatils: isp1763_probe
   *
   * probe function of ISP1763
   * This function is called from module_init if the corresponding platform
   * device is present. This function initializes the information
   * for the Host Controller with the assigned resources and tests the register
   * access to the controller and do a software reset and makes it ready
   * for the driver to play with. It also calls setup_gpio passed from pdata
   * to setup GPIOs (e.g. used for IRQ and RST lines).
   *
   *  Input:
   *              struct platform_device *dev   ----> Platform Device structure
   *  Output void
   *
   *  Called by: system function module_cleanup
   *
   *
   *
   --------------------------------------------------------------**/
  
  static int __devinit
  isp1763_probe(struct platform_device *pdev)
  {
  	u32 reg_data = 0;
  	struct isp1763_dev *loc_dev;
  	int status = 1;
  	u32 hwmodectrl = 0;
  	u16 us_reset_hc = 0;
  	u32 chipid = 0;
  	struct isp1763_platform_data *pdata = pdev->dev.platform_data;
  
  	hal_entry("%s: Entered\n", __FUNCTION__);
  
  	hal_init(("isp1763_probe(dev=%p)\n", dev));
  
  	loc_dev = &(isp1763_loc_dev[ISP1763_HC]);
  	loc_dev->dev = pdev;
  
  	/* Get the Host Controller IO and INT resources */
  	loc_dev->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (!loc_dev->mem_res) {
  		pr_err("%s: failed to get platform resource mem\n", __func__);
  		return -ENODEV;
  	}
  
  	loc_dev->baseaddress = ioremap_nocache(loc_dev->mem_res->start,
  					resource_size(loc_dev->mem_res));
  	if (!loc_dev->baseaddress) {
  		pr_err("%s: ioremap failed\n", __func__);
  		status = -ENOMEM;
  		goto put_mem_res;
  	}
  	pr_info("%s: ioremap done at: %x\n", __func__,
  					(int)loc_dev->baseaddress);
  	loc_dev->irq = platform_get_irq(pdev, 0);
  	if (!loc_dev->irq) {
  		pr_err("%s: platform_get_irq failed\n", __func__);
  		status = -ENODEV;
  		goto free_regs;
  	}
  
  	loc_dev->index = ISP1763_HC;	/*zero */
  	loc_dev->length = resource_size(loc_dev->mem_res);
  
  	hal_init(("isp1763 HC MEM Base= %p irq = %d\n",
  		loc_dev->baseaddress, loc_dev->irq));
  
  	/* Setup GPIOs and isssue RESET_N to Controller */
  	if (pdata->setup_gpio)
  		if (pdata->setup_gpio(1))
  			pr_err("%s: Failed to setup GPIOs for isp1763\n",
  								 __func__);
  	if (pdata->reset_gpio) {
  		gpio_set_value(pdata->reset_gpio, 0);
  		msleep(10);
  		gpio_set_value(pdata->reset_gpio, 1);
  	} else {
  		pr_err("%s: Failed to issue RESET_N to isp1763\n", __func__);
  	}
  
  	dummy_mem_read(loc_dev);
  
  	chipid = isp1763_reg_read32(loc_dev, DC_CHIPID, chipid);
  	pr_info("START: chip id:%x\n", chipid);
  
  	/*reset the host controller  */
  	pr_debug("RESETTING\n");
  	us_reset_hc |= 0x1;
  	isp1763_reg_write16(loc_dev, 0xB8, us_reset_hc);
  	msleep(20);
  	us_reset_hc = 0;
  	us_reset_hc |= 0x2;
  	isp1763_reg_write16(loc_dev, 0xB8, us_reset_hc);
  
  	chipid = isp1763_reg_read32(loc_dev, DC_CHIPID, chipid);
  	pr_info("after HC reset, chipid:%x\n", chipid);
  
  	msleep(20);
  	hwmodectrl = isp1763_reg_read16(loc_dev, HC_HWMODECTRL_REG, hwmodectrl);
  	pr_debug("Mode Ctrl Value b4 setting buswidth: %x\n", hwmodectrl);
  #ifdef DATABUS_WIDTH_16
  	hwmodectrl &= 0xFFEF;	/*enable the 16 bit bus */
  #else
  	pr_debug("Setting 8-BIT mode\n");
  	hwmodectrl |= 0x0010;	/*enable the 8 bit bus */
  #endif
  	isp1763_reg_write16(loc_dev, HC_HWMODECTRL_REG, hwmodectrl);
  	pr_debug("writing 0x%x to hw mode reg\n", hwmodectrl);
  
  	hwmodectrl = isp1763_reg_read16(loc_dev, HC_HWMODECTRL_REG, hwmodectrl);
  	msleep(100);
  
  	pr_debug("Mode Ctrl Value after setting buswidth: %x\n", hwmodectrl);
  
  
  	chipid = isp1763_reg_read32(loc_dev, DC_CHIPID, chipid);
  	pr_debug("after setting HW MODE to 8bit, chipid:%x\n", chipid);
  
  
  
  	hal_init(("isp1763 DC MEM Base= %lx irq = %d\n",
  		loc_dev->io_base, loc_dev->irq));
  	reg_data = isp1763_reg_read16(loc_dev, HC_SCRATCH_REG, reg_data);
  	pr_debug("Scratch register is 0x%x\n", reg_data);
  	reg_data = 0xABCD;
  	isp1763_reg_write16(loc_dev, HC_SCRATCH_REG, reg_data);
  	reg_data = isp1763_reg_read16(loc_dev, HC_SCRATCH_REG, reg_data);
  	pr_debug("After write, Scratch register is 0x%x\n", reg_data);
  
  	if (reg_data != 0xABCD) {
  		pr_err("%s: Scratch register write mismatch!!\n", __func__);
  		status = -ENODEV;
  		goto free_gpios;
  	}
  
  	memcpy(loc_dev->name, ISP1763_DRIVER_NAME, sizeof(ISP1763_DRIVER_NAME));
  	loc_dev->name[sizeof(ISP1763_DRIVER_NAME)] = 0;
  
  	pr_debug(KERN_NOTICE "-isp1763_pci_probe\n");
  	hal_entry("%s: Exit\n", __FUNCTION__);
  	return 0;
  
  free_gpios:
  	if (pdata->setup_gpio)
  		pdata->setup_gpio(0);
  free_regs:
  	iounmap(loc_dev->baseaddress);
  put_mem_res:
  	loc_dev->baseaddress = NULL;
  	hal_entry("%s: Exit\n", __FUNCTION__);
  	return status;
  }				/* End of isp1763_probe */
  
  
  /*--------------------------------------------------------------*
   *
   *  Module details: isp1763_remove
   *
   * cleanup function of ISP1763
   * This functions de-initializes the local variables, frees GPIOs
   * and releases memory resource.
   *
   *  Input:
   *              struct platform_device *dev    ----> Platform Device structure
   *
   *  Output void
   *
   *  Called by: system function module_cleanup
   *
   *
   *
   --------------------------------------------------------------*/
  static int __devexit
  isp1763_remove(struct platform_device *pdev)
  {
  	struct isp1763_dev *loc_dev;
  	struct isp1763_platform_data *pdata = pdev->dev.platform_data;
  
  	hal_init(("isp1763_pci_remove(dev=%p)\n", dev));
  
  	loc_dev = &isp1763_loc_dev[ISP1763_HC];
  	iounmap(loc_dev->baseaddress);
  	loc_dev->baseaddress = NULL;
  	if (pdata->setup_gpio)
  		return pdata->setup_gpio(0);
  
  	return 0;
  }				/* End of isp1763_remove */
  
  
  MODULE_AUTHOR(DRIVER_AUTHOR);
  MODULE_DESCRIPTION(DRIVER_DESC);
  MODULE_LICENSE("GPL");
  
  module_init(isp1763_module_init);
  module_exit(isp1763_module_cleanup);
  