[][openwrt][mt7988][crypto][Add scatterlist API in DDK for look-aside mode]
[Description]
Add scatterlist API in DDK for look-aside mode.
[Release-log]
N/A
Change-Id: I869b4b79ba2af94211661d77bb3592ea32f7ea14
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/8839606
diff --git a/feed/kernel/crypto-eip/src/ddk/device/dmares_gen.c b/feed/kernel/crypto-eip/src/ddk/device/dmares_gen.c
index 6fedd9f..7c2c8a5 100644
--- a/feed/kernel/crypto-eip/src/ddk/device/dmares_gen.c
+++ b/feed/kernel/crypto-eip/src/ddk/device/dmares_gen.c
@@ -864,6 +864,53 @@
HWPAL_DMAResource_UnInit();
}
+int
+DMAResource_SG_Alloc(
+ const DMAResource_Properties_t RequestedProperties,
+ dma_addr_t DmaAddress,
+ DMAResource_AddrPair_t * const AddrPair_p,
+ DMAResource_Handle_t * const Handle_p)
+{
+ HWPAL_DMAResource_Properties_Ext_t PoolPropertiesExt;
+
+#ifdef HWPAL_DMARESOURCE_BANKS_ENABLE
+ HWPAL_DMAResource_Bank_t * Bank_p;
+#endif
+
+ ZEROINIT(PoolPropertiesExt);
+
+#ifdef HWPAL_DMARESOURCE_BANKS_ENABLE
+ // Find the bank
+ Bank_p = DMAResourceLib_DMAPool_Bank_Get(RequestedProperties.Bank);
+ if (Bank_p == NULL)
+ {
+ LOG_CRIT("DMAResource_Alloc: failed for unsupported bank %d\n",
+ (int)RequestedProperties.Bank);
+ return -1; // Bank not supported
+ }
+
+ if (Bank_p->BankType == HWPAL_DMARESOURCE_BANK_DYNAMIC)
+ // Handle non-static banks
+ return HWPAL_SG_DMAResource_Alloc(RequestedProperties,
+ PoolPropertiesExt,
+ DmaAddress,
+ AddrPair_p,
+ Handle_p);
+ else {
+ LOG_WARN(
+ "DMAResource_SG_Alloc: "
+ "Non-static banks not support\n"
+ );
+ return -1;
+ }
+#else
+ return HWPAL_SG_DMAResource_Alloc(RequestedProperties,
+ PoolPropertiesExt,
+ DmaAddress,
+ AddrPair_p,
+ Handle_p);
+#endif // HWPAL_DMARESOURCE_BANKS_ENABLE
+}
/*----------------------------------------------------------------------------
* DMAResource_Alloc
@@ -1002,6 +1049,40 @@
#endif // HWPAL_DMARESOURCE_BANKS_ENABLE
}
+int
+DMAResource_SG_Release(
+ const DMAResource_Handle_t Handle)
+{
+#ifdef HWPAL_DMARESOURCE_BANKS_ENABLE
+ HWPAL_DMAResource_Bank_t * Bank_p;
+ DMAResource_Record_t * Rec_p;
+
+ Rec_p = DMAResource_Handle2RecordPtr(Handle);
+ if (Rec_p == NULL)
+ {
+ //LOG_CRIT("DMAResource_SG_Release: invalid handle %p\n", Handle);
+ return -1;
+ }
+
+ // Find the bank
+ Bank_p = DMAResourceLib_DMAPool_Bank_Get(Rec_p->Props.Bank);
+ if (Bank_p == NULL)
+ {
+ LOG_CRIT("DMAResource_SG_Release: failed for unsupported bank %d\n",
+ (int)Rec_p->Props.Bank);
+ return -1; // Bank not supported
+ }
+
+ // Handle non-static banks
+ if (Bank_p->BankType == HWPAL_DMARESOURCE_BANK_DYNAMIC)
+ return HWPAL_DMAResource_SG_Release(Handle);
+ else
+ {
+ LOG_CRIT("DMAResource_SG_Release: static banks not supported\n");
+ return -1;
+ }
+#endif // HWPAL_DMARESOURCE_BANKS_ENABLE
+}
/*----------------------------------------------------------------------------
* DMAResource_Release
diff --git a/feed/kernel/crypto-eip/src/ddk/device/lkm/dmares_lkm.c b/feed/kernel/crypto-eip/src/ddk/device/lkm/dmares_lkm.c
index 7fc041f..49d183a 100644
--- a/feed/kernel/crypto-eip/src/ddk/device/lkm/dmares_lkm.c
+++ b/feed/kernel/crypto-eip/src/ddk/device/lkm/dmares_lkm.c
@@ -575,6 +575,132 @@
#endif
}
+int
+HWPAL_SG_DMAResource_Alloc(
+ const DMAResource_Properties_t RequestedProperties,
+ const HWPAL_DMAResource_Properties_Ext_t RequestedPropertiesExt,
+ dma_addr_t DmaAddress,
+ DMAResource_AddrPair_t * const AddrPair_p,
+ DMAResource_Handle_t * const Handle_p)
+{
+ DMAResource_Properties_t ActualProperties;
+ DMAResource_AddrPair_t * Pair_p;
+ DMAResource_Handle_t Handle;
+ DMAResource_Record_t * Rec_p = NULL;
+
+ unsigned int AlignTo = RequestedProperties.Alignment;
+
+ ZEROINIT(ActualProperties);
+
+#ifdef HWPAL_DMARESOURCE_STRICT_ARGS_CHECKS
+ if ((NULL == AddrPair_p) || (NULL == Handle_p))
+ return -1;
+
+ if (!DMAResourceLib_IsSaneInput(NULL, NULL, &RequestedProperties))
+ return -1;
+#endif
+ // Allocate record
+ Handle = DMAResource_CreateRecord();
+ if (NULL == Handle)
+ return -1;
+
+ Rec_p = DMAResource_Handle2RecordPtr(Handle);
+ if (NULL == Rec_p)
+ {
+ DMAResource_DestroyRecord(Handle);
+ return -1;
+ }
+
+ ActualProperties.Bank = RequestedProperties.Bank;
+
+#ifdef HWPAL_ARCH_COHERENT
+ ActualProperties.fCached = false;
+#else
+ ActualProperties.fCached = true;
+#endif // HWPAL_ARCH_COHERENT
+
+#ifdef HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
+ ActualProperties.fCached = false;
+#endif // HWPAL_DMARESOURCE_ALLOC_CACHE_COHERENT
+
+ if (ActualProperties.fCached &&
+ HWPAL_DMAResource_DCache_Alignment_Get() > AlignTo)
+ {
+ AlignTo = HWPAL_DMAResource_DCache_Alignment_Get();
+ }
+
+ ActualProperties.Alignment = AlignTo;
+
+ // Hide the allocated size from the caller, since (s)he is not
+ // supposed to access/use any space beyond what was requested
+ ActualProperties.Size = RequestedProperties.Size;
+
+ Rec_p->BankType = RequestedPropertiesExt.BankType;
+
+ // Allocate DMA resource
+ {
+ struct device * DMADevice_p;
+ size_t n = 0;
+ void * UnalignedAddr_p = NULL;
+ //void * AlignedAddr_p = NULL;
+ //dma_addr_t DMAAddr = 0;
+ //phys_addr_t PhysAddr = 0;
+ Device_Data_t DevData;
+
+ ZEROINIT(DevData);
+
+ // Get device reference for this resource
+ DMADevice_p = Device_GetReference(NULL, &DevData);
+ {
+ gfp_t flags = HWPAL_DMA_FLAGS;
+
+ // Non-fixed dynamic address buffer allocation
+
+ // Align if required
+ n = DMAResourceLib_AlignForAddress(
+ DMAResourceLib_AlignForSize(RequestedProperties.Size,
+ AlignTo),
+ AlignTo);
+
+ if (in_atomic())
+ flags |= GFP_ATOMIC; // non-sleepable
+ else
+ flags |= GFP_KERNEL; // sleepable
+
+ UnalignedAddr_p = kmalloc(n, flags);
+ if (UnalignedAddr_p == NULL)
+ {
+ LOG_CRIT("DMAResource_Alloc: failed for handle 0x%p,"
+ " size %d\n",
+ Handle,(unsigned int)n);
+ DMAResource_DestroyRecord(Handle);
+ return -1;
+ }
+ }
+
+ DMAResourceLib_Setup_Record(&ActualProperties, 'A', Rec_p, n);
+
+ Pair_p = Rec_p->AddrPairs;
+ Pair_p->Address_p = (void *)(uintptr_t) DmaAddress;
+ Pair_p->Domain = DMARES_DOMAIN_BUS;
+
+ ++Pair_p;
+ Pair_p->Address_p = UnalignedAddr_p;
+ Pair_p->Domain = DMARES_DOMAIN_HOST;
+
+ // Return this address
+ *AddrPair_p = *Pair_p;
+
+ // This host address will be used for freeing the allocated buffer
+ ++Pair_p;
+ Pair_p->Address_p = UnalignedAddr_p;
+ Pair_p->Domain = DMARES_DOMAIN_HOST_UNALIGNED;
+ }
+
+ *Handle_p = Handle;
+
+ return 0;
+}
/*----------------------------------------------------------------------------
* HWPAL_DMAResource_Alloc
@@ -921,6 +1047,61 @@
return 0;
}
+int
+HWPAL_DMAResource_SG_Release(
+ const DMAResource_Handle_t Handle)
+{
+ DMAResource_Record_t * Rec_p;
+
+#ifdef HWPAL_TRACE_DMARESOURCE_BUF
+ void* UnalignedAddr_p = NULL;
+#endif
+
+ Rec_p = DMAResource_Handle2RecordPtr(Handle);
+ if (Rec_p == NULL)
+ {
+ LOG_WARN(
+ "HW_DMAResource_SG_Release: "
+ "Invalid handle %p\n",
+ Handle);
+ return -1;
+ }
+
+ // request the kernel to unmap the DMA resource
+ if (Rec_p->AllocatorRef == 'A' || Rec_p->AllocatorRef == 'k' ||
+ Rec_p->AllocatorRef == 'R')
+ {
+ DMAResource_AddrPair_t * Pair_p;
+
+ Pair_p = DMAResourceLib_LookupDomain(Rec_p, DMARES_DOMAIN_BUS);
+ if (Pair_p == NULL)
+ {
+ LOG_WARN(
+ "HW_DMAResource_SG_Release: "
+ "No bus address found for Handle %p?\n",
+ Handle);
+ return -1;
+ }
+
+ Pair_p = DMAResourceLib_LookupDomain(Rec_p,
+ DMARES_DOMAIN_HOST_UNALIGNED);
+ if (Pair_p == NULL)
+ {
+ LOG_WARN(
+ "HW_DMAResource_SG_Release: "
+ "No host address found for Handle %p?\n",
+ Handle);
+ return -1;
+ }
+
+ kfree(Pair_p->Address_p);
+ }
+ // free administration resources
+ Rec_p->Magic = 0;
+ DMAResource_DestroyRecord(Handle);
+
+ return 0;
+}
/*----------------------------------------------------------------------------
* HWPAL_DMAResource_Release
@@ -1969,10 +2150,10 @@
Rec_p = DMAResource_Handle2RecordPtr(Handle);
if (Rec_p == NULL)
{
- LOG_WARN(
- "DMAResource_PreDMA: "
- "Invalid handle %p\n",
- Handle);
+ //LOG_WARN(
+ // "DMAResource_PreDMA: "
+ // "Invalid handle %p\n",
+ // Handle);
return;
}
@@ -2089,10 +2270,10 @@
Rec_p = DMAResource_Handle2RecordPtr(Handle);
if (Rec_p == NULL)
{
- LOG_WARN(
- "DMAResource_PostDMA: "
- "Invalid handle %p\n",
- Handle);
+ //LOG_WARN(
+ // "DMAResource_PostDMA: "
+ // "Invalid handle %p\n",
+ // Handle);
return;
}
diff --git a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/configs/cs_driver.h b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/configs/cs_driver.h
index 13401a1..17e4ccf 100644
--- a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/configs/cs_driver.h
+++ b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/configs/cs_driver.h
@@ -64,7 +64,7 @@
#define DRIVER_INTERRUPT_COALESCING
#define DRIVER_BOUNCEBUFFERS
//#define DRIVER_PERFORMANCE
-//#define DRIVER_SCATTERGATHER
+#define DRIVER_SCATTERGATHER
#define DRIVER_PEC_MAX_SAS 64
#define DRIVER_PEC_MAX_PACKETS 32
#define DRIVER_MAX_PECLOGICDESCR 32
diff --git a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/device/dmares_hwpal.h b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/device/dmares_hwpal.h
index e94ee77..b4abd7d 100644
--- a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/device/dmares_hwpal.h
+++ b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/device/dmares_hwpal.h
@@ -137,6 +137,13 @@
DMAResource_AddrPair_t * const AddrPair_p,
DMAResource_Handle_t * const Handle_p);
+int
+HWPAL_SG_DMAResource_Alloc(
+ const DMAResource_Properties_t RequestedProperties,
+ const HWPAL_DMAResource_Properties_Ext_t RequestedPropertiesExt,
+ dma_addr_t DmaAddress,
+ DMAResource_AddrPair_t * const AddrPair_p,
+ DMAResource_Handle_t * const Handle_p);
/*----------------------------------------------------------------------------
* HWPAL_DMAResource_Release
@@ -145,6 +152,9 @@
HWPAL_DMAResource_Release(
const DMAResource_Handle_t Handle);
+int
+HWPAL_DMAResource_SG_Release(
+ const DMAResource_Handle_t Handle);
/*----------------------------------------------------------------------------
* HWPAL_DMAResource_Init
diff --git a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/dmares/dmares_buf.h b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/dmares/dmares_buf.h
index 0d3ad08..f4dfd8c 100644
--- a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/dmares/dmares_buf.h
+++ b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/dmares/dmares_buf.h
@@ -60,6 +60,12 @@
DMAResource_AddrPair_t * const AddrPair_p,
DMAResource_Handle_t * const Handle_p);
+int
+DMAResource_SG_Alloc(
+ const DMAResource_Properties_t RequestedProperties,
+ dma_addr_t DmaAddress,
+ DMAResource_AddrPair_t * const AddrPair_p,
+ DMAResource_Handle_t * const Handle_p);
/*----------------------------------------------------------------------------
* DMAResource_CheckAndRegister
@@ -166,6 +172,9 @@
DMAResource_Release(
const DMAResource_Handle_t Handle);
+int
+DMAResource_SG_Release(
+ const DMAResource_Handle_t Handle);
/*----------------------------------------------------------------------------
* DMAResource_SwapEndianness_Set
diff --git a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/kit/builder/sa/sa_builder_params.h b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/kit/builder/sa/sa_builder_params.h
index 5f1b77e..4929c10 100644
--- a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/kit/builder/sa/sa_builder_params.h
+++ b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/kit/builder/sa/sa_builder_params.h
@@ -117,7 +117,7 @@
SAB_CRYPTO_MODE_UEA2, /* Only with SNOW */
SAB_CRYPTO_MODE_EEA3, /* Only with ZUC */
SAB_CRYPTO_MODE_CHACHA_CTR32, /* Only with Chacha20 */
- SAB_CRYPTO_MODE_CHACHA_CTR64, /* Only with Chacha20 */w
+ SAB_CRYPTO_MODE_CHACHA_CTR64, /* Only with Chacha20 */
} SABuilder_Crypto_Mode_t;
/* Specify one of the IV sources. Not all methods are supported with all
diff --git a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/slad/api_dmabuf.h b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/slad/api_dmabuf.h
index ab20069..b24e0a7 100644
--- a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/slad/api_dmabuf.h
+++ b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/slad/api_dmabuf.h
@@ -160,7 +160,12 @@
DMABuf_HostAddress_t * const Buffer_p,
DMABuf_Handle_t * const Handle_p);
-
+DMABuf_Status_t
+DMABuf_Particle_Alloc(
+ const DMABuf_Properties_t RequestedProperties,
+ dma_addr_t DmaAddress,
+ DMABuf_HostAddress_t * const Buffer_p,
+ DMABuf_Handle_t * const Handle_p);
/*----------------------------------------------------------------------------
* DMABuf_Register
*
@@ -226,6 +231,9 @@
DMABuf_Release(
DMABuf_Handle_t Handle);
+DMABuf_Status_t
+DMABuf_Particle_Release(
+ DMABuf_Handle_t Handle);
#endif /* Include Guard */
diff --git a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/slad/lkm/adapter_driver197_init_ext.h b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/slad/lkm/adapter_driver197_init_ext.h
index bc24a70..3cb9dcb 100644
--- a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/slad/lkm/adapter_driver197_init_ext.h
+++ b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/slad/lkm/adapter_driver197_init_ext.h
@@ -105,8 +105,10 @@
EXPORT_SYMBOL(DMABuf_NULLHandle);
EXPORT_SYMBOL(DMABuf_Handle_IsSame);
EXPORT_SYMBOL(DMABuf_Alloc);
+EXPORT_SYMBOL(DMABuf_Particle_Alloc);
EXPORT_SYMBOL(DMABuf_Register);
EXPORT_SYMBOL(DMABuf_Release);
+EXPORT_SYMBOL(DMABuf_Particle_Release);
EXPORT_SYMBOL(Device_Find);
diff --git a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/slad/lkm/adapter_driver197_pec_init_ext.h b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/slad/lkm/adapter_driver197_pec_init_ext.h
index e3b4fa9..14218f9 100644
--- a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/slad/lkm/adapter_driver197_pec_init_ext.h
+++ b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/slad/lkm/adapter_driver197_pec_init_ext.h
@@ -48,8 +48,10 @@
EXPORT_SYMBOL(DMABuf_NULLHandle);
EXPORT_SYMBOL(DMABuf_Handle_IsSame);
EXPORT_SYMBOL(DMABuf_Alloc);
+EXPORT_SYMBOL(DMABuf_Particle_Alloc);
EXPORT_SYMBOL(DMABuf_Register);
EXPORT_SYMBOL(DMABuf_Release);
+EXPORT_SYMBOL(DMABuf_Particle_Release);
// PEC API LKM implementation extensions
diff --git a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/slad/lkm/adapter_driver97_init_ext.h b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/slad/lkm/adapter_driver97_init_ext.h
index f01b150..4b1003b 100644
--- a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/slad/lkm/adapter_driver97_init_ext.h
+++ b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/slad/lkm/adapter_driver97_init_ext.h
@@ -48,6 +48,7 @@
EXPORT_SYMBOL(DMABuf_NULLHandle);
EXPORT_SYMBOL(DMABuf_Handle_IsSame);
EXPORT_SYMBOL(DMABuf_Alloc);
+EXPORT_SYMBOL(DMABuf_Particle_Alloc);
EXPORT_SYMBOL(DMABuf_Register);
EXPORT_SYMBOL(DMABuf_Release);
diff --git a/feed/kernel/crypto-eip/src/ddk/slad/adapter_dmabuf.c b/feed/kernel/crypto-eip/src/ddk/slad/adapter_dmabuf.c
index 790f478..d2ce76d 100644
--- a/feed/kernel/crypto-eip/src/ddk/slad/adapter_dmabuf.c
+++ b/feed/kernel/crypto-eip/src/ddk/slad/adapter_dmabuf.c
@@ -277,6 +277,63 @@
}
}
+DMABuf_Status_t
+DMABuf_Particle_Alloc(
+ const DMABuf_Properties_t RequestedProperties,
+ dma_addr_t DmaAddress,
+ DMABuf_HostAddress_t * const Buffer_p,
+ DMABuf_Handle_t * const Handle_p)
+{
+ DMAResource_Handle_t DMAHandle;
+ DMAResource_AddrPair_t AddrPair;
+ DMAResource_Properties_t ActualProperties;
+
+ ZEROINIT(AddrPair);
+ ZEROINIT(ActualProperties);
+
+ if (Handle_p == NULL ||
+ Buffer_p == NULL)
+ {
+ return DMABUF_ERROR_BAD_ARGUMENT;
+ }
+
+ // initialize the output parameters
+ Handle_p->p = NULL;
+ Buffer_p->p = NULL;
+
+ ActualProperties.Size = RequestedProperties.Size;
+ ActualProperties.Bank = RequestedProperties.Bank;
+ ActualProperties.fCached = RequestedProperties.fCached;
+
+ if (Adapter_DMABuf_Alignment != ADAPTER_DMABUF_ALIGNMENT_INVALID &&
+ RequestedProperties.Alignment < Adapter_DMABuf_Alignment)
+ ActualProperties.Alignment = Adapter_DMABuf_Alignment;
+ else
+ ActualProperties.Alignment = RequestedProperties.Alignment;
+
+ if(!DMAResource_SG_Alloc(ActualProperties, DmaAddress, &AddrPair,&DMAHandle))
+ {
+ // set the output parameters
+ Handle_p->p = (void*)DMAHandle;
+ Buffer_p->p = AddrPair.Address_p;
+
+ LOG_INFO("DMABuf_Alloc: allocated handle=%p, host addr=%p, "
+ "alignment requested/actual %d/%d, "
+ "bank requested %d, cached requested %d\n",
+ Handle_p->p,
+ Buffer_p->p,
+ RequestedProperties.Alignment,
+ ActualProperties.Alignment,
+ RequestedProperties.Bank,
+ RequestedProperties.fCached);
+
+ return DMABUF_STATUS_OK;
+ }
+ else
+ {
+ return DMABUF_ERROR_OUT_OF_MEMORY;
+ }
+}
/*----------------------------------------------------------------------------
* DMABuf_Register
@@ -400,5 +457,23 @@
}
}
+DMABuf_Status_t
+DMABuf_Particle_Release(
+ DMABuf_Handle_t Handle)
+{
+ DMAResource_Handle_t DMAHandle =
+ Adapter_DMABuf_Handle2DMAResourceHandle(Handle);
+ LOG_INFO("DMABuf_Particle_Release: handle to release=%p\n",Handle.p);
+
+ if( DMAResource_SG_Release(DMAHandle) == 0 )
+ {
+ return DMABUF_STATUS_OK;
+ }
+ else
+ {
+ return DMABUF_ERROR_INVALID_HANDLE;
+ }
+}
+
/* end of file adapter_dmabuf.c */