]>
Commit | Line | Data |
---|---|---|
7d55524d ORL |
1 | /* |
2 | * drv_interface.c | |
3 | * | |
4 | * DSP-BIOS Bridge driver support functions for TI OMAP processors. | |
5 | * | |
6 | * DSP/BIOS Bridge driver interface. | |
7 | * | |
8 | * Copyright (C) 2005-2006 Texas Instruments, Inc. | |
9 | * | |
10 | * This package is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License version 2 as | |
12 | * published by the Free Software Foundation. | |
13 | * | |
14 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
15 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
16 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
17 | */ | |
18 | ||
19 | /* ----------------------------------- Host OS */ | |
20 | ||
21 | #include <dspbridge/host_os.h> | |
22 | #include <linux/platform_device.h> | |
23 | #include <linux/pm.h> | |
24 | ||
25 | #ifdef MODULE | |
26 | #include <linux/module.h> | |
27 | #endif | |
28 | ||
29 | #include <linux/device.h> | |
30 | #include <linux/init.h> | |
31 | #include <linux/moduleparam.h> | |
32 | #include <linux/cdev.h> | |
33 | ||
34 | /* ----------------------------------- DSP/BIOS Bridge */ | |
35 | #include <dspbridge/std.h> | |
36 | #include <dspbridge/dbdefs.h> | |
37 | ||
38 | /* ----------------------------------- Trace & Debug */ | |
39 | #include <dspbridge/dbc.h> | |
40 | ||
41 | /* ----------------------------------- OS Adaptation Layer */ | |
42 | #include <dspbridge/services.h> | |
43 | #include <dspbridge/clk.h> | |
44 | #include <dspbridge/sync.h> | |
45 | ||
46 | /* ----------------------------------- Platform Manager */ | |
47 | #include <dspbridge/dspapi-ioctl.h> | |
48 | #include <dspbridge/dspapi.h> | |
49 | #include <dspbridge/dspdrv.h> | |
50 | ||
51 | /* ----------------------------------- Resource Manager */ | |
52 | #include <dspbridge/pwr.h> | |
53 | ||
54 | /* ----------------------------------- This */ | |
55 | #include <drv_interface.h> | |
56 | ||
57 | #include <dspbridge/cfg.h> | |
58 | #include <dspbridge/resourcecleanup.h> | |
59 | #include <dspbridge/chnl.h> | |
60 | #include <dspbridge/proc.h> | |
61 | #include <dspbridge/dev.h> | |
62 | #include <dspbridge/drvdefs.h> | |
63 | #include <dspbridge/drv.h> | |
64 | ||
b3d23688 | 65 | #ifdef CONFIG_TIDSPBRIDGE_DVFS |
7d55524d ORL |
66 | #include <mach-omap2/omap3-opp.h> |
67 | #endif | |
68 | ||
69 | #define BRIDGE_NAME "C6410" | |
70 | /* ----------------------------------- Globals */ | |
71 | #define DRIVER_NAME "DspBridge" | |
72 | #define DSPBRIDGE_VERSION "0.3" | |
73 | s32 dsp_debug; | |
74 | ||
75 | struct platform_device *omap_dspbridge_dev; | |
76 | struct device *bridge; | |
77 | ||
78 | /* This is a test variable used by Bridge to test different sleep states */ | |
79 | s32 dsp_test_sleepstate; | |
80 | ||
81 | static struct cdev bridge_cdev; | |
82 | ||
83 | static struct class *bridge_class; | |
84 | ||
85 | static u32 driver_context; | |
86 | static s32 driver_major; | |
87 | static char *base_img; | |
88 | char *iva_img; | |
89 | static s32 shm_size = 0x500000; /* 5 MB */ | |
90 | static int tc_wordswapon; /* Default value is always false */ | |
b3d23688 | 91 | #ifdef CONFIG_TIDSPBRIDGE_RECOVERY |
7d55524d ORL |
92 | #define REC_TIMEOUT 5000 /*recovery timeout in msecs */ |
93 | static atomic_t bridge_cref; /* number of bridge open handles */ | |
94 | static struct workqueue_struct *bridge_rec_queue; | |
95 | static struct work_struct bridge_recovery_work; | |
96 | static DECLARE_COMPLETION(bridge_comp); | |
97 | static DECLARE_COMPLETION(bridge_open_comp); | |
98 | static bool recover; | |
99 | #endif | |
100 | ||
101 | #ifdef CONFIG_PM | |
102 | struct omap34_xx_bridge_suspend_data { | |
103 | int suspended; | |
104 | wait_queue_head_t suspend_wq; | |
105 | }; | |
106 | ||
107 | static struct omap34_xx_bridge_suspend_data bridge_suspend_data; | |
108 | ||
109 | static int omap34_xxbridge_suspend_lockout(struct omap34_xx_bridge_suspend_data | |
110 | *s, struct file *f) | |
111 | { | |
112 | if ((s)->suspended) { | |
113 | if ((f)->f_flags & O_NONBLOCK) | |
114 | return -EPERM; | |
115 | wait_event_interruptible((s)->suspend_wq, (s)->suspended == 0); | |
116 | } | |
117 | return 0; | |
118 | } | |
119 | #endif | |
120 | ||
121 | module_param(dsp_debug, int, 0); | |
122 | MODULE_PARM_DESC(dsp_debug, "Wait after loading DSP image. default = false"); | |
123 | ||
124 | module_param(dsp_test_sleepstate, int, 0); | |
125 | MODULE_PARM_DESC(dsp_test_sleepstate, "DSP Sleep state = 0"); | |
126 | ||
127 | module_param(base_img, charp, 0); | |
128 | MODULE_PARM_DESC(base_img, "DSP base image, default = NULL"); | |
129 | ||
130 | module_param(shm_size, int, 0); | |
131 | MODULE_PARM_DESC(shm_size, "shm size, default = 4 MB, minimum = 64 KB"); | |
132 | ||
133 | module_param(tc_wordswapon, int, 0); | |
134 | MODULE_PARM_DESC(tc_wordswapon, "TC Word Swap Option. default = 0"); | |
135 | ||
136 | MODULE_AUTHOR("Texas Instruments"); | |
137 | MODULE_LICENSE("GPL"); | |
138 | MODULE_VERSION(DSPBRIDGE_VERSION); | |
139 | ||
140 | static char *driver_name = DRIVER_NAME; | |
141 | ||
142 | static const struct file_operations bridge_fops = { | |
143 | .open = bridge_open, | |
144 | .release = bridge_release, | |
145 | .unlocked_ioctl = bridge_ioctl, | |
146 | .mmap = bridge_mmap, | |
147 | }; | |
148 | ||
149 | #ifdef CONFIG_PM | |
150 | static u32 time_out = 1000; | |
b3d23688 | 151 | #ifdef CONFIG_TIDSPBRIDGE_DVFS |
7d55524d ORL |
152 | s32 dsp_max_opps = VDD1_OPP5; |
153 | #endif | |
154 | ||
155 | /* Maximum Opps that can be requested by IVA */ | |
156 | /*vdd1 rate table */ | |
b3d23688 | 157 | #ifdef CONFIG_TIDSPBRIDGE_DVFS |
7d55524d ORL |
158 | const struct omap_opp vdd1_rate_table_bridge[] = { |
159 | {0, 0, 0}, | |
160 | /*OPP1 */ | |
161 | {S125M, VDD1_OPP1, 0}, | |
162 | /*OPP2 */ | |
163 | {S250M, VDD1_OPP2, 0}, | |
164 | /*OPP3 */ | |
165 | {S500M, VDD1_OPP3, 0}, | |
166 | /*OPP4 */ | |
167 | {S550M, VDD1_OPP4, 0}, | |
168 | /*OPP5 */ | |
169 | {S600M, VDD1_OPP5, 0}, | |
170 | }; | |
171 | #endif | |
172 | #endif | |
173 | ||
174 | struct dspbridge_platform_data *omap_dspbridge_pdata; | |
175 | ||
176 | u32 vdd1_dsp_freq[6][4] = { | |
177 | {0, 0, 0, 0}, | |
178 | /*OPP1 */ | |
179 | {0, 90000, 0, 86000}, | |
180 | /*OPP2 */ | |
181 | {0, 180000, 80000, 170000}, | |
182 | /*OPP3 */ | |
183 | {0, 360000, 160000, 340000}, | |
184 | /*OPP4 */ | |
185 | {0, 396000, 325000, 376000}, | |
186 | /*OPP5 */ | |
187 | {0, 430000, 355000, 430000}, | |
188 | }; | |
189 | ||
b3d23688 | 190 | #ifdef CONFIG_TIDSPBRIDGE_RECOVERY |
7d55524d ORL |
191 | static void bridge_recover(struct work_struct *work) |
192 | { | |
193 | struct dev_object *dev; | |
194 | struct cfg_devnode *dev_node; | |
195 | if (atomic_read(&bridge_cref)) { | |
196 | INIT_COMPLETION(bridge_comp); | |
197 | while (!wait_for_completion_timeout(&bridge_comp, | |
198 | msecs_to_jiffies(REC_TIMEOUT))) | |
199 | pr_info("%s:%d handle(s) still opened\n", | |
200 | __func__, atomic_read(&bridge_cref)); | |
201 | } | |
202 | dev = dev_get_first(); | |
203 | dev_get_dev_node(dev, &dev_node); | |
204 | if (!dev_node || DSP_FAILED(proc_auto_start(dev_node, dev))) | |
205 | pr_err("DSP could not be restarted\n"); | |
206 | recover = false; | |
207 | complete_all(&bridge_open_comp); | |
208 | } | |
209 | ||
210 | void bridge_recover_schedule(void) | |
211 | { | |
212 | INIT_COMPLETION(bridge_open_comp); | |
213 | recover = true; | |
214 | queue_work(bridge_rec_queue, &bridge_recovery_work); | |
215 | } | |
216 | #endif | |
b3d23688 | 217 | #ifdef CONFIG_TIDSPBRIDGE_DVFS |
7d55524d ORL |
218 | static int dspbridge_scale_notification(struct notifier_block *op, |
219 | unsigned long val, void *ptr) | |
220 | { | |
221 | struct dspbridge_platform_data *pdata = | |
222 | omap_dspbridge_dev->dev.platform_data; | |
223 | ||
224 | if (CPUFREQ_POSTCHANGE == val && pdata->dsp_get_opp) | |
225 | pwr_pm_post_scale(PRCM_VDD1, pdata->dsp_get_opp()); | |
226 | ||
227 | return 0; | |
228 | } | |
229 | ||
230 | static struct notifier_block iva_clk_notifier = { | |
231 | .notifier_call = dspbridge_scale_notification, | |
232 | NULL, | |
233 | }; | |
234 | #endif | |
235 | ||
236 | /** | |
237 | * omap3_bridge_startup() - perform low lever initializations | |
238 | * @pdev: pointer to platform device | |
239 | * | |
240 | * Initializes recovery, PM and DVFS required data, before calling | |
241 | * clk and memory init routines. | |
242 | */ | |
243 | static int omap3_bridge_startup(struct platform_device *pdev) | |
244 | { | |
245 | struct dspbridge_platform_data *pdata = pdev->dev.platform_data; | |
246 | struct drv_data *drv_datap = NULL; | |
247 | u32 phys_membase, phys_memsize; | |
248 | int err; | |
249 | ||
b3d23688 | 250 | #ifdef CONFIG_TIDSPBRIDGE_RECOVERY |
7d55524d ORL |
251 | bridge_rec_queue = create_workqueue("bridge_rec_queue"); |
252 | INIT_WORK(&bridge_recovery_work, bridge_recover); | |
253 | INIT_COMPLETION(bridge_comp); | |
254 | #endif | |
255 | ||
256 | #ifdef CONFIG_PM | |
257 | /* Initialize the wait queue */ | |
258 | bridge_suspend_data.suspended = 0; | |
259 | init_waitqueue_head(&bridge_suspend_data.suspend_wq); | |
260 | ||
b3d23688 | 261 | #ifdef CONFIG_TIDSPBRIDGE_DVFS |
7d55524d ORL |
262 | for (i = 0; i < 6; i++) |
263 | pdata->mpu_speed[i] = vdd1_rate_table_bridge[i].rate; | |
264 | ||
265 | err = cpufreq_register_notifier(&iva_clk_notifier, | |
266 | CPUFREQ_TRANSITION_NOTIFIER); | |
267 | if (err) | |
268 | pr_err("%s: clk_notifier_register failed for iva2_ck\n", | |
269 | __func__); | |
270 | #endif | |
271 | #endif | |
272 | ||
273 | dsp_clk_init(); | |
274 | services_init(); | |
275 | ||
276 | drv_datap = kzalloc(sizeof(struct drv_data), GFP_KERNEL); | |
277 | if (!drv_datap) { | |
278 | err = -ENOMEM; | |
279 | goto err1; | |
280 | } | |
281 | ||
282 | drv_datap->shm_size = shm_size; | |
283 | drv_datap->tc_wordswapon = tc_wordswapon; | |
284 | ||
285 | if (base_img) { | |
286 | drv_datap->base_img = kmalloc(strlen(base_img) + 1, GFP_KERNEL); | |
287 | if (!drv_datap->base_img) { | |
288 | err = -ENOMEM; | |
289 | goto err2; | |
290 | } | |
291 | strncpy(drv_datap->base_img, base_img, strlen(base_img) + 1); | |
292 | } | |
293 | ||
294 | dev_set_drvdata(bridge, drv_datap); | |
295 | ||
296 | if (shm_size < 0x10000) { /* 64 KB */ | |
297 | err = -EINVAL; | |
298 | pr_err("%s: shm size must be at least 64 KB\n", __func__); | |
299 | goto err3; | |
300 | } | |
301 | dev_dbg(bridge, "%s: requested shm_size = 0x%x\n", __func__, shm_size); | |
302 | ||
303 | phys_membase = pdata->phys_mempool_base; | |
304 | phys_memsize = pdata->phys_mempool_size; | |
305 | if (phys_membase > 0 && phys_memsize > 0) | |
306 | mem_ext_phys_pool_init(phys_membase, phys_memsize); | |
307 | ||
308 | if (tc_wordswapon) | |
309 | dev_dbg(bridge, "%s: TC Word Swap is enabled\n", __func__); | |
310 | ||
311 | driver_context = dsp_init(&err); | |
312 | if (err) { | |
313 | pr_err("DSP Bridge driver initialization failed\n"); | |
314 | goto err4; | |
315 | } | |
316 | ||
317 | return 0; | |
318 | ||
319 | err4: | |
320 | mem_ext_phys_pool_release(); | |
321 | err3: | |
322 | kfree(drv_datap->base_img); | |
323 | err2: | |
324 | kfree(drv_datap); | |
325 | err1: | |
b3d23688 | 326 | #ifdef CONFIG_TIDSPBRIDGE_DVFS |
7d55524d ORL |
327 | cpufreq_unregister_notifier(&iva_clk_notifier, |
328 | CPUFREQ_TRANSITION_NOTIFIER); | |
329 | #endif | |
330 | dsp_clk_exit(); | |
331 | services_exit(); | |
332 | ||
333 | return err; | |
334 | } | |
335 | ||
336 | static int __devinit omap34_xx_bridge_probe(struct platform_device *pdev) | |
337 | { | |
338 | int err; | |
339 | dev_t dev = 0; | |
b3d23688 | 340 | #ifdef CONFIG_TIDSPBRIDGE_DVFS |
7d55524d ORL |
341 | int i = 0; |
342 | #endif | |
343 | ||
344 | omap_dspbridge_dev = pdev; | |
345 | ||
346 | /* Global bridge device */ | |
347 | bridge = &omap_dspbridge_dev->dev; | |
348 | ||
349 | /* Bridge low level initializations */ | |
350 | err = omap3_bridge_startup(pdev); | |
351 | if (err) | |
352 | goto err1; | |
353 | ||
354 | /* use 2.6 device model */ | |
355 | err = alloc_chrdev_region(&dev, 0, 1, driver_name); | |
356 | if (err) { | |
357 | pr_err("%s: Can't get major %d\n", __func__, driver_major); | |
358 | goto err1; | |
359 | } | |
360 | ||
361 | cdev_init(&bridge_cdev, &bridge_fops); | |
362 | bridge_cdev.owner = THIS_MODULE; | |
363 | ||
364 | err = cdev_add(&bridge_cdev, dev, 1); | |
365 | if (err) { | |
366 | pr_err("%s: Failed to add bridge device\n", __func__); | |
367 | goto err2; | |
368 | } | |
369 | ||
370 | /* udev support */ | |
371 | bridge_class = class_create(THIS_MODULE, "ti_bridge"); | |
372 | if (IS_ERR(bridge_class)) { | |
373 | pr_err("%s: Error creating bridge class\n", __func__); | |
374 | goto err3; | |
375 | } | |
376 | ||
377 | driver_major = MAJOR(dev); | |
378 | device_create(bridge_class, NULL, MKDEV(driver_major, 0), | |
379 | NULL, "DspBridge"); | |
380 | pr_info("DSP Bridge driver loaded\n"); | |
381 | ||
382 | return 0; | |
383 | ||
384 | err3: | |
385 | cdev_del(&bridge_cdev); | |
386 | err2: | |
387 | unregister_chrdev_region(dev, 1); | |
388 | err1: | |
389 | return err; | |
390 | } | |
391 | ||
392 | static int __devexit omap34_xx_bridge_remove(struct platform_device *pdev) | |
393 | { | |
394 | dev_t devno; | |
395 | bool ret; | |
396 | int status = 0; | |
397 | void *hdrv_obj = NULL; | |
398 | ||
399 | status = cfg_get_object((u32 *) &hdrv_obj, REG_DRV_OBJECT); | |
400 | if (DSP_FAILED(status)) | |
401 | goto func_cont; | |
402 | ||
b3d23688 | 403 | #ifdef CONFIG_TIDSPBRIDGE_DVFS |
7d55524d ORL |
404 | if (cpufreq_unregister_notifier(&iva_clk_notifier, |
405 | CPUFREQ_TRANSITION_NOTIFIER)) | |
406 | pr_err("%s: cpufreq_unregister_notifier failed for iva2_ck\n", | |
407 | __func__); | |
b3d23688 | 408 | #endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */ |
7d55524d ORL |
409 | |
410 | if (driver_context) { | |
411 | /* Put the DSP in reset state */ | |
412 | ret = dsp_deinit(driver_context); | |
413 | driver_context = 0; | |
414 | DBC_ASSERT(ret == true); | |
415 | } | |
416 | ||
417 | func_cont: | |
418 | mem_ext_phys_pool_release(); | |
419 | ||
420 | dsp_clk_exit(); | |
421 | services_exit(); | |
422 | ||
423 | devno = MKDEV(driver_major, 0); | |
424 | cdev_del(&bridge_cdev); | |
425 | unregister_chrdev_region(devno, 1); | |
426 | if (bridge_class) { | |
427 | /* remove the device from sysfs */ | |
428 | device_destroy(bridge_class, MKDEV(driver_major, 0)); | |
429 | class_destroy(bridge_class); | |
430 | ||
431 | } | |
432 | return 0; | |
433 | } | |
434 | ||
435 | #ifdef CONFIG_PM | |
436 | static int BRIDGE_SUSPEND(struct platform_device *pdev, pm_message_t state) | |
437 | { | |
438 | u32 status; | |
439 | u32 command = PWR_EMERGENCYDEEPSLEEP; | |
440 | ||
441 | status = pwr_sleep_dsp(command, time_out); | |
442 | if (DSP_FAILED(status)) | |
443 | return -1; | |
444 | ||
445 | bridge_suspend_data.suspended = 1; | |
446 | return 0; | |
447 | } | |
448 | ||
449 | static int BRIDGE_RESUME(struct platform_device *pdev) | |
450 | { | |
451 | u32 status; | |
452 | ||
453 | status = pwr_wake_dsp(time_out); | |
454 | if (DSP_FAILED(status)) | |
455 | return -1; | |
456 | ||
457 | bridge_suspend_data.suspended = 0; | |
458 | wake_up(&bridge_suspend_data.suspend_wq); | |
459 | return 0; | |
460 | } | |
461 | #else | |
462 | #define BRIDGE_SUSPEND NULL | |
463 | #define BRIDGE_RESUME NULL | |
464 | #endif | |
465 | ||
466 | static struct platform_driver bridge_driver = { | |
467 | .driver = { | |
468 | .name = BRIDGE_NAME, | |
469 | }, | |
470 | .probe = omap34_xx_bridge_probe, | |
471 | .remove = __devexit_p(omap34_xx_bridge_remove), | |
472 | .suspend = BRIDGE_SUSPEND, | |
473 | .resume = BRIDGE_RESUME, | |
474 | }; | |
475 | ||
476 | static int __init bridge_init(void) | |
477 | { | |
478 | return platform_driver_register(&bridge_driver); | |
479 | } | |
480 | ||
481 | static void __exit bridge_exit(void) | |
482 | { | |
483 | platform_driver_unregister(&bridge_driver); | |
484 | } | |
485 | ||
486 | /* | |
487 | * This function is called when an application opens handle to the | |
488 | * bridge driver. | |
489 | */ | |
490 | static int bridge_open(struct inode *ip, struct file *filp) | |
491 | { | |
492 | int status = 0; | |
493 | struct process_context *pr_ctxt = NULL; | |
494 | ||
495 | /* | |
496 | * Allocate a new process context and insert it into global | |
497 | * process context list. | |
498 | */ | |
499 | ||
b3d23688 | 500 | #ifdef CONFIG_TIDSPBRIDGE_RECOVERY |
7d55524d ORL |
501 | if (recover) { |
502 | if (filp->f_flags & O_NONBLOCK || | |
503 | wait_for_completion_interruptible(&bridge_open_comp)) | |
504 | return -EBUSY; | |
505 | } | |
506 | #endif | |
507 | pr_ctxt = kzalloc(sizeof(struct process_context), GFP_KERNEL); | |
508 | if (pr_ctxt) { | |
509 | pr_ctxt->res_state = PROC_RES_ALLOCATED; | |
510 | spin_lock_init(&pr_ctxt->dmm_map_lock); | |
511 | INIT_LIST_HEAD(&pr_ctxt->dmm_map_list); | |
512 | spin_lock_init(&pr_ctxt->dmm_rsv_lock); | |
513 | INIT_LIST_HEAD(&pr_ctxt->dmm_rsv_list); | |
514 | mutex_init(&pr_ctxt->node_mutex); | |
515 | mutex_init(&pr_ctxt->strm_mutex); | |
516 | } else { | |
517 | status = -ENOMEM; | |
518 | } | |
519 | ||
520 | filp->private_data = pr_ctxt; | |
b3d23688 | 521 | #ifdef CONFIG_TIDSPBRIDGE_RECOVERY |
7d55524d ORL |
522 | if (!status) |
523 | atomic_inc(&bridge_cref); | |
524 | #endif | |
525 | return status; | |
526 | } | |
527 | ||
528 | /* | |
529 | * This function is called when an application closes handle to the bridge | |
530 | * driver. | |
531 | */ | |
532 | static int bridge_release(struct inode *ip, struct file *filp) | |
533 | { | |
534 | int status = 0; | |
535 | struct process_context *pr_ctxt; | |
536 | ||
537 | if (!filp->private_data) { | |
538 | status = -EIO; | |
539 | goto err; | |
540 | } | |
541 | ||
542 | pr_ctxt = filp->private_data; | |
543 | flush_signals(current); | |
544 | drv_remove_all_resources(pr_ctxt); | |
545 | proc_detach(pr_ctxt); | |
546 | kfree(pr_ctxt); | |
547 | ||
548 | filp->private_data = NULL; | |
549 | ||
550 | err: | |
b3d23688 | 551 | #ifdef CONFIG_TIDSPBRIDGE_RECOVERY |
7d55524d ORL |
552 | if (!atomic_dec_return(&bridge_cref)) |
553 | complete(&bridge_comp); | |
554 | #endif | |
555 | return status; | |
556 | } | |
557 | ||
558 | /* This function provides IO interface to the bridge driver. */ | |
559 | static long bridge_ioctl(struct file *filp, unsigned int code, | |
560 | unsigned long args) | |
561 | { | |
562 | int status; | |
563 | u32 retval = 0; | |
564 | union Trapped_Args buf_in; | |
565 | ||
566 | DBC_REQUIRE(filp != NULL); | |
b3d23688 | 567 | #ifdef CONFIG_TIDSPBRIDGE_RECOVERY |
7d55524d ORL |
568 | if (recover) { |
569 | status = -EIO; | |
570 | goto err; | |
571 | } | |
572 | #endif | |
573 | #ifdef CONFIG_PM | |
574 | status = omap34_xxbridge_suspend_lockout(&bridge_suspend_data, filp); | |
575 | if (status != 0) | |
576 | return status; | |
577 | #endif | |
578 | ||
579 | if (!filp->private_data) { | |
580 | status = -EIO; | |
581 | goto err; | |
582 | } | |
583 | ||
584 | status = copy_from_user(&buf_in, (union Trapped_Args *)args, | |
585 | sizeof(union Trapped_Args)); | |
586 | ||
587 | if (!status) { | |
588 | status = api_call_dev_ioctl(code, &buf_in, &retval, | |
589 | filp->private_data); | |
590 | ||
591 | if (DSP_SUCCEEDED(status)) { | |
592 | status = retval; | |
593 | } else { | |
594 | dev_dbg(bridge, "%s: IOCTL Failed, code: 0x%x " | |
595 | "status 0x%x\n", __func__, code, status); | |
596 | status = -1; | |
597 | } | |
598 | ||
599 | } | |
600 | ||
601 | err: | |
602 | return status; | |
603 | } | |
604 | ||
605 | /* This function maps kernel space memory to user space memory. */ | |
606 | static int bridge_mmap(struct file *filp, struct vm_area_struct *vma) | |
607 | { | |
608 | u32 offset = vma->vm_pgoff << PAGE_SHIFT; | |
609 | u32 status; | |
610 | ||
611 | DBC_ASSERT(vma->vm_start < vma->vm_end); | |
612 | ||
613 | vma->vm_flags |= VM_RESERVED | VM_IO; | |
614 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | |
615 | ||
616 | dev_dbg(bridge, "%s: vm filp %p offset %x start %lx end %lx page_prot " | |
617 | "%lx flags %lx\n", __func__, filp, offset, | |
618 | vma->vm_start, vma->vm_end, vma->vm_page_prot, vma->vm_flags); | |
619 | ||
620 | status = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, | |
621 | vma->vm_end - vma->vm_start, | |
622 | vma->vm_page_prot); | |
623 | if (status != 0) | |
624 | status = -EAGAIN; | |
625 | ||
626 | return status; | |
627 | } | |
628 | ||
629 | /* To remove all process resources before removing the process from the | |
630 | * process context list */ | |
631 | int drv_remove_all_resources(void *hPCtxt) | |
632 | { | |
633 | int status = 0; | |
634 | struct process_context *ctxt = (struct process_context *)hPCtxt; | |
635 | drv_remove_all_strm_res_elements(ctxt); | |
636 | drv_remove_all_node_res_elements(ctxt); | |
637 | drv_remove_all_dmm_res_elements(ctxt); | |
638 | ctxt->res_state = PROC_RES_FREED; | |
639 | return status; | |
640 | } | |
641 | ||
642 | /* Bridge driver initialization and de-initialization functions */ | |
643 | module_init(bridge_init); | |
644 | module_exit(bridge_exit); |