aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/tegra/mediaserver
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/media/video/tegra/mediaserver
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/media/video/tegra/mediaserver')
-rw-r--r--drivers/media/video/tegra/mediaserver/Kconfig10
-rw-r--r--drivers/media/video/tegra/mediaserver/Makefile3
-rw-r--r--drivers/media/video/tegra/mediaserver/tegra_mediaserver.c556
3 files changed, 569 insertions, 0 deletions
diff --git a/drivers/media/video/tegra/mediaserver/Kconfig b/drivers/media/video/tegra/mediaserver/Kconfig
new file mode 100644
index 00000000000..9e60a5b49cd
--- /dev/null
+++ b/drivers/media/video/tegra/mediaserver/Kconfig
@@ -0,0 +1,10 @@
1config TEGRA_MEDIASERVER
2bool "Tegra Media Server support"
3depends on ARCH_TEGRA && TEGRA_RPC
4default y
5help
6 Enables support for the multiple OpenMAX clients. Exports the
7 interface on the device node /dev/tegra_mediaserver.
8
9 If unsure, say Y
10
diff --git a/drivers/media/video/tegra/mediaserver/Makefile b/drivers/media/video/tegra/mediaserver/Makefile
new file mode 100644
index 00000000000..ed24e91932b
--- /dev/null
+++ b/drivers/media/video/tegra/mediaserver/Makefile
@@ -0,0 +1,3 @@
1GCOV_PROFILE := y
2obj-$(CONFIG_TEGRA_MEDIASERVER) += tegra_mediaserver.o
3
diff --git a/drivers/media/video/tegra/mediaserver/tegra_mediaserver.c b/drivers/media/video/tegra/mediaserver/tegra_mediaserver.c
new file mode 100644
index 00000000000..f6f5b1ec8b7
--- /dev/null
+++ b/drivers/media/video/tegra/mediaserver/tegra_mediaserver.c
@@ -0,0 +1,556 @@
1/*
2 * Copyright (C) 2011 NVIDIA Corp.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#include <linux/module.h>
16#include <linux/kernel.h>
17#include <linux/fs.h>
18#include <linux/miscdevice.h>
19#include <linux/slab.h>
20#include <linux/uaccess.h>
21#include <linux/mm.h>
22
23#include <linux/tegra_mediaserver.h>
24#include "../avp/nvavp.h"
25#include "../../../../video/tegra/nvmap/nvmap.h"
26
27#define CHECK_STATUS(e, tag) \
28 do { if (e < 0) goto tag; } while (0)
29
30#define CHECK_NULL(ptr, tag) \
31 do { if (!ptr) goto tag; } while (0)
32
33#define CHECK_CONDITION(c, tag) \
34 do { if (c) goto tag; } while (0)
35
36struct tegra_mediasrv_block {
37 struct list_head entry;
38 struct tegra_mediaserver_block_info block;
39};
40
41struct tegra_mediasrv_iram {
42 struct list_head entry;
43 struct tegra_mediaserver_iram_info iram;
44};
45
46struct tegra_mediasrv_node {
47 struct tegra_mediasrv_info *mediasrv;
48 struct list_head blocks;
49 int nr_iram_shared;
50};
51
52struct tegra_mediasrv_manager {
53 struct tegra_avp_lib lib;
54 struct tegra_rpc_info *rpc;
55 struct tegra_sema_info *sema;
56};
57
58struct tegra_mediasrv_info {
59 int minor;
60 struct mutex lock;
61 struct nvmap_client *nvmap;
62 struct tegra_avp_info *avp;
63 struct tegra_mediasrv_manager manager;
64 int nr_nodes;
65 int nr_blocks;
66 struct tegra_mediaserver_iram_info iram; /* only one supported */
67 int nr_iram_shared;
68};
69
70static struct tegra_mediasrv_info *mediasrv_info;
71
72
73/*
74 * File entry points
75 */
76static int mediasrv_open(struct inode *inode, struct file *file)
77{
78 struct tegra_mediasrv_info *mediasrv = mediasrv_info;
79 struct tegra_mediasrv_node *node = NULL;
80 struct tegra_mediasrv_manager *manager = &mediasrv->manager;
81 struct tegra_avp_lib *lib = &manager->lib;
82 int e;
83
84 node = kzalloc(sizeof(struct tegra_mediasrv_node), GFP_KERNEL);
85 CHECK_NULL(node, node_alloc_fail);
86 INIT_LIST_HEAD(&node->blocks);
87 node->mediasrv = mediasrv;
88
89 mutex_lock(&mediasrv->lock);
90 nonseekable_open(inode, file);
91
92 if (!mediasrv->nr_nodes) {
93 e = tegra_sema_open(&manager->sema);
94 CHECK_STATUS(e, fail);
95
96 e = tegra_rpc_open(&manager->rpc);
97 CHECK_STATUS(e, fail);
98
99 e = tegra_rpc_port_create(manager->rpc, "NVMM_MANAGER_SRV",
100 manager->sema);
101 CHECK_STATUS(e, fail);
102
103 e = tegra_avp_open(&mediasrv->avp);
104 CHECK_STATUS(e, fail);
105
106 memcpy(lib->name, "nvmm_manager.axf\0",
107 strlen("nvmm_manager.axf") + 1);
108 lib->args = &mediasrv;
109 lib->args_len = sizeof(unsigned long);
110 e = tegra_avp_load_lib(mediasrv->avp, lib);
111 CHECK_STATUS(e, fail);
112
113 e = tegra_rpc_port_connect(manager->rpc, 50000);
114 CHECK_STATUS(e, fail);
115 }
116
117 mediasrv->nr_nodes++;
118 try_module_get(THIS_MODULE);
119
120 mutex_unlock(&mediasrv->lock);
121
122 file->private_data = node;
123
124 return 0;
125
126fail:
127 if (lib->handle) {
128 tegra_avp_unload_lib(mediasrv->avp, lib->handle);
129 lib->handle = 0;
130 }
131
132 if (mediasrv->avp) {
133 tegra_avp_release(mediasrv->avp);
134 mediasrv->avp = NULL;
135 }
136
137 if (manager->rpc) {
138 tegra_rpc_release(manager->rpc);
139 manager->rpc = NULL;
140 }
141 if (manager->sema) {
142 tegra_sema_release(manager->sema);
143 manager->sema = NULL;
144 }
145
146 kfree(node);
147
148 mutex_unlock(&mediasrv->lock);
149 return e;
150
151node_alloc_fail:
152 e = -ENOMEM;
153 return e;
154}
155
156static int mediasrv_release(struct inode *inode, struct file *file)
157{
158 struct tegra_mediasrv_info *mediasrv = mediasrv_info;
159 struct tegra_mediasrv_node *node = file->private_data;
160 struct tegra_mediasrv_block *block;
161 struct list_head *entry;
162 struct list_head *temp;
163 u32 message[2];
164 int e;
165
166 mutex_lock(&mediasrv->lock);
167
168 list_for_each_safe(entry, temp, &node->blocks) {
169 block = list_entry(entry, struct tegra_mediasrv_block, entry);
170
171 pr_info("Improperly closed block found!");
172 pr_info(" NVMM Block Handle: 0x%08x\n",
173 block->block.nvmm_block_handle);
174 pr_info(" AVP Block Handle: 0x%08x\n",
175 block->block.avp_block_handle);
176
177 message[0] = 1; /* NvmmManagerMsgType_AbnormalTerm */
178 message[1] = block->block.avp_block_handle;
179
180 e = tegra_rpc_write(mediasrv->manager.rpc, (u8 *)message,
181 sizeof(u32) * 2);
182 pr_info("Abnormal termination message result: %d\n", e);
183
184 if (block->block.avp_block_library_handle) {
185 e = tegra_avp_unload_lib(mediasrv->avp,
186 block->block.avp_block_library_handle);
187 pr_info("Unload block (0x%08x) result: %d\n",
188 block->block.avp_block_library_handle, e);
189 }
190
191 if (block->block.service_library_handle) {
192 e = tegra_avp_unload_lib(mediasrv->avp,
193 block->block.service_library_handle);
194 pr_info("Unload service (0x%08x) result: %d\n",
195 block->block.service_library_handle, e);
196 }
197
198 mediasrv->nr_blocks--;
199 list_del(entry);
200 kfree(block);
201 }
202
203 mediasrv->nr_iram_shared -= node->nr_iram_shared;
204 if (mediasrv->iram.rm_handle && !mediasrv->nr_iram_shared) {
205 pr_info("Improperly freed shared iram found!");
206 nvmap_unpin_ids(mediasrv->nvmap, 1, &mediasrv->iram.rm_handle);
207 nvmap_free_handle_id(mediasrv->nvmap, mediasrv->iram.rm_handle);
208 mediasrv->iram.rm_handle = 0;
209 mediasrv->iram.physical_address = 0;
210 }
211
212 kfree(node);
213 mediasrv->nr_nodes--;
214 if (!mediasrv->nr_nodes) {
215 struct tegra_mediasrv_manager *manager = &mediasrv->manager;
216
217 tegra_avp_unload_lib(mediasrv->avp, manager->lib.handle);
218 manager->lib.handle = 0;
219
220 tegra_avp_release(mediasrv->avp);
221 mediasrv->avp = NULL;
222
223 tegra_rpc_release(manager->rpc);
224 manager->rpc = NULL;
225
226 tegra_sema_release(manager->sema);
227 manager->sema = NULL;
228 }
229
230 mutex_unlock(&mediasrv->lock);
231 module_put(THIS_MODULE);
232 return 0;
233}
234
235static int mediasrv_alloc(struct tegra_mediasrv_node *node,
236 union tegra_mediaserver_alloc_info *in,
237 union tegra_mediaserver_alloc_info *out)
238{
239 struct tegra_mediasrv_info *mediasrv = node->mediasrv;
240 int e;
241
242 switch (in->in.tegra_mediaserver_resource_type) {
243 case TEGRA_MEDIASERVER_RESOURCE_BLOCK:
244 {
245 struct tegra_mediasrv_block *block;
246
247 block = kzalloc(sizeof(struct tegra_mediasrv_block),
248 GFP_KERNEL);
249 CHECK_NULL(block, block_alloc_fail);
250
251 block->block = in->in.u.block;
252 list_add(&block->entry, &node->blocks);
253 goto block_done;
254
255block_alloc_fail:
256 e = -ENOMEM;
257 goto fail;
258
259block_done:
260 mediasrv->nr_blocks++;
261 out->out.u.block.count = mediasrv->nr_blocks;
262 }
263 break;
264
265 case TEGRA_MEDIASERVER_RESOURCE_IRAM:
266 {
267 if (in->in.u.iram.tegra_mediaserver_iram_type ==
268 TEGRA_MEDIASERVER_IRAM_SHARED) {
269 if (!mediasrv->nr_iram_shared) {
270 size_t align, size;
271 struct nvmap_handle_ref *r = NULL;
272 unsigned long id;
273 int physical_address;
274
275 size = PAGE_ALIGN(in->in.u.iram.size);
276 r = nvmap_create_handle(mediasrv->nvmap, size);
277 CHECK_CONDITION((r < 0),
278 iram_shared_handle_fail);
279
280 id = nvmap_ref_to_id(r);
281
282 align = max_t(size_t, in->in.u.iram.alignment,
283 PAGE_SIZE);
284 e = nvmap_alloc_handle_id(mediasrv->nvmap, id,
285 NVMAP_HEAP_CARVEOUT_IRAM, align,
286 NVMAP_HANDLE_WRITE_COMBINE);
287 CHECK_STATUS(e, iram_shared_alloc_fail);
288
289 physical_address =
290 nvmap_pin_ids(mediasrv->nvmap, 1, &id);
291 CHECK_CONDITION((physical_address < 0),
292 iram_shared_pin_fail);
293
294 mediasrv->iram.rm_handle = id;
295 mediasrv->iram.physical_address =
296 physical_address;
297 goto iram_shared_done;
298
299iram_shared_pin_fail:
300 e = physical_address;
301iram_shared_alloc_fail:
302 nvmap_free_handle_id(mediasrv->nvmap, id);
303iram_shared_handle_fail:
304 goto fail;
305 }
306
307iram_shared_done:
308 out->out.u.iram.rm_handle = mediasrv->iram.rm_handle;
309 out->out.u.iram.physical_address =
310 mediasrv->iram.physical_address;
311 mediasrv->nr_iram_shared++;
312 node->nr_iram_shared++;
313 } else if (in->in.u.iram.tegra_mediaserver_iram_type ==
314 TEGRA_MEDIASERVER_IRAM_SCRATCH) {
315 e = -EINVAL;
316 goto fail;
317 }
318 }
319 break;
320
321 default:
322 {
323 e = -EINVAL;
324 goto fail;
325 }
326 break;
327 }
328
329 return 0;
330
331fail:
332 return e;
333}
334
335static void mediasrv_free(struct tegra_mediasrv_node *node,
336 union tegra_mediaserver_free_info *in)
337{
338 struct tegra_mediasrv_info *mediasrv = node->mediasrv;
339
340 switch (in->in.tegra_mediaserver_resource_type) {
341 case TEGRA_MEDIASERVER_RESOURCE_BLOCK:
342 {
343 struct tegra_mediasrv_block *block = NULL;
344 struct tegra_mediasrv_block *temp;
345 struct list_head *entry;
346
347 list_for_each(entry, &node->blocks) {
348 temp = list_entry(entry, struct tegra_mediasrv_block,
349 entry);
350 if (temp->block.nvmm_block_handle !=
351 in->in.u.nvmm_block_handle)
352 continue;
353
354 block = temp;
355 break;
356 }
357
358 CHECK_NULL(block, done);
359 list_del(&block->entry);
360 kfree(block);
361 }
362 break;
363
364 case TEGRA_MEDIASERVER_RESOURCE_IRAM:
365 {
366 if (in->in.u.iram_rm_handle == mediasrv->iram.rm_handle &&
367 node->nr_iram_shared) {
368 node->nr_iram_shared--;
369 mediasrv->nr_iram_shared--;
370
371 if (!mediasrv->nr_iram_shared) {
372 nvmap_unpin_ids(mediasrv->nvmap, 1,
373 &mediasrv->iram.rm_handle);
374 nvmap_free_handle_id(mediasrv->nvmap,
375 mediasrv->iram.rm_handle);
376 mediasrv->iram.rm_handle = 0;
377 mediasrv->iram.physical_address = 0;
378 }
379 }
380
381 else
382 goto done;
383 }
384 break;
385 }
386
387done:
388 return;
389}
390
391static int mediasrv_update_block_info(
392 struct tegra_mediasrv_node *node,
393 union tegra_mediaserver_update_block_info *in
394)
395{
396 struct tegra_mediasrv_block *entry = NULL;
397 struct tegra_mediasrv_block *block = NULL;
398 int e;
399
400 list_for_each_entry(entry, &node->blocks, entry) {
401 if (entry->block.nvmm_block_handle != in->in.nvmm_block_handle)
402 continue;
403
404 block = entry;
405 break;
406 }
407
408 CHECK_NULL(block, fail);
409
410 block->block = in->in;
411 return 0;
412
413fail:
414 e = -EINVAL;
415 return e;
416}
417
418static long mediasrv_unlocked_ioctl(struct file *file, unsigned int cmd,
419 unsigned long arg)
420{
421 struct tegra_mediasrv_info *mediasrv = mediasrv_info;
422 struct tegra_mediasrv_node *node = file->private_data;
423 int e = -ENODEV;
424
425 mutex_lock(&mediasrv->lock);
426
427 switch (cmd) {
428 case TEGRA_MEDIASERVER_IOCTL_ALLOC:
429 {
430 union tegra_mediaserver_alloc_info in, out;
431 e = copy_from_user(&in, (void __user *)arg, sizeof(in));
432 CHECK_CONDITION(e, copy_fail);
433 e = mediasrv_alloc(node, &in, &out);
434 CHECK_STATUS(e, fail);
435 e = copy_to_user((void __user *)arg, &out, sizeof(out));
436 CHECK_CONDITION(e, copy_fail);
437 }
438 break;
439
440 case TEGRA_MEDIASERVER_IOCTL_FREE:
441 {
442 union tegra_mediaserver_free_info in;
443 e = copy_from_user(&in, (void __user *)arg, sizeof(in));
444 CHECK_CONDITION(e, copy_fail);
445 mediasrv_free(node, &in);
446 }
447 break;
448
449 case TEGRA_MEDIASERVER_IOCTL_UPDATE_BLOCK_INFO:
450 {
451 union tegra_mediaserver_update_block_info in;
452 e = copy_from_user(&in, (void __user *)arg, sizeof(in));
453 CHECK_CONDITION(e, copy_fail);
454 e = mediasrv_update_block_info(node, &in);
455 CHECK_CONDITION(e, fail);
456 }
457 break;
458
459 default:
460 {
461 e = -ENODEV;
462 goto fail;
463 }
464 break;
465 }
466
467 mutex_unlock(&mediasrv->lock);
468 return 0;
469
470copy_fail:
471 e = -EFAULT;
472fail:
473 mutex_unlock(&mediasrv->lock);
474 return e;
475}
476
477/*
478 * Kernel structures and entry points
479 */
480static const struct file_operations mediaserver_fops = {
481 .owner = THIS_MODULE,
482 .open = mediasrv_open,
483 .release = mediasrv_release,
484 .unlocked_ioctl = mediasrv_unlocked_ioctl,
485};
486
487static struct miscdevice mediaserver_misc_device = {
488 .minor = MISC_DYNAMIC_MINOR,
489 .name = "tegra_mediaserver",
490 .fops = &mediaserver_fops,
491};
492
493static int __init tegra_mediaserver_init(void)
494{
495 struct tegra_mediasrv_info *mediasrv;
496 int e = 0;
497
498 CHECK_NULL(!mediasrv_info, busy);
499
500 mediasrv = kzalloc(sizeof(struct tegra_mediasrv_info), GFP_KERNEL);
501 CHECK_NULL(mediasrv, alloc_fail);
502
503 mediasrv->nvmap = nvmap_create_client(nvmap_dev, "tegra_mediaserver");
504 CHECK_NULL(mediasrv, nvmap_create_fail);
505
506 e = misc_register(&mediaserver_misc_device);
507 CHECK_STATUS(e, register_fail);
508
509 mediasrv->nr_nodes = 0;
510 mutex_init(&mediasrv->lock);
511
512 mediasrv_info = mediasrv;
513 goto done;
514
515nvmap_create_fail:
516 e = -ENOMEM;
517 kfree(mediasrv);
518 goto done;
519
520register_fail:
521 nvmap_client_put(mediasrv->nvmap);
522 kfree(mediasrv);
523 goto done;
524
525alloc_fail:
526 e = -ENOMEM;
527 goto done;
528
529busy:
530 e = -EBUSY;
531 goto done;
532
533done:
534 return e;
535}
536
537void __exit tegra_mediaserver_cleanup(void)
538{
539 struct tegra_mediasrv_info *mediasrv = mediasrv_info;
540 int e;
541
542 e = misc_deregister(&mediaserver_misc_device);
543 CHECK_STATUS(e, fail);
544
545 nvmap_client_put(mediasrv->nvmap);
546 kfree(mediasrv);
547 mediasrv_info = NULL;
548
549fail:
550 return;
551}
552
553module_init(tegra_mediaserver_init);
554module_exit(tegra_mediaserver_cleanup);
555MODULE_LICENSE("GPL");
556