• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 Google, Inc.
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 <video/adf_client.h>
16 
17 #include "adf.h"
18 #include "adf_fops.h"
19 #include "adf_sysfs.h"
20 
21 static struct class *adf_class;
22 static int adf_major;
23 static DEFINE_IDR(adf_minors);
24 
25 #define dev_to_adf_interface(p) \
26 	adf_obj_to_interface(container_of(p, struct adf_obj, dev))
27 
dpms_state_show(struct device * dev,struct device_attribute * attr,char * buf)28 static ssize_t dpms_state_show(struct device *dev,
29 		struct device_attribute *attr, char *buf)
30 {
31 	struct adf_interface *intf = dev_to_adf_interface(dev);
32 	return scnprintf(buf, PAGE_SIZE, "%u\n",
33 			adf_interface_dpms_state(intf));
34 }
35 
dpms_state_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)36 static ssize_t dpms_state_store(struct device *dev,
37 		struct device_attribute *attr, const char *buf, size_t count)
38 {
39 	struct adf_interface *intf = dev_to_adf_interface(dev);
40 	u8 dpms_state;
41 	int err;
42 
43 	err = kstrtou8(buf, 0, &dpms_state);
44 	if (err < 0)
45 		return err;
46 
47 	err = adf_interface_blank(intf, dpms_state);
48 	if (err < 0)
49 		return err;
50 
51 	return count;
52 }
53 
current_mode_show(struct device * dev,struct device_attribute * attr,char * buf)54 static ssize_t current_mode_show(struct device *dev,
55 		struct device_attribute *attr, char *buf)
56 {
57 	struct adf_interface *intf = dev_to_adf_interface(dev);
58 	struct drm_mode_modeinfo mode;
59 
60 	adf_interface_current_mode(intf, &mode);
61 
62 	if (mode.name[0]) {
63 		return scnprintf(buf, PAGE_SIZE, "%s\n", mode.name);
64 	} else {
65 		bool interlaced = !!(mode.flags & DRM_MODE_FLAG_INTERLACE);
66 		return scnprintf(buf, PAGE_SIZE, "%ux%u%s\n", mode.hdisplay,
67 				mode.vdisplay, interlaced ? "i" : "");
68 	}
69 }
70 
type_show(struct device * dev,struct device_attribute * attr,char * buf)71 static ssize_t type_show(struct device *dev, struct device_attribute *attr,
72 			char *buf)
73 {
74 	struct adf_interface *intf = dev_to_adf_interface(dev);
75 	return scnprintf(buf, PAGE_SIZE, "%s\n",
76 			adf_interface_type_str(intf));
77 }
78 
vsync_timestamp_show(struct device * dev,struct device_attribute * attr,char * buf)79 static ssize_t vsync_timestamp_show(struct device *dev,
80 		struct device_attribute *attr, char *buf)
81 {
82 	struct adf_interface *intf = dev_to_adf_interface(dev);
83 	ktime_t timestamp;
84 	unsigned long flags;
85 
86 	read_lock_irqsave(&intf->vsync_lock, flags);
87 	memcpy(&timestamp, &intf->vsync_timestamp, sizeof(timestamp));
88 	read_unlock_irqrestore(&intf->vsync_lock, flags);
89 
90 	return scnprintf(buf, PAGE_SIZE, "%llu\n", ktime_to_ns(timestamp));
91 }
92 
hotplug_detect_show(struct device * dev,struct device_attribute * attr,char * buf)93 static ssize_t hotplug_detect_show(struct device *dev,
94 		struct device_attribute *attr, char *buf)
95 {
96 	struct adf_interface *intf = dev_to_adf_interface(dev);
97 	return scnprintf(buf, PAGE_SIZE, "%u\n", intf->hotplug_detect);
98 }
99 
100 static struct device_attribute adf_interface_attrs[] = {
101 	__ATTR(dpms_state, S_IRUGO|S_IWUSR, dpms_state_show, dpms_state_store),
102 	__ATTR_RO(current_mode),
103 	__ATTR_RO(hotplug_detect),
104 	__ATTR_RO(type),
105 	__ATTR_RO(vsync_timestamp),
106 };
107 
adf_obj_sysfs_init(struct adf_obj * obj,struct device * parent)108 int adf_obj_sysfs_init(struct adf_obj *obj, struct device *parent)
109 {
110 	int ret = idr_alloc(&adf_minors, obj, 0, 0, GFP_KERNEL);
111 	if (ret < 0) {
112 		pr_err("%s: allocating adf minor failed: %d\n", __func__,
113 				ret);
114 		return ret;
115 	}
116 
117 	obj->minor = ret;
118 	obj->dev.parent = parent;
119 	obj->dev.class = adf_class;
120 	obj->dev.devt = MKDEV(adf_major, obj->minor);
121 
122 	ret = device_register(&obj->dev);
123 	if (ret < 0) {
124 		pr_err("%s: registering adf object failed: %d\n", __func__,
125 				ret);
126 		goto err_device_register;
127 	}
128 
129 	return 0;
130 
131 err_device_register:
132 	idr_remove(&adf_minors, obj->minor);
133 	return ret;
134 }
135 
adf_device_devnode(struct device * dev,umode_t * mode,kuid_t * uid,kgid_t * gid)136 static char *adf_device_devnode(struct device *dev, umode_t *mode,
137 		kuid_t *uid, kgid_t *gid)
138 {
139 	struct adf_obj *obj = container_of(dev, struct adf_obj, dev);
140 	return kasprintf(GFP_KERNEL, "adf%d", obj->id);
141 }
142 
adf_interface_devnode(struct device * dev,umode_t * mode,kuid_t * uid,kgid_t * gid)143 static char *adf_interface_devnode(struct device *dev, umode_t *mode,
144 		kuid_t *uid, kgid_t *gid)
145 {
146 	struct adf_obj *obj = container_of(dev, struct adf_obj, dev);
147 	struct adf_interface *intf = adf_obj_to_interface(obj);
148 	struct adf_device *parent = adf_interface_parent(intf);
149 	return kasprintf(GFP_KERNEL, "adf-interface%d.%d",
150 			parent->base.id, intf->base.id);
151 }
152 
adf_overlay_engine_devnode(struct device * dev,umode_t * mode,kuid_t * uid,kgid_t * gid)153 static char *adf_overlay_engine_devnode(struct device *dev, umode_t *mode,
154 		kuid_t *uid, kgid_t *gid)
155 {
156 	struct adf_obj *obj = container_of(dev, struct adf_obj, dev);
157 	struct adf_overlay_engine *eng = adf_obj_to_overlay_engine(obj);
158 	struct adf_device *parent = adf_overlay_engine_parent(eng);
159 	return kasprintf(GFP_KERNEL, "adf-overlay-engine%d.%d",
160 			parent->base.id, eng->base.id);
161 }
162 
adf_noop_release(struct device * dev)163 static void adf_noop_release(struct device *dev)
164 {
165 }
166 
167 static struct device_type adf_device_type = {
168 	.name = "adf_device",
169 	.devnode = adf_device_devnode,
170 	.release = adf_noop_release,
171 };
172 
173 static struct device_type adf_interface_type = {
174 	.name = "adf_interface",
175 	.devnode = adf_interface_devnode,
176 	.release = adf_noop_release,
177 };
178 
179 static struct device_type adf_overlay_engine_type = {
180 	.name = "adf_overlay_engine",
181 	.devnode = adf_overlay_engine_devnode,
182 	.release = adf_noop_release,
183 };
184 
adf_device_sysfs_init(struct adf_device * dev)185 int adf_device_sysfs_init(struct adf_device *dev)
186 {
187 	dev->base.dev.type = &adf_device_type;
188 	dev_set_name(&dev->base.dev, "%s", dev->base.name);
189 	return adf_obj_sysfs_init(&dev->base, dev->dev);
190 }
191 
adf_interface_sysfs_init(struct adf_interface * intf)192 int adf_interface_sysfs_init(struct adf_interface *intf)
193 {
194 	struct adf_device *parent = adf_interface_parent(intf);
195 	size_t i, j;
196 	int ret;
197 
198 	intf->base.dev.type = &adf_interface_type;
199 	dev_set_name(&intf->base.dev, "%s-interface%d", parent->base.name,
200 			intf->base.id);
201 
202 	ret = adf_obj_sysfs_init(&intf->base, &parent->base.dev);
203 	if (ret < 0)
204 		return ret;
205 
206 	for (i = 0; i < ARRAY_SIZE(adf_interface_attrs); i++) {
207 		ret = device_create_file(&intf->base.dev,
208 				&adf_interface_attrs[i]);
209 		if (ret < 0) {
210 			dev_err(&intf->base.dev, "creating sysfs attribute %s failed: %d\n",
211 					adf_interface_attrs[i].attr.name, ret);
212 			goto err;
213 		}
214 	}
215 
216 	return 0;
217 
218 err:
219 	for (j = 0; j < i; j++)
220 		device_remove_file(&intf->base.dev, &adf_interface_attrs[j]);
221 	return ret;
222 }
223 
adf_overlay_engine_sysfs_init(struct adf_overlay_engine * eng)224 int adf_overlay_engine_sysfs_init(struct adf_overlay_engine *eng)
225 {
226 	struct adf_device *parent = adf_overlay_engine_parent(eng);
227 
228 	eng->base.dev.type = &adf_overlay_engine_type;
229 	dev_set_name(&eng->base.dev, "%s-overlay-engine%d", parent->base.name,
230 			eng->base.id);
231 
232 	return adf_obj_sysfs_init(&eng->base, &parent->base.dev);
233 }
234 
adf_obj_sysfs_find(int minor)235 struct adf_obj *adf_obj_sysfs_find(int minor)
236 {
237 	return idr_find(&adf_minors, minor);
238 }
239 
adf_obj_sysfs_destroy(struct adf_obj * obj)240 void adf_obj_sysfs_destroy(struct adf_obj *obj)
241 {
242 	idr_remove(&adf_minors, obj->minor);
243 	device_unregister(&obj->dev);
244 }
245 
adf_device_sysfs_destroy(struct adf_device * dev)246 void adf_device_sysfs_destroy(struct adf_device *dev)
247 {
248 	adf_obj_sysfs_destroy(&dev->base);
249 }
250 
adf_interface_sysfs_destroy(struct adf_interface * intf)251 void adf_interface_sysfs_destroy(struct adf_interface *intf)
252 {
253 	size_t i;
254 
255 	for (i = 0; i < ARRAY_SIZE(adf_interface_attrs); i++)
256 		device_remove_file(&intf->base.dev, &adf_interface_attrs[i]);
257 	adf_obj_sysfs_destroy(&intf->base);
258 }
259 
adf_overlay_engine_sysfs_destroy(struct adf_overlay_engine * eng)260 void adf_overlay_engine_sysfs_destroy(struct adf_overlay_engine *eng)
261 {
262 	adf_obj_sysfs_destroy(&eng->base);
263 }
264 
adf_sysfs_init(void)265 int adf_sysfs_init(void)
266 {
267 	struct class *class;
268 	int ret;
269 
270 	class = class_create(THIS_MODULE, "adf");
271 	if (IS_ERR(class)) {
272 		ret = PTR_ERR(class);
273 		pr_err("%s: creating class failed: %d\n", __func__, ret);
274 		return ret;
275 	}
276 
277 	ret = register_chrdev(0, "adf", &adf_fops);
278 	if (ret < 0) {
279 		pr_err("%s: registering device failed: %d\n", __func__, ret);
280 		goto err_chrdev;
281 	}
282 
283 	adf_class = class;
284 	adf_major = ret;
285 	return 0;
286 
287 err_chrdev:
288 	class_destroy(adf_class);
289 	return ret;
290 }
291 
adf_sysfs_destroy(void)292 void adf_sysfs_destroy(void)
293 {
294 	idr_destroy(&adf_minors);
295 	class_destroy(adf_class);
296 }
297