1 /*
2  * linux/drivers/video/omap2/dss/manager.c
3  *
4  * Copyright (C) 2009 Nokia Corporation
5  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6  *
7  * Some code and ideas taken from drivers/video/omap/ driver
8  * by Imre Deak.
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License version 2 as published by
12  * the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17  * more details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #define DSS_SUBSYS_NAME "MANAGER"
24 
25 #include <linux/kernel.h>
26 #include <linux/slab.h>
27 #include <linux/module.h>
28 #include <linux/platform_device.h>
29 #include <linux/jiffies.h>
30 
31 #include <video/omapdss.h>
32 
33 #include "dss.h"
34 #include "dss_features.h"
35 
36 static int num_managers;
37 static struct omap_overlay_manager *managers;
38 
manager_name_show(struct omap_overlay_manager * mgr,char * buf)39 static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
40 {
41 	return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
42 }
43 
manager_display_show(struct omap_overlay_manager * mgr,char * buf)44 static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
45 {
46 	return snprintf(buf, PAGE_SIZE, "%s\n",
47 			mgr->device ? mgr->device->name : "<none>");
48 }
49 
manager_display_store(struct omap_overlay_manager * mgr,const char * buf,size_t size)50 static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
51 		const char *buf, size_t size)
52 {
53 	int r = 0;
54 	size_t len = size;
55 	struct omap_dss_device *dssdev = NULL;
56 
57 	int match(struct omap_dss_device *dssdev, void *data)
58 	{
59 		const char *str = data;
60 		return sysfs_streq(dssdev->name, str);
61 	}
62 
63 	if (buf[size-1] == '\n')
64 		--len;
65 
66 	if (len > 0)
67 		dssdev = omap_dss_find_device((void *)buf, match);
68 
69 	if (len > 0 && dssdev == NULL)
70 		return -EINVAL;
71 
72 	if (dssdev)
73 		DSSDBG("display %s found\n", dssdev->name);
74 
75 	if (mgr->device) {
76 		r = mgr->unset_device(mgr);
77 		if (r) {
78 			DSSERR("failed to unset display\n");
79 			goto put_device;
80 		}
81 	}
82 
83 	if (dssdev) {
84 		r = mgr->set_device(mgr, dssdev);
85 		if (r) {
86 			DSSERR("failed to set manager\n");
87 			goto put_device;
88 		}
89 
90 		r = mgr->apply(mgr);
91 		if (r) {
92 			DSSERR("failed to apply dispc config\n");
93 			goto put_device;
94 		}
95 	}
96 
97 put_device:
98 	if (dssdev)
99 		omap_dss_put_device(dssdev);
100 
101 	return r ? r : size;
102 }
103 
manager_default_color_show(struct omap_overlay_manager * mgr,char * buf)104 static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
105 					  char *buf)
106 {
107 	struct omap_overlay_manager_info info;
108 
109 	mgr->get_manager_info(mgr, &info);
110 
111 	return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color);
112 }
113 
manager_default_color_store(struct omap_overlay_manager * mgr,const char * buf,size_t size)114 static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
115 					   const char *buf, size_t size)
116 {
117 	struct omap_overlay_manager_info info;
118 	u32 color;
119 	int r;
120 
121 	r = kstrtouint(buf, 0, &color);
122 	if (r)
123 		return r;
124 
125 	mgr->get_manager_info(mgr, &info);
126 
127 	info.default_color = color;
128 
129 	r = mgr->set_manager_info(mgr, &info);
130 	if (r)
131 		return r;
132 
133 	r = mgr->apply(mgr);
134 	if (r)
135 		return r;
136 
137 	return size;
138 }
139 
140 static const char *trans_key_type_str[] = {
141 	"gfx-destination",
142 	"video-source",
143 };
144 
manager_trans_key_type_show(struct omap_overlay_manager * mgr,char * buf)145 static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
146 					   char *buf)
147 {
148 	enum omap_dss_trans_key_type key_type;
149 	struct omap_overlay_manager_info info;
150 
151 	mgr->get_manager_info(mgr, &info);
152 
153 	key_type = info.trans_key_type;
154 	BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
155 
156 	return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
157 }
158 
manager_trans_key_type_store(struct omap_overlay_manager * mgr,const char * buf,size_t size)159 static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
160 					    const char *buf, size_t size)
161 {
162 	enum omap_dss_trans_key_type key_type;
163 	struct omap_overlay_manager_info info;
164 	int r;
165 
166 	for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
167 			key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
168 		if (sysfs_streq(buf, trans_key_type_str[key_type]))
169 			break;
170 	}
171 
172 	if (key_type == ARRAY_SIZE(trans_key_type_str))
173 		return -EINVAL;
174 
175 	mgr->get_manager_info(mgr, &info);
176 
177 	info.trans_key_type = key_type;
178 
179 	r = mgr->set_manager_info(mgr, &info);
180 	if (r)
181 		return r;
182 
183 	r = mgr->apply(mgr);
184 	if (r)
185 		return r;
186 
187 	return size;
188 }
189 
manager_trans_key_value_show(struct omap_overlay_manager * mgr,char * buf)190 static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
191 					    char *buf)
192 {
193 	struct omap_overlay_manager_info info;
194 
195 	mgr->get_manager_info(mgr, &info);
196 
197 	return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key);
198 }
199 
manager_trans_key_value_store(struct omap_overlay_manager * mgr,const char * buf,size_t size)200 static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
201 					     const char *buf, size_t size)
202 {
203 	struct omap_overlay_manager_info info;
204 	u32 key_value;
205 	int r;
206 
207 	r = kstrtouint(buf, 0, &key_value);
208 	if (r)
209 		return r;
210 
211 	mgr->get_manager_info(mgr, &info);
212 
213 	info.trans_key = key_value;
214 
215 	r = mgr->set_manager_info(mgr, &info);
216 	if (r)
217 		return r;
218 
219 	r = mgr->apply(mgr);
220 	if (r)
221 		return r;
222 
223 	return size;
224 }
225 
manager_trans_key_enabled_show(struct omap_overlay_manager * mgr,char * buf)226 static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
227 					      char *buf)
228 {
229 	struct omap_overlay_manager_info info;
230 
231 	mgr->get_manager_info(mgr, &info);
232 
233 	return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled);
234 }
235 
manager_trans_key_enabled_store(struct omap_overlay_manager * mgr,const char * buf,size_t size)236 static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
237 					       const char *buf, size_t size)
238 {
239 	struct omap_overlay_manager_info info;
240 	bool enable;
241 	int r;
242 
243 	r = strtobool(buf, &enable);
244 	if (r)
245 		return r;
246 
247 	mgr->get_manager_info(mgr, &info);
248 
249 	info.trans_enabled = enable;
250 
251 	r = mgr->set_manager_info(mgr, &info);
252 	if (r)
253 		return r;
254 
255 	r = mgr->apply(mgr);
256 	if (r)
257 		return r;
258 
259 	return size;
260 }
261 
manager_alpha_blending_enabled_show(struct omap_overlay_manager * mgr,char * buf)262 static ssize_t manager_alpha_blending_enabled_show(
263 		struct omap_overlay_manager *mgr, char *buf)
264 {
265 	struct omap_overlay_manager_info info;
266 
267 	mgr->get_manager_info(mgr, &info);
268 
269 	WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
270 
271 	return snprintf(buf, PAGE_SIZE, "%d\n",
272 		info.partial_alpha_enabled);
273 }
274 
manager_alpha_blending_enabled_store(struct omap_overlay_manager * mgr,const char * buf,size_t size)275 static ssize_t manager_alpha_blending_enabled_store(
276 		struct omap_overlay_manager *mgr,
277 		const char *buf, size_t size)
278 {
279 	struct omap_overlay_manager_info info;
280 	bool enable;
281 	int r;
282 
283 	WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
284 
285 	r = strtobool(buf, &enable);
286 	if (r)
287 		return r;
288 
289 	mgr->get_manager_info(mgr, &info);
290 
291 	info.partial_alpha_enabled = enable;
292 
293 	r = mgr->set_manager_info(mgr, &info);
294 	if (r)
295 		return r;
296 
297 	r = mgr->apply(mgr);
298 	if (r)
299 		return r;
300 
301 	return size;
302 }
303 
manager_cpr_enable_show(struct omap_overlay_manager * mgr,char * buf)304 static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
305 		char *buf)
306 {
307 	struct omap_overlay_manager_info info;
308 
309 	mgr->get_manager_info(mgr, &info);
310 
311 	return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable);
312 }
313 
manager_cpr_enable_store(struct omap_overlay_manager * mgr,const char * buf,size_t size)314 static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
315 		const char *buf, size_t size)
316 {
317 	struct omap_overlay_manager_info info;
318 	int r;
319 	bool enable;
320 
321 	if (!dss_has_feature(FEAT_CPR))
322 		return -ENODEV;
323 
324 	r = strtobool(buf, &enable);
325 	if (r)
326 		return r;
327 
328 	mgr->get_manager_info(mgr, &info);
329 
330 	if (info.cpr_enable == enable)
331 		return size;
332 
333 	info.cpr_enable = enable;
334 
335 	r = mgr->set_manager_info(mgr, &info);
336 	if (r)
337 		return r;
338 
339 	r = mgr->apply(mgr);
340 	if (r)
341 		return r;
342 
343 	return size;
344 }
345 
manager_cpr_coef_show(struct omap_overlay_manager * mgr,char * buf)346 static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,
347 		char *buf)
348 {
349 	struct omap_overlay_manager_info info;
350 
351 	mgr->get_manager_info(mgr, &info);
352 
353 	return snprintf(buf, PAGE_SIZE,
354 			"%d %d %d %d %d %d %d %d %d\n",
355 			info.cpr_coefs.rr,
356 			info.cpr_coefs.rg,
357 			info.cpr_coefs.rb,
358 			info.cpr_coefs.gr,
359 			info.cpr_coefs.gg,
360 			info.cpr_coefs.gb,
361 			info.cpr_coefs.br,
362 			info.cpr_coefs.bg,
363 			info.cpr_coefs.bb);
364 }
365 
manager_cpr_coef_store(struct omap_overlay_manager * mgr,const char * buf,size_t size)366 static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,
367 		const char *buf, size_t size)
368 {
369 	struct omap_overlay_manager_info info;
370 	struct omap_dss_cpr_coefs coefs;
371 	int r, i;
372 	s16 *arr;
373 
374 	if (!dss_has_feature(FEAT_CPR))
375 		return -ENODEV;
376 
377 	if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",
378 				&coefs.rr, &coefs.rg, &coefs.rb,
379 				&coefs.gr, &coefs.gg, &coefs.gb,
380 				&coefs.br, &coefs.bg, &coefs.bb) != 9)
381 		return -EINVAL;
382 
383 	arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,
384 		coefs.gr, coefs.gg, coefs.gb,
385 		coefs.br, coefs.bg, coefs.bb };
386 
387 	for (i = 0; i < 9; ++i) {
388 		if (arr[i] < -512 || arr[i] > 511)
389 			return -EINVAL;
390 	}
391 
392 	mgr->get_manager_info(mgr, &info);
393 
394 	info.cpr_coefs = coefs;
395 
396 	r = mgr->set_manager_info(mgr, &info);
397 	if (r)
398 		return r;
399 
400 	r = mgr->apply(mgr);
401 	if (r)
402 		return r;
403 
404 	return size;
405 }
406 
407 struct manager_attribute {
408 	struct attribute attr;
409 	ssize_t (*show)(struct omap_overlay_manager *, char *);
410 	ssize_t	(*store)(struct omap_overlay_manager *, const char *, size_t);
411 };
412 
413 #define MANAGER_ATTR(_name, _mode, _show, _store) \
414 	struct manager_attribute manager_attr_##_name = \
415 	__ATTR(_name, _mode, _show, _store)
416 
417 static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
418 static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
419 		manager_display_show, manager_display_store);
420 static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
421 		manager_default_color_show, manager_default_color_store);
422 static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
423 		manager_trans_key_type_show, manager_trans_key_type_store);
424 static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
425 		manager_trans_key_value_show, manager_trans_key_value_store);
426 static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
427 		manager_trans_key_enabled_show,
428 		manager_trans_key_enabled_store);
429 static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
430 		manager_alpha_blending_enabled_show,
431 		manager_alpha_blending_enabled_store);
432 static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,
433 		manager_cpr_enable_show,
434 		manager_cpr_enable_store);
435 static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,
436 		manager_cpr_coef_show,
437 		manager_cpr_coef_store);
438 
439 
440 static struct attribute *manager_sysfs_attrs[] = {
441 	&manager_attr_name.attr,
442 	&manager_attr_display.attr,
443 	&manager_attr_default_color.attr,
444 	&manager_attr_trans_key_type.attr,
445 	&manager_attr_trans_key_value.attr,
446 	&manager_attr_trans_key_enabled.attr,
447 	&manager_attr_alpha_blending_enabled.attr,
448 	&manager_attr_cpr_enable.attr,
449 	&manager_attr_cpr_coef.attr,
450 	NULL
451 };
452 
manager_attr_show(struct kobject * kobj,struct attribute * attr,char * buf)453 static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
454 		char *buf)
455 {
456 	struct omap_overlay_manager *manager;
457 	struct manager_attribute *manager_attr;
458 
459 	manager = container_of(kobj, struct omap_overlay_manager, kobj);
460 	manager_attr = container_of(attr, struct manager_attribute, attr);
461 
462 	if (!manager_attr->show)
463 		return -ENOENT;
464 
465 	return manager_attr->show(manager, buf);
466 }
467 
manager_attr_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t size)468 static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
469 		const char *buf, size_t size)
470 {
471 	struct omap_overlay_manager *manager;
472 	struct manager_attribute *manager_attr;
473 
474 	manager = container_of(kobj, struct omap_overlay_manager, kobj);
475 	manager_attr = container_of(attr, struct manager_attribute, attr);
476 
477 	if (!manager_attr->store)
478 		return -ENOENT;
479 
480 	return manager_attr->store(manager, buf, size);
481 }
482 
483 static const struct sysfs_ops manager_sysfs_ops = {
484 	.show = manager_attr_show,
485 	.store = manager_attr_store,
486 };
487 
488 static struct kobj_type manager_ktype = {
489 	.sysfs_ops = &manager_sysfs_ops,
490 	.default_attrs = manager_sysfs_attrs,
491 };
492 
dss_mgr_wait_for_vsync(struct omap_overlay_manager * mgr)493 static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
494 {
495 	unsigned long timeout = msecs_to_jiffies(500);
496 	u32 irq;
497 	int r;
498 
499 	r = dispc_runtime_get();
500 	if (r)
501 		return r;
502 
503 	if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) {
504 		irq = DISPC_IRQ_EVSYNC_ODD;
505 	} else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) {
506 		irq = DISPC_IRQ_EVSYNC_EVEN;
507 	} else {
508 		if (mgr->id == OMAP_DSS_CHANNEL_LCD)
509 			irq = DISPC_IRQ_VSYNC;
510 		else
511 			irq = DISPC_IRQ_VSYNC2;
512 	}
513 
514 	r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
515 
516 	dispc_runtime_put();
517 
518 	return r;
519 }
520 
dss_init_overlay_managers(struct platform_device * pdev)521 int dss_init_overlay_managers(struct platform_device *pdev)
522 {
523 	int i, r;
524 
525 	num_managers = dss_feat_get_num_mgrs();
526 
527 	managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers,
528 			GFP_KERNEL);
529 
530 	BUG_ON(managers == NULL);
531 
532 	for (i = 0; i < num_managers; ++i) {
533 		struct omap_overlay_manager *mgr = &managers[i];
534 
535 		switch (i) {
536 		case 0:
537 			mgr->name = "lcd";
538 			mgr->id = OMAP_DSS_CHANNEL_LCD;
539 			break;
540 		case 1:
541 			mgr->name = "tv";
542 			mgr->id = OMAP_DSS_CHANNEL_DIGIT;
543 			break;
544 		case 2:
545 			mgr->name = "lcd2";
546 			mgr->id = OMAP_DSS_CHANNEL_LCD2;
547 			break;
548 		}
549 
550 		mgr->set_device = &dss_mgr_set_device;
551 		mgr->unset_device = &dss_mgr_unset_device;
552 		mgr->apply = &omap_dss_mgr_apply;
553 		mgr->set_manager_info = &dss_mgr_set_info;
554 		mgr->get_manager_info = &dss_mgr_get_info;
555 		mgr->wait_for_go = &dss_mgr_wait_for_go;
556 		mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
557 
558 		mgr->caps = 0;
559 		mgr->supported_displays =
560 			dss_feat_get_supported_displays(mgr->id);
561 
562 		INIT_LIST_HEAD(&mgr->overlays);
563 
564 		r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
565 				&pdev->dev.kobj, "manager%d", i);
566 
567 		if (r)
568 			DSSERR("failed to create sysfs file\n");
569 	}
570 
571 	return 0;
572 }
573 
dss_uninit_overlay_managers(struct platform_device * pdev)574 void dss_uninit_overlay_managers(struct platform_device *pdev)
575 {
576 	int i;
577 
578 	for (i = 0; i < num_managers; ++i) {
579 		struct omap_overlay_manager *mgr = &managers[i];
580 
581 		kobject_del(&mgr->kobj);
582 		kobject_put(&mgr->kobj);
583 	}
584 
585 	kfree(managers);
586 	managers = NULL;
587 	num_managers = 0;
588 }
589 
omap_dss_get_num_overlay_managers(void)590 int omap_dss_get_num_overlay_managers(void)
591 {
592 	return num_managers;
593 }
594 EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
595 
omap_dss_get_overlay_manager(int num)596 struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
597 {
598 	if (num >= num_managers)
599 		return NULL;
600 
601 	return &managers[num];
602 }
603 EXPORT_SYMBOL(omap_dss_get_overlay_manager);
604 
dss_mgr_simple_check(struct omap_overlay_manager * mgr,const struct omap_overlay_manager_info * info)605 int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
606 		const struct omap_overlay_manager_info *info)
607 {
608 	if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
609 		/*
610 		 * OMAP3 supports only graphics source transparency color key
611 		 * and alpha blending simultaneously. See TRM 15.4.2.4.2.2
612 		 * Alpha Mode.
613 		 */
614 		if (info->partial_alpha_enabled && info->trans_enabled
615 			&& info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) {
616 			DSSERR("check_manager: illegal transparency key\n");
617 			return -EINVAL;
618 		}
619 	}
620 
621 	return 0;
622 }
623 
dss_mgr_check_zorder(struct omap_overlay_manager * mgr,struct omap_overlay_info ** overlay_infos)624 static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr,
625 		struct omap_overlay_info **overlay_infos)
626 {
627 	struct omap_overlay *ovl1, *ovl2;
628 	struct omap_overlay_info *info1, *info2;
629 
630 	list_for_each_entry(ovl1, &mgr->overlays, list) {
631 		info1 = overlay_infos[ovl1->id];
632 
633 		if (info1 == NULL)
634 			continue;
635 
636 		list_for_each_entry(ovl2, &mgr->overlays, list) {
637 			if (ovl1 == ovl2)
638 				continue;
639 
640 			info2 = overlay_infos[ovl2->id];
641 
642 			if (info2 == NULL)
643 				continue;
644 
645 			if (info1->zorder == info2->zorder) {
646 				DSSERR("overlays %d and %d have the same "
647 						"zorder %d\n",
648 					ovl1->id, ovl2->id, info1->zorder);
649 				return -EINVAL;
650 			}
651 		}
652 	}
653 
654 	return 0;
655 }
656 
dss_mgr_check(struct omap_overlay_manager * mgr,struct omap_dss_device * dssdev,struct omap_overlay_manager_info * info,struct omap_overlay_info ** overlay_infos)657 int dss_mgr_check(struct omap_overlay_manager *mgr,
658 		struct omap_dss_device *dssdev,
659 		struct omap_overlay_manager_info *info,
660 		struct omap_overlay_info **overlay_infos)
661 {
662 	struct omap_overlay *ovl;
663 	int r;
664 
665 	if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) {
666 		r = dss_mgr_check_zorder(mgr, overlay_infos);
667 		if (r)
668 			return r;
669 	}
670 
671 	list_for_each_entry(ovl, &mgr->overlays, list) {
672 		struct omap_overlay_info *oi;
673 		int r;
674 
675 		oi = overlay_infos[ovl->id];
676 
677 		if (oi == NULL)
678 			continue;
679 
680 		r = dss_ovl_check(ovl, oi, dssdev);
681 		if (r)
682 			return r;
683 	}
684 
685 	return 0;
686 }
687