1 /* 2 * Copyright (C) 2019 Allwinnertech Co.Ltd 3 * Authors: zhengwanyu 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License as published by the 7 * Free Software Foundation; either version 2 of the License, or (at your 8 * option) any later version. 9 * 10 */ 11 #include <linux/device.h> 12 #include <linux/kernel.h> 13 #include <linux/fs.h> 14 15 #include "sunxi_drm_fb.h" 16 #include "sunxi_drm_plane.h" 17 #include "sunxi_drm_gem.h" 18 #include "sunxi_drm_crtc.h" 19 #include "sunxi_drm_encoder.h" 20 #include "sunxi_drm_connector.h" 21 #include "sunxi_drm_sysfs.h" 22 #include "sunxi_drm_drv.h" 23 24 #if 0 25 struct device *sunxi_drv_dev; 26 27 static ssize_t sunxi_planes_info_show(struct device *device, 28 struct device_attribute *attr, 29 char *buf) 30 { 31 ssize_t n = 0; 32 struct drm_device *drm_dev = sunxi_drm_get_drm_device(); 33 34 n += sunxi_drm_planes_show(buf + n, drm_dev, NULL); 35 36 return n; 37 } 38 39 static ssize_t sunxi_planes_info_store(struct device *device, 40 struct device_attribute *attr, 41 const char *buf, size_t count) 42 { 43 return count; 44 } 45 46 static DEVICE_ATTR(planes_info, 0660, sunxi_planes_info_show, sunxi_planes_info_store); 47 48 49 static ssize_t sunxi_crtc_info_show(struct device *device, 50 struct device_attribute *attr, 51 char *buf) 52 { 53 ssize_t n = 0; 54 struct drm_device *drm_dev = sunxi_drm_get_drm_device(); 55 56 n += sunxi_drm_crtc_show(buf + n, drm_dev); 57 58 return n; 59 } 60 61 static ssize_t sunxi_crtc_info_store(struct device *device, 62 struct device_attribute *attr, 63 const char *buf, size_t count) 64 { 65 return count; 66 } 67 68 static DEVICE_ATTR(crtc_info, 0660, sunxi_crtc_info_show, sunxi_crtc_info_store); 69 70 71 static unsigned int fb_id; 72 73 static char sunxi_printable_char(int c) 74 { 75 return isascii(c) && isprint(c) ? c : '?'; 76 } 77 78 char *sunxi_drm_get_path_name(char *dir, uint32_t format, 79 uint32_t w, uint32_t h) 80 { 81 char *buf = kmalloc(100, GFP_KERNEL); 82 83 snprintf(buf, 32, 84 "%s/%dx%d_%c%c%c%c", 85 dir, w, h, 86 sunxi_printable_char(format & 0xff), 87 sunxi_printable_char((format >> 8) & 0xff), 88 sunxi_printable_char((format >> 16) & 0xff), 89 sunxi_printable_char((format >> 24) & 0x7f)); 90 91 return buf; 92 } 93 94 static ssize_t sunxi_fb_capture_show(struct device *device, 95 struct device_attribute *attr, 96 char *buf) 97 { 98 ssize_t n = 0; 99 unsigned int i; 100 bool find = false; 101 struct drm_framebuffer *fb = NULL; 102 struct sunxi_drm_fb *sunxi_fb = NULL; 103 unsigned char *vaddr; 104 105 struct file *fp; 106 mm_segment_t fs; 107 loff_t pos; 108 109 char *path; 110 struct drm_device *dev = sunxi_drm_get_drm_device(); 111 112 mutex_lock(&dev->mode_config.fb_lock); 113 drm_for_each_fb(fb, dev) { 114 DRM_INFO("fb base id:%d\n", fb->base.id); 115 if (fb->base.id == fb_id) { 116 find = true; 117 break; 118 } 119 } 120 mutex_unlock(&dev->mode_config.fb_lock); 121 122 if (!find) { 123 DRM_ERROR("[ERROR]fb_id:%d is invalid!\n", fb_id); 124 return n; 125 } 126 127 sunxi_fb = to_sunxi_fb(fb); 128 129 path = sunxi_drm_get_path_name("/mnt", fb->pixel_format, 130 fb->width, fb->height); 131 if ((fb->pixel_format == DRM_FORMAT_XRGB8888) 132 || (fb->pixel_format == DRM_FORMAT_ARGB8888)) { 133 fp = filp_open(path, O_RDWR | O_CREAT, 0644); 134 if (IS_ERR(fp)) { 135 n += sprintf(buf + n, "create file error\n"); 136 kfree(path); 137 return n; 138 } 139 140 fs = get_fs(); 141 set_fs(KERNEL_DS); 142 143 vaddr = sunxi_fb->obj[0]->vaddr; 144 145 n += sprintf(buf + n, "Wait for capture!\n"); 146 pos = fp->f_pos; 147 vfs_write(fp, vaddr, fb->pitches[0] * fb->height, &pos); 148 n += sprintf(buf + n, "Capture finished!\n"); 149 150 set_fs(fs); 151 filp_close(fp, NULL); 152 } else if (fb->pixel_format == DRM_FORMAT_RGB888) { 153 unsigned char alpha = 0xff; 154 155 fp = filp_open(path, O_RDWR | O_CREAT, 0644); 156 if (IS_ERR(fp)) { 157 n += sprintf(buf + n, "create file error\n"); 158 kfree(path); 159 return n; 160 } 161 162 vaddr = sunxi_fb->obj[0]->vaddr; 163 164 fs = get_fs(); 165 set_fs(KERNEL_DS); 166 167 n += sprintf(buf + n, "Wait for capture, for 0~2 minute...\n"); 168 pos = fp->f_pos; 169 for (i = 0; i < fb->width * fb->height; i++) { 170 vfs_write(fp, &vaddr[3 * i], 3, &pos); 171 vfs_write(fp, &alpha, 1, &pos); 172 } 173 n += sprintf(buf + n, "Capture finished!\n"); 174 175 set_fs(fs); 176 filp_close(fp, NULL); 177 } else { 178 n += sprintf(buf + n, "[ERROR]NOT support format:%c%c%c%c\n", 179 (char)(fb->pixel_format & 0xff), 180 (char)((fb->pixel_format >> 8) & 0xff), 181 (char)((fb->pixel_format >> 16) & 0xff), 182 (char)((fb->pixel_format >> 24) & 0xff)); 183 } 184 185 n += sprintf(buf + n, "Program Finished!\n"); 186 kfree(path); 187 return n; 188 } 189 190 static ssize_t sunxi_fb_capture_store(struct device *device, 191 struct device_attribute *attr, 192 const char *buf, size_t count) 193 { 194 fb_id = simple_strtoul(buf, NULL, 0); 195 196 return count; 197 } 198 199 static DEVICE_ATTR(fb_capture, 0660, sunxi_fb_capture_show, 200 sunxi_fb_capture_store); 201 202 203 static ssize_t sunxi_drm_fb_info_dump(char *buf) 204 { 205 ssize_t n = 0; 206 struct drm_framebuffer *fb; 207 struct drm_device *dev = sunxi_drm_get_drm_device(); 208 209 mutex_lock(&dev->mode_config.fb_lock); 210 n += sprintf(buf + n, "fb num:%d\n", dev->mode_config.num_fb); 211 drm_for_each_fb(fb, dev) 212 n += sunxi_drm_fb_show(buf + n, fb); 213 mutex_unlock(&dev->mode_config.fb_lock); 214 215 return n; 216 } 217 218 static ssize_t sunxi_fb_info_show(struct device *device, 219 struct device_attribute *attr, 220 char *buf) 221 { 222 ssize_t n = 0; 223 224 n += sunxi_drm_fb_info_dump(buf + n); 225 226 return n; 227 } 228 229 static ssize_t sunxi_fb_info_store(struct device *device, 230 struct device_attribute *attr, 231 const char *buf, size_t count) 232 { 233 return count; 234 } 235 236 static DEVICE_ATTR(fb_info, 0660, sunxi_fb_info_show, sunxi_fb_info_store); 237 238 static ssize_t sunxi_encoder_info_show(struct device *device, 239 struct device_attribute *attr, 240 char *buf) 241 { 242 ssize_t n = 0; 243 struct drm_device *drm_dev = sunxi_drm_get_drm_device(); 244 245 n += sunxi_drm_encoder_show(buf + n, drm_dev); 246 247 return n; 248 } 249 250 static ssize_t sunxi_encoder_info_store(struct device *device, 251 struct device_attribute *attr, 252 const char *buf, size_t count) 253 { 254 return count; 255 } 256 257 static DEVICE_ATTR(encoder_info, 0660, sunxi_encoder_info_show, sunxi_encoder_info_store); 258 259 260 static ssize_t sunxi_connector_info_show(struct device *device, 261 struct device_attribute *attr, 262 char *buf) 263 { 264 ssize_t n = 0; 265 struct drm_device *drm_dev = sunxi_drm_get_drm_device(); 266 267 n += sunxi_drm_connector_show(buf + n, drm_dev); 268 269 return n; 270 } 271 272 static ssize_t sunxi_connector_info_store(struct device *device, 273 struct device_attribute *attr, 274 const char *buf, size_t count) 275 { 276 return count; 277 } 278 279 static DEVICE_ATTR(connector_info, 0660, sunxi_connector_info_show, sunxi_connector_info_store); 280 281 282 static ssize_t sunxi_drm_debug_show(struct device *device, 283 struct device_attribute *attr, 284 char *buf) 285 { 286 ssize_t n = 0; 287 288 n += sprintf(buf + n, "drm_debug=%u\n\n", drm_debug); 289 n += sprintf(buf + n, "params explain:\n"); 290 n += sprintf(buf + n, "NONE print:0x00\n"); 291 n += sprintf(buf + n, "CORE print:0x01\n"); 292 n += sprintf(buf + n, "DRIVER print:0x02\n"); 293 n += sprintf(buf + n, "KMS print:0x04\n"); 294 n += sprintf(buf + n, "PRIME print:0x08\n"); 295 n += sprintf(buf + n, "ATOMIC print:0x10\n"); 296 n += sprintf(buf + n, "VBL print:0x20\n"); 297 298 return n; 299 } 300 301 static ssize_t sunxi_drm_debug_store(struct device *device, 302 struct device_attribute *attr, 303 const char *buf, size_t count) 304 { 305 if (kstrtoul(buf, 0, (unsigned long *)&drm_debug) < 0) { 306 DRM_ERROR("ERROR input\n"); 307 return 0; 308 } 309 310 return count; 311 } 312 313 static DEVICE_ATTR(debug, 0660, sunxi_drm_debug_show, sunxi_drm_debug_store); 314 315 static struct attribute *sunxi_dev_attrs[] = { 316 &dev_attr_planes_info.attr, 317 &dev_attr_crtc_info.attr, 318 &dev_attr_fb_capture.attr, 319 &dev_attr_fb_info.attr, 320 &dev_attr_encoder_info.attr, 321 &dev_attr_connector_info.attr, 322 &dev_attr_debug.attr, 323 NULL 324 }; 325 326 static const struct attribute_group sunxi_dev_group = { 327 .attrs = sunxi_dev_attrs, 328 }; 329 330 static const struct attribute_group *sunxi_drm_dev_groups[] = { 331 &sunxi_dev_group, 332 NULL 333 }; 334 335 int sunxi_drm_sysfs_init(struct drm_device *dev) 336 { 337 sunxi_drv_dev = device_create_with_groups(dev->primary->kdev->class, 338 dev->dev, 0, dev, 339 sunxi_drm_dev_groups, 340 "driver"); 341 if (IS_ERR(sunxi_drv_dev)) { 342 DRM_ERROR("failed to register connector device: %ld\n", 343 PTR_ERR(sunxi_drv_dev)); 344 return -1; 345 } 346 347 return 0; 348 } 349 350 351 void sunxi_drm_sysfs_exit(struct drm_device *dev) 352 { 353 device_unregister(sunxi_drv_dev); 354 } 355 #endif 356 357