//*****************************************************************************
//
//! This function is used to open an instance of the CDC driver.
//!
//! \param pDevice is a pointer to the device information structure.
//!
//! This function will attempt to open an instance of the CDC driver based on
//! the information contained in the pDevice structure.  This call can fail if
//! there are not sufficient resources to open the device.  The function will
//! return a value that should be passed back into USBCDCClose() when the
//! driver is no longer needed.
//!
//! \return The function will return a pointer to a CDC driver instance.
//
//*****************************************************************************
static void *
USBHCDCOpen(tUSBHostDevice *psDevice)
{
    //printf("USBHCDCOpen: Start\n");

    int32_t i32Idx, i32Idz;
    tEndpointDescriptor *psEndpointDescriptor;
    tInterfaceDescriptor *psInterface;

    //
    // Don't allow the device to be opened without closing first.
    //
    if(g_USBHCDCDevice.psDevice)
    {
		//printf("USBHCDCOpen: For Loop: i32Idx, %d\n", i32Idx);

        return(0);
    }

    //
    // Save the device pointer.
    //
    g_USBHCDCDevice.psDevice = psDevice;

    //
    //  Loop Through the first 3 Interfaces Searching for Endpoints
    //
    for(i32Idz = 0; i32Idz < 3; i32Idz++)
    {
		//
		// Get the interface descriptor.
		//
		psInterface = USBDescGetInterface(psDevice->psConfigDescriptor, i32Idz, 0);

		//
		// Loop through the endpoints of the device.
		// bNumEndPoints returning 1, should be 3 - will set manually, as there is always 3...then it works!!!
		//
		for(i32Idx = 0; i32Idx < 3; i32Idx++)  //psInterface->bNumEndpoints; i32Idx++)
		{
			//
			// Get the first endpoint descriptor.
			//
			psEndpointDescriptor =
				USBDescGetInterfaceEndpoint(psInterface, i32Idx,
											psDevice->ui32ConfigDescriptorSize);

			//System_printf("USBHCDCOpen: psEndPointDecriptor: %d  bmAttribute: %d\n", psEndpointDescriptor, psEndpointDescriptor->bmAttributes);
			//System_flush();

			//
			// If no more endpoints then break out.
			//
			if(psEndpointDescriptor == 0)
			{
				break;
			}

			//
			// See if this is an Interrupt endpoint.
			//
			if((psEndpointDescriptor->bmAttributes & USB_EP_ATTR_TYPE_M) == USB_EP_ATTR_INT)
			{
				//
				// Interrupt IN.
				//
				if(psEndpointDescriptor->bEndpointAddress & USB_EP_DESC_IN)
				{
					g_USBHCDCDevice.ui32IntInPipe =
							USBHCDPipeAlloc(0, USBHCD_PIPE_INTR_IN,
											psDevice, USBHCDCInterruptCallback);

					USBHCDPipeConfig(g_USBHCDCDevice.ui32IntInPipe,
								psEndpointDescriptor->wMaxPacketSize,
								psEndpointDescriptor->bInterval,
								(psEndpointDescriptor->bEndpointAddress &
								 USB_EP_DESC_NUM_M));

					//System_printf("USBHCDCOpen: Allocated and Configured Interrupt In Endpoint: Interface Index: %d  bEndPointAddress: %d  ui32BulkOutPipe: %d\n", i32Idz, psEndpointDescriptor->bEndpointAddress, g_USBHCDCDevice.ui32IntInPipe);
					//System_flush();
				}
			}

			//
			// See if this is a bulk endpoint.
			//
			if((psEndpointDescriptor->bmAttributes & USB_EP_ATTR_TYPE_M) == USB_EP_ATTR_BULK)
			{
				//
				// See if this is bulk IN or bulk OUT or Interrupt
				//
				//if((psEndpointDescriptor->bmAttributes & USB_EP_ATTR_INT) == USB_EP_ATTR_INT)
				//{
	//                //
	//                // Allocate the USB Pipe for this Bulk IN Interrupt endpoint.
	//                //
	//                g_USBHCDCDevice.ui32BulkInPipe =
	//                    USBHCDPipeAllocSize(0, USBHCD_PIPE_BULK_IN,
	//                                        psDevice,
	//                                        psEndpointDescriptor->wMaxPacketSize,
	//                                        USBHCDCInterruptCallback);
	//                //
	//                // Configure the USB pipe as a Bulk IN endpoint.
	//                //
	//                USBHCDPipeConfig(g_USBHCDCDevice.ui32BulkInPipe,
	//                                 psEndpointDescriptor->wMaxPacketSize,
	//                                 1,
	//                                 (psEndpointDescriptor->bEndpointAddress &
	//                                  USB_EP_DESC_NUM_M));
	//
	//				System_printf("USBHCDCOpen: Allocated and Configured Interrupt EndPoint**: Interface Index: %d  bEndPointAddress: %d  ui32BulkOutPipe: %d\n", i32Idz, psEndpointDescriptor->bEndpointAddress, g_USBHCDCDevice.ui32BulkOutPipe);
	//				System_flush();
    //
	//			}
				if(psEndpointDescriptor->bEndpointAddress & USB_EP_DESC_IN)
				{
					//
					// Allocate the USB Pipe for this Bulk IN endpoint.
					//
					g_USBHCDCDevice.ui32BulkInPipe =
						USBHCDPipeAllocSize(0, USBHCD_PIPE_BULK_IN,
											psDevice,
											psEndpointDescriptor->wMaxPacketSize,
											USBHCDCINCallback);
					//
					// Configure the USB pipe as a Bulk IN endpoint.
					//
					USBHCDPipeConfig(g_USBHCDCDevice.ui32BulkInPipe,
									 psEndpointDescriptor->wMaxPacketSize,
									 64,
									 (psEndpointDescriptor->bEndpointAddress &
									  USB_EP_DESC_NUM_M));

					//System_printf("USBHCDCOpen: Allocated and Configured Bulk In EndPoint: Interface Index: %d  bEndPointAddress: %d  ui32BulkOutPipe: %d\n", i32Idz, psEndpointDescriptor->bEndpointAddress, g_USBHCDCDevice.ui32BulkOutPipe);
					//System_flush();

				}
				else
				{
					//
					// Allocate the USB Pipe for this Bulk OUT endpoint.
					//
					g_USBHCDCDevice.ui32BulkOutPipe =
						USBHCDPipeAllocSize(0, USBHCD_PIPE_BULK_OUT,
											psDevice,
											psEndpointDescriptor->wMaxPacketSize,
											0);
					//
					// Configure the USB pipe as a Bulk OUT endpoint.
					//
					USBHCDPipeConfig(g_USBHCDCDevice.ui32BulkOutPipe,
									 psEndpointDescriptor->wMaxPacketSize,
									 0,
									 (psEndpointDescriptor->bEndpointAddress &
									  USB_EP_DESC_NUM_M));

					//System_printf("USBHCDCOpen: Allocated and Configured Bulk Out EndPoint: Interface Index: %d  bEndPointAddress: %d  ui32BulkOutPipe: %d\n", i32Idz, psEndpointDescriptor->bEndpointAddress, g_USBHCDCDevice.ui32BulkOutPipe);
					//System_flush();
				}
			}
		}
    }


    //
    // If there is a callback function call it to inform the application that
    // the device has been enumerated.
    //
    // To be used with the RTOS callback handler example.
    //
//    if(g_USBCDCDevice.pfnCallback != 0)
//    {
//        g_psHIDDevice[i32Dev].pfnCallback(
//                            g_psHIDDevice[i32Dev].pvCBData,
//                            USB_EVENT_CONNECTED,
//                            (uint32_t)&g_psHIDDevice[i32Dev], 0);
//    }

    //
    // If the callback exists, call it with an Open event.
    //
    if(g_USBHCDCDevice.pfnCallback != 0)
    {
       // printf("USBHCDCOpen: Callback Exists: Calling\n");
       // System_flush();

        g_USBHCDCDevice.pfnCallback(&g_USBHCDCDevice,
                                    CDC_EVENT_OPEN, 0, 0);
    }

    //
    // Return the only instance of this device.
    //
    return(&g_USBHCDCDevice);
}
//*****************************************************************************
//
//! This function is used to open an instance of the ANDROID driver and configure it as Open Accessory.
//!
//! \param pDevice is a pointer to the device information structure.
//!
//! This function will attempt to open an instance of the ANDROID driver based on
//! the information contained in the pDevice structure.  This call can fail if
//! there are not sufficient resources to open the device.  The function will
//! return a value that should be passed back into USBANDROIDClose() when the
//! driver is no longer needed.
//!
//! \return The function will return a pointer to a ANDROID driver instance.
//
//*****************************************************************************
static void * USBHANDROIDOpen(tUSBHostDevice *pDevice)
{
    int iIdx;
    tEndpointDescriptor *pEndpointDescriptor;
    tInterfaceDescriptor *pInterface;

    UARTprintf("\nStart USBHANDROIDOpen Time=%d\n", g_ulSysTickCount);

    /* For Debug purpose you can also list full Configuration Descriptor & Device Descriptor */
    getConfigDesc(pDevice);
    getDeviceDesc(pDevice);
/*
    UARTprintf("Start pDevice->pConfigDescriptor details Time=%d:\n", g_ulSysTickCount);
    UARTprintf(" bLength=0x%02X (shall be 0x09)\n", pDevice->pConfigDescriptor->bLength);
    UARTprintf(" wTotalLength=0x%04X\n", pDevice->pConfigDescriptor->wTotalLength);
    UARTprintf(" bDescriptorType=0x%02X\n", pDevice->pConfigDescriptor->bDescriptorType);
    UARTprintf(" bNumInterfaces=0x%02X\n", pDevice->pConfigDescriptor->bNumInterfaces);    
    UARTprintf(" bConfigurationValue=0x%02X\n", pDevice->pConfigDescriptor->bConfigurationValue);
    UARTprintf(" iConfiguration=0x%02X\n", pDevice->pConfigDescriptor->iConfiguration);
    UARTprintf(" bmAttributes=0x%02X\n", pDevice->pConfigDescriptor->bmAttributes);
    UARTprintf(" bMaxPower=0x%02X (unit of 2mA)\n\n", pDevice->pConfigDescriptor->bMaxPower);

    UARTprintf("pDevice->DeviceDescriptor details:\n");
    UARTprintf(" bLength=0x%02X (shall be 0x12)\n",  pDevice->DeviceDescriptor.bLength);
    UARTprintf(" bDescriptorType=0x%02X\n",  pDevice->DeviceDescriptor.bDescriptorType);
    UARTprintf(" bcdUSB=0x%02X (USB2.0=0x200)\n",  pDevice->DeviceDescriptor.bcdUSB);
    UARTprintf(" bDeviceClass=0x%02X\n",  pDevice->DeviceDescriptor.bDeviceClass);
    UARTprintf(" bDeviceSubClass=0x%02X\n",  pDevice->DeviceDescriptor.bDeviceSubClass);    
    UARTprintf(" bDeviceProtocol=0x%02X\n",  pDevice->DeviceDescriptor.bDeviceProtocol);
    UARTprintf(" bMaxPacketSize0=0x%02X\n",  pDevice->DeviceDescriptor.bMaxPacketSize0);
    UARTprintf(" idVendor=0x%02X\n",  pDevice->DeviceDescriptor.idVendor);
    UARTprintf(" idProduct=0x%02X\n",  pDevice->DeviceDescriptor.idProduct);
    UARTprintf(" bcdDevice=0x%02X\n",  pDevice->DeviceDescriptor.bcdDevice);
    UARTprintf(" iManufacturer=0x%02X\n",  pDevice->DeviceDescriptor.iManufacturer);        
    UARTprintf(" iProduct=0x%02X\n",  pDevice->DeviceDescriptor.iProduct);    
    UARTprintf(" iSerialNumber=0x%02X\n",  pDevice->DeviceDescriptor.iSerialNumber);    
    UARTprintf(" bNumConfigurations=0x%02X\n",  pDevice->DeviceDescriptor.bNumConfigurations);
    UARTprintf("End pDevice->pConfigDescriptor details Time=%d:\n\n", g_ulSysTickCount);
*/
    // Don't allow the device to be opened without closing first.
    if(g_USBHANDROIDDevice.pDevice)
    {
        UARTprintf("\nUSBHANDROIDOpen return 0 device already opened\n");
        return(0);
    }

    // Save the device pointer.
    g_USBHANDROIDDevice.pDevice = pDevice;

    // Save the callback.
    // The CallBack is the driver callback for any Android ADK events.
    //
    // This function is called to open an instance of an android device.  It
    // should be called before any devices are connected to allow for proper
    // notification of android connection and disconnection. The
    // application should also provide the \e pfnCallback to be notified of Andoid
    // ADK related events like device enumeration and device removal.
    g_USBHANDROIDDevice.pfnCallback = USBHANDROIDCallback;
    
    /* Check Android Accessory device */
    if (isAccessoryDevice(&pDevice->DeviceDescriptor)) 
    {
        UARTprintf("Found Android Accessory device Time=%d\n", g_ulSysTickCount);

        // Get the interface descriptor.
        pInterface = USBDescGetInterface(pDevice->pConfigDescriptor, 0, 0);    

        // Loop through the endpoints of the device.
        for(iIdx = 0; iIdx < 3; iIdx++)
        {
            // Get the first endpoint descriptor.
             pEndpointDescriptor =
            USBDescGetInterfaceEndpoint(pInterface, iIdx,
            pDevice->ulConfigDescriptorSize);
            
            UARTprintf("\nEndpoint%d USBDescGetInterfaceEndpoint()=pEndpointDescriptor res=0x%08X\n", iIdx, pEndpointDescriptor);

            // If no more endpoints then break out.
            if(pEndpointDescriptor == 0)
            {
                break;
            }
            UARTprintf("pEndpointDescriptor details:\n");
            UARTprintf(" bLength=0x%02X (shall be 0x07)\n", pEndpointDescriptor->bLength);
            UARTprintf(" bDescriptorType=0x%02X\n", pEndpointDescriptor->bDescriptorType);
            UARTprintf(" bEndpointAddress=0x%02X\n", pEndpointDescriptor->bEndpointAddress);
            UARTprintf(" bmAttributes=0x%02X (0x00=CTRL, 0x01=ISOC, 0x02=BULK, 0x03=INT\n", pEndpointDescriptor->bmAttributes);
            UARTprintf(" wMaxPacketSize=0x%04X\n", pEndpointDescriptor->wMaxPacketSize);
            UARTprintf(" bInterval=0x%04X\n", pEndpointDescriptor->bInterval);

            // See if this is a bulk endpoint.
            if((pEndpointDescriptor->bmAttributes & USB_EP_ATTR_TYPE_M) ==
                    USB_EP_ATTR_BULK)
            {
                // See if this is bulk IN or bulk OUT.
                if(pEndpointDescriptor->bEndpointAddress & USB_EP_DESC_IN)
                {
                    UARTprintf("Endpoint Bulk In alloc USB Pipe\n");
                    // Allocate the USB Pipe for this Bulk IN endpoint.
                    g_USBHANDROIDDevice.ulBulkInPipe = USBHCDPipeAllocSize(0, USBHCD_PIPE_BULK_IN_DMA,
                                                                           pDevice->ulAddress,
                                                                           pEndpointDescriptor->wMaxPacketSize,
                                                                           0);
                    // Configure the USB pipe as a Bulk IN endpoint.
                    USBHCDPipeConfig(g_USBHANDROIDDevice.ulBulkInPipe,
                                     pEndpointDescriptor->wMaxPacketSize,
                                     BULK_READ_TIMEOUT,
                                     (pEndpointDescriptor->bEndpointAddress &
                                     USB_EP_DESC_NUM_M));
                }
                else
                {
                    UARTprintf("Endpoint Bulk OUT alloc USB Pipe\n");
                    // Allocate the USB Pipe for this Bulk OUT endpoint.
                    g_USBHANDROIDDevice.ulBulkOutPipe = USBHCDPipeAllocSize(0, USBHCD_PIPE_BULK_OUT_DMA,
                                                                            pDevice->ulAddress,
                                                                            pEndpointDescriptor->wMaxPacketSize,
                                                                            0);
                    // Configure the USB pipe as a Bulk OUT endpoint.
                    USBHCDPipeConfig(g_USBHANDROIDDevice.ulBulkOutPipe,
                                     pEndpointDescriptor->wMaxPacketSize,
                                     BULK_WRITE_TIMEOUT,
                                     (pEndpointDescriptor->bEndpointAddress &
                                     USB_EP_DESC_NUM_M));
                }
            }
        }

        // If the callback exists, call it with an Open event.
        if(g_USBHANDROIDDevice.pfnCallback != 0)
        {
            g_USBHANDROIDDevice.pfnCallback((t_u32)&g_USBHANDROIDDevice,
            ANDROID_EVENT_OPEN, 0);
        }
        
        // Set Flag isConnected
        g_USBHANDROIDDevice.connected = true;
    } else 
    {
        UARTprintf("Found possible device. switching to serial mode Time=%d\n", g_ulSysTickCount);
        switchDevice(pDevice);
        
        // Set Flag isConnected
        g_USBHANDROIDDevice.connected = false;  
    }

    UARTprintf("\nEnd USBHANDROIDOpen Time=%d\n", g_ulSysTickCount);        
    // Return the only instance of this device.
    return(&g_USBHANDROIDDevice);
}
Beispiel #3
0
//*****************************************************************************
//
//! This function is used to open an instance of the MSC driver.
//!
//! \param pDevice is a pointer to the device information structure.
//!
//! This function will attempt to open an instance of the MSC driver based on
//! the information contained in the pDevice structure.  This call can fail if
//! there are not sufficient resources to open the device.  The function will
//! return a value that should be passed back into USBMSCClose() when the
//! driver is no longer needed.
//!
//! \return The function will return a pointer to a MSC driver instance.
//
//*****************************************************************************
static void *
USBHMSCOpen(tUSBHostDevice *pDevice)
{
    long lIdx;
    tEndpointDescriptor *pEndpointDescriptor;
    tInterfaceDescriptor *pInterface;

    //
    // Don't allow the device to be opened without closing first.
    //
    if(g_USBHMSCDevice.pDevice)
    {
        return(0);
    }

    //
    // Save the device pointer.
    //
    g_USBHMSCDevice.pDevice = pDevice;

    //
    // Get the interface descriptor.
    //
    pInterface = USBDescGetInterface(pDevice->pConfigDescriptor, 0, 0);

    //
    // Loop through the endpoints of the device.
    //
    for(lIdx = 0; lIdx < 3; lIdx++)
    {
        //
        // Get the first endpoint descriptor.
        //
        pEndpointDescriptor =
            USBDescGetInterfaceEndpoint(pInterface, lIdx,
                                        pDevice->ulConfigDescriptorSize);

        //
        // If no more endpoints then break out.
        //
        if(pEndpointDescriptor == 0)
        {
            break;
        }

        //
        // See if this is a bulk endpoint.
        //
        if((pEndpointDescriptor->bmAttributes & USB_EP_ATTR_TYPE_M) ==
           USB_EP_ATTR_BULK)
        {
            //
            // See if this is bulk IN or bulk OUT.
            //
            if(pEndpointDescriptor->bEndpointAddress & USB_EP_DESC_IN)
            {
                //
                // Allocate the USB Pipe for this Bulk IN endpoint.
                //
                g_USBHMSCDevice.ulBulkInPipe =
                    USBHCDPipeAllocSize(0, USBHCD_PIPE_BULK_IN_DMA,
                                        pDevice->ulAddress,
                                        pEndpointDescriptor->wMaxPacketSize,
                                        0);
                //
                // Configure the USB pipe as a Bulk IN endpoint.
                //
                USBHCDPipeConfig(g_USBHMSCDevice.ulBulkInPipe,
                                 pEndpointDescriptor->wMaxPacketSize,
                                 0,
                                 (pEndpointDescriptor->bEndpointAddress &
                                  USB_EP_DESC_NUM_M));
            }
            else
            {
                //
                // Allocate the USB Pipe for this Bulk OUT endpoint.
                //
                g_USBHMSCDevice.ulBulkOutPipe =
                    USBHCDPipeAllocSize(0, USBHCD_PIPE_BULK_OUT_DMA,
                                        pDevice->ulAddress,
                                        pEndpointDescriptor->wMaxPacketSize,
                                        0);
                //
                // Configure the USB pipe as a Bulk OUT endpoint.
                //
                USBHCDPipeConfig(g_USBHMSCDevice.ulBulkOutPipe,
                                 pEndpointDescriptor->wMaxPacketSize,
                                 0,
                                 (pEndpointDescriptor->bEndpointAddress &
                                  USB_EP_DESC_NUM_M));
            }
        }
    }

    //
    // If the callback exists, call it with an Open event.
    //
    if(g_USBHMSCDevice.pfnCallback != 0)
    {
        g_USBHMSCDevice.pfnCallback((unsigned long)&g_USBHMSCDevice,
                                    MSC_EVENT_OPEN, 0);
    }

    //
    // Return the only instance of this device.
    //
    return(&g_USBHMSCDevice);
}
Beispiel #4
0
//*****************************************************************************
//
//! This function is used to open an instance of the MSC driver.
//!
//! \param psDevice is a pointer to the device information structure.
//!
//! This function will attempt to open an instance of the MSC driver based on
//! the information contained in the \e psDevice structure.  This call can fail
//! if there are not sufficient resources to open the device.  The function
//! returns a value that should be passed back into USBMSCClose() when the
//! driver is no longer needed.
//!
//! \return The function will return a pointer to a MSC driver instance.
//
//*****************************************************************************
static void *
USBHMSCOpen(tUSBHostDevice *psDevice)
{
    int32_t i32Idx;
    tEndpointDescriptor *psEndpointDescriptor;
    tInterfaceDescriptor *psInterface;

    //
    // Don't allow the device to be opened without closing first.
    //
    if(g_sUSBHMSCDevice.psDevice)
    {
        return(0);
    }

    //
    // Save the device pointer.
    //
    g_sUSBHMSCDevice.psDevice = psDevice;

    //
    // Get the interface descriptor.
    //
    psInterface = USBDescGetInterface(psDevice->psConfigDescriptor, 0, 0);

    //
    // Loop through the endpoints of the device.
    //
    for(i32Idx = 0; i32Idx < 3; i32Idx++)
    {
        //
        // Get the first endpoint descriptor.
        //
        psEndpointDescriptor =
            USBDescGetInterfaceEndpoint(psInterface, i32Idx,
                                        psDevice->ui32ConfigDescriptorSize);

        //
        // If no more endpoints then break out.
        //
        if(psEndpointDescriptor == 0)
        {
            break;
        }

        //
        // See if this is a bulk endpoint.
        //
        if((psEndpointDescriptor->bmAttributes & USB_EP_ATTR_TYPE_M) ==
           USB_EP_ATTR_BULK)
        {
            //
            // See if this is bulk IN or bulk OUT.
            //
            if(psEndpointDescriptor->bEndpointAddress & USB_EP_DESC_IN)
            {
                //
                // Allocate the USB Pipe for this Bulk IN endpoint.
                //
                g_sUSBHMSCDevice.ui32BulkInPipe =
                    USBHCDPipeAllocSize(0, USBHCD_PIPE_BULK_IN,
                                        psDevice,
                                        readusb16_t(&(psEndpointDescriptor->wMaxPacketSize)),
                                        0);
                //
                // Configure the USB pipe as a Bulk IN endpoint.
                //
                USBHCDPipeConfig(g_sUSBHMSCDevice.ui32BulkInPipe,
                				 readusb16_t(&(psEndpointDescriptor->wMaxPacketSize)),
                                 0,
                                 (psEndpointDescriptor->bEndpointAddress &
                                  USB_EP_DESC_NUM_M));
            }
            else
            {
                //
                // Allocate the USB Pipe for this Bulk OUT endpoint.
                //
                g_sUSBHMSCDevice.ui32BulkOutPipe =
                    USBHCDPipeAllocSize(0, USBHCD_PIPE_BULK_OUT,
                                        psDevice,
                                        readusb16_t(&(psEndpointDescriptor->wMaxPacketSize)),
                                        0);
                //
                // Configure the USB pipe as a Bulk OUT endpoint.
                //
                USBHCDPipeConfig(g_sUSBHMSCDevice.ui32BulkOutPipe,
                				 readusb16_t(&(psEndpointDescriptor->wMaxPacketSize)),
                                 0,
                                 (psEndpointDescriptor->bEndpointAddress &
                                  USB_EP_DESC_NUM_M));
            }
        }
    }

    //
    // If the callback exists, call it with an Open event.
    //
    if(g_sUSBHMSCDevice.pfnCallback != 0)
    {
        g_sUSBHMSCDevice.pfnCallback(&g_sUSBHMSCDevice, MSC_EVENT_OPEN, 0);
    }


    g_sUSBHMSCDevice.ui32MaxLUN = 0xffffffff;

    //
    // Return the only instance of this device.
    //
    return(&g_sUSBHMSCDevice);
}