1 /*
2 * emmc_adapter.c
3 *
4 * linux emmc driver implement.
5 *
6 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19 #include <securec.h>
20 #include <linux/mmc/card.h>
21 #include <linux/mmc/host.h>
22 #include "device_resource_if.h"
23 #include "hdf_log.h"
24 #include "emmc_if.h"
25 #include "mmc_corex.h"
26 #include "mmc_emmc.h"
27
28 #define HDF_LOG_TAG emmc_adapter_c
29
30 struct mmc_host *GetMmcHost(int32_t slot);
31
LinuxEmmcGetCid(struct EmmcDevice * dev,uint8_t * cid,uint32_t size)32 int32_t LinuxEmmcGetCid(struct EmmcDevice *dev, uint8_t *cid, uint32_t size)
33 {
34 struct mmc_host *mmcHost = NULL;
35 struct MmcCntlr *cntlr = NULL;
36
37 if (dev == NULL || dev->mmc.cntlr == NULL) {
38 HDF_LOGE("LinuxEmmcGetCid: dev or cntlr is null.");
39 return HDF_ERR_INVALID_OBJECT;
40 }
41 if (cid == NULL || size < EMMC_CID_LEN) {
42 HDF_LOGE("LinuxEmmcGetCid: cid is null or size is invalid.");
43 return HDF_ERR_INVALID_PARAM;
44 }
45
46 cntlr = dev->mmc.cntlr;
47 mmcHost = (struct mmc_host *)cntlr->priv;
48 if (mmcHost == NULL) {
49 HDF_LOGE("LinuxEmmcGetCid: mmcHost is NULL!");
50 return HDF_ERR_NOT_SUPPORT;
51 }
52 if (mmcHost->card == NULL) {
53 HDF_LOGE("LinuxEmmcGetCid: card is null.");
54 return HDF_ERR_NOT_SUPPORT;
55 }
56 if (memcpy_s(cid, sizeof(uint8_t) * size, (uint8_t *)(mmcHost->card->raw_cid),
57 sizeof(mmcHost->card->raw_cid)) != EOK) {
58 HDF_LOGE("LinuxEmmcGetCid: memcpy_s fail!");
59 return HDF_FAILURE;
60 }
61 return HDF_SUCCESS;
62 }
63
64 static struct EmmcDeviceOps g_emmcMethod = {
65 .getCid = LinuxEmmcGetCid,
66 };
67
LinuxEmmcDeleteCntlr(struct MmcCntlr * cntlr)68 static void LinuxEmmcDeleteCntlr(struct MmcCntlr *cntlr)
69 {
70 if (cntlr == NULL) {
71 return;
72 }
73
74 if (cntlr->curDev != NULL) {
75 MmcDeviceRemove(cntlr->curDev);
76 OsalMemFree(cntlr->curDev);
77 }
78 MmcCntlrRemove(cntlr);
79 OsalMemFree(cntlr);
80 }
81
LinuxEmmcCntlrParse(struct MmcCntlr * cntlr,struct HdfDeviceObject * obj)82 static int32_t LinuxEmmcCntlrParse(struct MmcCntlr *cntlr, struct HdfDeviceObject *obj)
83 {
84 const struct DeviceResourceNode *node = NULL;
85 struct DeviceResourceIface *drsOps = NULL;
86 int32_t ret;
87
88 if (obj == NULL || cntlr == NULL) {
89 HDF_LOGE("LinuxEmmcCntlrParse: input para is NULL.");
90 return HDF_FAILURE;
91 }
92
93 node = obj->property;
94 if (node == NULL) {
95 HDF_LOGE("LinuxEmmcCntlrParse: drs node is NULL.");
96 return HDF_FAILURE;
97 }
98 drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
99 if (drsOps == NULL || drsOps->GetUint16 == NULL || drsOps->GetUint32 == NULL) {
100 HDF_LOGE("LinuxEmmcCntlrParse: invalid drs ops fail!");
101 return HDF_FAILURE;
102 }
103
104 ret = drsOps->GetUint16(node, "hostId", &(cntlr->index), 0);
105 if (ret != HDF_SUCCESS) {
106 HDF_LOGE("LinuxEmmcCntlrParse: read hostIndex fail!");
107 return ret;
108 }
109 ret = drsOps->GetUint32(node, "devType", &(cntlr->devType), 0);
110 if (ret != HDF_SUCCESS) {
111 HDF_LOGE("LinuxEmmcCntlrParse: read devType fail!");
112 return ret;
113 }
114 return HDF_SUCCESS;
115 }
116
LinuxEmmcBind(struct HdfDeviceObject * obj)117 static int32_t LinuxEmmcBind(struct HdfDeviceObject *obj)
118 {
119 struct MmcCntlr *cntlr = NULL;
120 int32_t ret;
121
122 if (obj == NULL) {
123 HDF_LOGE("LinuxEmmcBind: Fail, obj is NULL.");
124 return HDF_ERR_INVALID_OBJECT;
125 }
126
127 cntlr = (struct MmcCntlr *)OsalMemCalloc(sizeof(struct MmcCntlr));
128 if (cntlr == NULL) {
129 HDF_LOGE("LinuxEmmcBind: no mem for MmcCntlr.");
130 return HDF_ERR_MALLOC_FAIL;
131 }
132
133 cntlr->ops = NULL;
134 cntlr->hdfDevObj = obj;
135 obj->service = &cntlr->service;
136 ret = LinuxEmmcCntlrParse(cntlr, obj);
137 if (ret != HDF_SUCCESS) {
138 HDF_LOGE("LinuxEmmcBind: cntlr parse fail.");
139 goto _ERR;
140 }
141 cntlr->priv = (void *)GetMmcHost((int32_t)cntlr->index);
142
143 ret = MmcCntlrAdd(cntlr);
144 if (ret != HDF_SUCCESS) {
145 HDF_LOGE("LinuxEmmcBind: cntlr add fail.");
146 goto _ERR;
147 }
148
149 ret = MmcCntlrAllocDev(cntlr, (enum MmcDevType)cntlr->devType);
150 if (ret != HDF_SUCCESS) {
151 HDF_LOGE("LinuxEmmcBind: alloc dev fail.");
152 goto _ERR;
153 }
154 MmcDeviceAddOps(cntlr->curDev, &g_emmcMethod);
155 HDF_LOGD("LinuxEmmcBind: Success!");
156 return HDF_SUCCESS;
157
158 _ERR:
159 LinuxEmmcDeleteCntlr(cntlr);
160 HDF_LOGE("LinuxEmmcBind: Fail!");
161 return HDF_FAILURE;
162 }
163
LinuxEmmcInit(struct HdfDeviceObject * obj)164 static int32_t LinuxEmmcInit(struct HdfDeviceObject *obj)
165 {
166 (void)obj;
167
168 HDF_LOGD("LinuxEmmcInit: Success!");
169 return HDF_SUCCESS;
170 }
171
LinuxEmmcRelease(struct HdfDeviceObject * obj)172 static void LinuxEmmcRelease(struct HdfDeviceObject *obj)
173 {
174 if (obj == NULL) {
175 return;
176 }
177 LinuxEmmcDeleteCntlr((struct MmcCntlr *)obj->service);
178 }
179
180 struct HdfDriverEntry g_emmcDriverEntry = {
181 .moduleVersion = 1,
182 .Bind = LinuxEmmcBind,
183 .Init = LinuxEmmcInit,
184 .Release = LinuxEmmcRelease,
185 .moduleName = "HDF_PLATFORM_EMMC",
186 };
187 HDF_INIT(g_emmcDriverEntry);
188