platform_ctx.c 5.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <platform.h>
#include <platform_errors.h>
#include <platform_devfiles.h>
#include <platform_devctx.h>
#include <platform_logging.h>

struct platform_ctx {
	int				fd_tlkm;
	size_t				num_devs;
16
	platform_device_info_t		devs[PLATFORM_MAX_DEVS];
17
18
19
20
21
	char				version[TLKM_VERSION_SZ];
	platform_devctx_t		*devctx[PLATFORM_MAX_DEVS];
};

static
22
int get_tlkm_version(platform_ctx_t *ctx, char *v, int v_buffer_length)
23
{
24
	struct tlkm_ioctl_version_cmd c = { .version = "", };
25
	if (ioctl(ctx->fd_tlkm, TLKM_IOCTL_VERSION, &c)) {
26
		ERR("getting version from device driver failed: %s (%d)", strerror(errno), errno);
27
28
		return errno;
	}
29
	strncpy(v, c.version, v_buffer_length);
30
31
32
33
34
35
36
37
38
39
	return 0;
}

static
int enum_devs(platform_ctx_t *ctx)
{
	int r = 0;
	assert(ctx);
	assert(ctx->fd_tlkm > 0);
	struct tlkm_ioctl_enum_devices_cmd c;
40
	memset(&c, 0, sizeof(c));
41
42
43
44
45
46
47
48
49
50
	if ((r = ioctl(ctx->fd_tlkm, TLKM_IOCTL_ENUM_DEVICES, &c))) {
		ERR("could not enumerate devices: %s (%d)", strerror(r), r);
		ctx->num_devs = 0;
		return PERR_TLKM_ERROR;
	}
	ctx->num_devs = c.num_devs;
	memcpy(ctx->devs, c.devs, sizeof(*(ctx->devs)) * c.num_devs);
	return 0;
}

51
static
52
53
54
platform_res_t get_dev(platform_ctx_t *ctx,
		platform_dev_id_t const dev_id,
		platform_device_info_t *info)
55
56
{
	if (dev_id >= ctx->num_devs) {
57
		ERR("unknown device #" PRIdev, dev_id);
58
59
60
61
62
63
		return PERR_NO_SUCH_DEVICE;
	}
	memcpy(info, &ctx->devs[dev_id], sizeof(*info));
	return PLATFORM_SUCCESS;
}

64
65
66
67
68
69
70
71
72
73
static
platform_res_t init_platform(platform_ctx_t *ctx)
{
	platform_res_t r = PLATFORM_SUCCESS;
	ctx->fd_tlkm = open(TLKM_CONTROL_FN, O_RDWR);
	if (ctx->fd_tlkm == -1) {
		ERR("could not open " TLKM_CONTROL_FN ": %s (%d)", strerror(errno), errno);
		r = PERR_TLKM_ERROR;
		goto err_tlkm;
	}
74
	if (get_tlkm_version(ctx, ctx->version, TLKM_VERSION_SZ)) goto err_ioctl;
75
76
77
78
79
	LOG(LPLL_TLKM, "TLKM version: %s", ctx->version);

	if (enum_devs(ctx)) goto err_ioctl;
	LOG(LPLL_TLKM, "found %zu TaPaSCo devices:", ctx->num_devs);
	for (size_t i = 0; i < ctx->num_devs; ++i) {
80
		LOG(LPLL_TLKM, "  device #" PRIdev ": %s (%04x:%04x)", i, ctx->devs[i].name,
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
				ctx->devs[i].vendor_id, ctx->devs[i].product_id);
	}

	if (ctx->num_devs == 0) {
		ERR("found no TaPaSCo devices - is the device driver module tlkm loaded?");
		r = PERR_NO_DEVICES_FOUND;
		goto err_ioctl;
	}

	LOG(LPLL_TLKM, "platform context successfully initialized");
	return r;

err_ioctl:
	close(ctx->fd_tlkm);
err_tlkm:
	return r;
}

99
100
101
102
103
104
105
static
void deinit_platform(platform_ctx_t *ctx)
{
	close(ctx->fd_tlkm);
	LOG(LPLL_INIT, "platform deinited");
}

106
107
108
109
110
111
platform_res_t _platform_init(const char *const version, platform_ctx_t **ctx)
{
	platform_res_t r = PLATFORM_SUCCESS;
	platform_logging_init();
	LOG(LPLL_INIT, "Platform API Version: %s", platform_version());
	if (platform_check_version(version) != PLATFORM_SUCCESS) {
112
		ERR("Platform API version mismatch: found %s, expected %s", platform_version(), version);
113
114
115
116
117
118
119
120
121
122
123
		return PERR_VERSION_MISMATCH;
	}

	*ctx = (platform_ctx_t *)calloc(sizeof(**ctx), 1);
	if (! *ctx) {
		ERR("could not allocate platform_ctx");
		r = PERR_OUT_OF_MEMORY;
		goto err_ctx_alloc;
	}

	if ((r = init_platform(*ctx)) != PLATFORM_SUCCESS) {
124
		ERR("failed to initialize platform: %s (" PRIres ")", platform_strerror(r), r);
125
126
127
128
129
130
131
132
		goto err_init;
	}

	return r;

err_init:
	free(*ctx);
err_ctx_alloc:
133
	platform_logging_deinit();
134
135
136
	return r;
}

137
138
139
140
141
void platform_deinit(platform_ctx_t *ctx)
{
	deinit_platform(ctx);
	free(ctx);
	LOG(LPLL_INIT, "so long & thanks for all the fish, bye");
142
	platform_logging_deinit();
143
}
144

Jens Korinth's avatar
Jens Korinth committed
145
platform_res_t platform_enum_devices(platform_ctx_t *ctx,
146
147
		size_t *num_devs,
		platform_device_info_t **devs)
148
149
150
151
152
153
{
	*num_devs = ctx->num_devs;
	*devs = ctx->devs;
	return PLATFORM_SUCCESS;
}

154
155
156
157
158
159
160
platform_res_t platform_device_info(platform_ctx_t *ctx,
		platform_dev_id_t const dev_id,
		platform_device_info_t *info)
{
	return get_dev(ctx, dev_id, info);
}

161
162
163
164
platform_res_t platform_create_device(platform_ctx_t *ctx,
		platform_dev_id_t const dev_id,
		platform_access_t const mode,
		platform_devctx_t **pdctx)
165
166
167
168
169
170
171
172
173
174
175
{
	int r = 0;
	platform_res_t res = PLATFORM_SUCCESS;
	assert(ctx);
	assert(dev_id < PLATFORM_MAX_DEVS);
	assert(ctx->fd_tlkm > 0);
	struct tlkm_ioctl_device_cmd c = {
		.dev_id = dev_id,
		.access = mode,
	};
	if ((r = ioctl(ctx->fd_tlkm, TLKM_IOCTL_CREATE_DEVICE, &c))) {
176
		ERR("could not create device #" PRIdev ": %s (%d)", dev_id, strerror(errno), errno);
177
178
		return PERR_TLKM_ERROR;
	}
179
	LOG(LPLL_TLKM, "created device #" PRIdev ", initializing device context ...", dev_id);
180
	if ((res = platform_devctx_init(ctx, dev_id, mode, &ctx->devctx[dev_id])) != PLATFORM_SUCCESS) {
181
		ERR("could not initialize device context for #" PRIdev ": %s (" PRIres ")",
Jens Korinth's avatar
Jens Korinth committed
182
				dev_id, platform_strerror(res), res);
183
184
		goto err_pdev;
	}
185
	if (pdctx) *pdctx = ctx->devctx[dev_id];
186
	LOG(LPLL_DEVICE, "successfully initialized device #" PRIdev, dev_id);
Jens Korinth's avatar
Jens Korinth committed
187
	return PLATFORM_SUCCESS;
188
189

err_pdev:
Jens Korinth's avatar
Jens Korinth committed
190
	return res;
191
192
}

193
void platform_destroy_device_by_id(platform_ctx_t *ctx, platform_dev_id_t const dev_id)
194
195
196
197
198
199
{
	assert(dev_id < PLATFORM_MAX_DEVS);
	assert(ctx);
	assert(ctx->devctx[dev_id]);
	struct tlkm_ioctl_device_cmd c = {
		.dev_id = dev_id,
200
		.access = ctx->devctx[dev_id]->mode,
201
202
203
204
205
	};
	int r = 0;
	assert(ctx);
	assert(ctx->fd_tlkm > 0);
	assert(dev_id < PLATFORM_MAX_DEVS);
206
	platform_devctx_deinit(ctx->devctx[dev_id]);
207
208
	ctx->devctx[dev_id] = NULL;
	if ((r = ioctl(ctx->fd_tlkm, TLKM_IOCTL_DESTROY_DEVICE, &c))) {
209
		ERR("could not destroy device #" PRIdev ": %s (%d)", dev_id, strerror(errno), errno);
210
	} else {
211
		LOG(LPLL_DEVICE, "device #" PRIdev " destroyed", dev_id);
212
213
	}
}
214
215
216
217
218
219

void platform_destroy_device(platform_ctx_t *ctx, platform_devctx_t *pdctx)
{
	assert(pdctx);
	platform_destroy_device_by_id(ctx, pdctx->dev_id);
}