0001
0002
0003
0004
0005
0006 #include <linux/iosys-map.h>
0007 #include <linux/list.h>
0008 #include <linux/module.h>
0009 #include <linux/mutex.h>
0010 #include <linux/seq_file.h>
0011 #include <linux/slab.h>
0012
0013 #include <drm/drm_client.h>
0014 #include <drm/drm_debugfs.h>
0015 #include <drm/drm_device.h>
0016 #include <drm/drm_drv.h>
0017 #include <drm/drm_file.h>
0018 #include <drm/drm_fourcc.h>
0019 #include <drm/drm_framebuffer.h>
0020 #include <drm/drm_gem.h>
0021 #include <drm/drm_mode.h>
0022 #include <drm/drm_print.h>
0023
0024 #include "drm_crtc_internal.h"
0025 #include "drm_internal.h"
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 static int drm_client_open(struct drm_client_dev *client)
0036 {
0037 struct drm_device *dev = client->dev;
0038 struct drm_file *file;
0039
0040 file = drm_file_alloc(dev->primary);
0041 if (IS_ERR(file))
0042 return PTR_ERR(file);
0043
0044 mutex_lock(&dev->filelist_mutex);
0045 list_add(&file->lhead, &dev->filelist_internal);
0046 mutex_unlock(&dev->filelist_mutex);
0047
0048 client->file = file;
0049
0050 return 0;
0051 }
0052
0053 static void drm_client_close(struct drm_client_dev *client)
0054 {
0055 struct drm_device *dev = client->dev;
0056
0057 mutex_lock(&dev->filelist_mutex);
0058 list_del(&client->file->lhead);
0059 mutex_unlock(&dev->filelist_mutex);
0060
0061 drm_file_free(client->file);
0062 }
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079 int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
0080 const char *name, const struct drm_client_funcs *funcs)
0081 {
0082 int ret;
0083
0084 if (!drm_core_check_feature(dev, DRIVER_MODESET) || !dev->driver->dumb_create)
0085 return -EOPNOTSUPP;
0086
0087 if (funcs && !try_module_get(funcs->owner))
0088 return -ENODEV;
0089
0090 client->dev = dev;
0091 client->name = name;
0092 client->funcs = funcs;
0093
0094 ret = drm_client_modeset_create(client);
0095 if (ret)
0096 goto err_put_module;
0097
0098 ret = drm_client_open(client);
0099 if (ret)
0100 goto err_free;
0101
0102 drm_dev_get(dev);
0103
0104 return 0;
0105
0106 err_free:
0107 drm_client_modeset_free(client);
0108 err_put_module:
0109 if (funcs)
0110 module_put(funcs->owner);
0111
0112 return ret;
0113 }
0114 EXPORT_SYMBOL(drm_client_init);
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126 void drm_client_register(struct drm_client_dev *client)
0127 {
0128 struct drm_device *dev = client->dev;
0129
0130 mutex_lock(&dev->clientlist_mutex);
0131 list_add(&client->list, &dev->clientlist);
0132 mutex_unlock(&dev->clientlist_mutex);
0133 }
0134 EXPORT_SYMBOL(drm_client_register);
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150 void drm_client_release(struct drm_client_dev *client)
0151 {
0152 struct drm_device *dev = client->dev;
0153
0154 drm_dbg_kms(dev, "%s\n", client->name);
0155
0156 drm_client_modeset_free(client);
0157 drm_client_close(client);
0158 drm_dev_put(dev);
0159 if (client->funcs)
0160 module_put(client->funcs->owner);
0161 }
0162 EXPORT_SYMBOL(drm_client_release);
0163
0164 void drm_client_dev_unregister(struct drm_device *dev)
0165 {
0166 struct drm_client_dev *client, *tmp;
0167
0168 if (!drm_core_check_feature(dev, DRIVER_MODESET))
0169 return;
0170
0171 mutex_lock(&dev->clientlist_mutex);
0172 list_for_each_entry_safe(client, tmp, &dev->clientlist, list) {
0173 list_del(&client->list);
0174 if (client->funcs && client->funcs->unregister) {
0175 client->funcs->unregister(client);
0176 } else {
0177 drm_client_release(client);
0178 kfree(client);
0179 }
0180 }
0181 mutex_unlock(&dev->clientlist_mutex);
0182 }
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193 void drm_client_dev_hotplug(struct drm_device *dev)
0194 {
0195 struct drm_client_dev *client;
0196 int ret;
0197
0198 if (!drm_core_check_feature(dev, DRIVER_MODESET))
0199 return;
0200
0201 mutex_lock(&dev->clientlist_mutex);
0202 list_for_each_entry(client, &dev->clientlist, list) {
0203 if (!client->funcs || !client->funcs->hotplug)
0204 continue;
0205
0206 ret = client->funcs->hotplug(client);
0207 drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
0208 }
0209 mutex_unlock(&dev->clientlist_mutex);
0210 }
0211 EXPORT_SYMBOL(drm_client_dev_hotplug);
0212
0213 void drm_client_dev_restore(struct drm_device *dev)
0214 {
0215 struct drm_client_dev *client;
0216 int ret;
0217
0218 if (!drm_core_check_feature(dev, DRIVER_MODESET))
0219 return;
0220
0221 mutex_lock(&dev->clientlist_mutex);
0222 list_for_each_entry(client, &dev->clientlist, list) {
0223 if (!client->funcs || !client->funcs->restore)
0224 continue;
0225
0226 ret = client->funcs->restore(client);
0227 drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
0228 if (!ret)
0229 break;
0230 }
0231 mutex_unlock(&dev->clientlist_mutex);
0232 }
0233
0234 static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
0235 {
0236 struct drm_device *dev = buffer->client->dev;
0237
0238 drm_gem_vunmap(buffer->gem, &buffer->map);
0239
0240 if (buffer->gem)
0241 drm_gem_object_put(buffer->gem);
0242
0243 if (buffer->handle)
0244 drm_mode_destroy_dumb(dev, buffer->handle, buffer->client->file);
0245
0246 kfree(buffer);
0247 }
0248
0249 static struct drm_client_buffer *
0250 drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
0251 {
0252 const struct drm_format_info *info = drm_format_info(format);
0253 struct drm_mode_create_dumb dumb_args = { };
0254 struct drm_device *dev = client->dev;
0255 struct drm_client_buffer *buffer;
0256 struct drm_gem_object *obj;
0257 int ret;
0258
0259 buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
0260 if (!buffer)
0261 return ERR_PTR(-ENOMEM);
0262
0263 buffer->client = client;
0264
0265 dumb_args.width = width;
0266 dumb_args.height = height;
0267 dumb_args.bpp = info->cpp[0] * 8;
0268 ret = drm_mode_create_dumb(dev, &dumb_args, client->file);
0269 if (ret)
0270 goto err_delete;
0271
0272 buffer->handle = dumb_args.handle;
0273 buffer->pitch = dumb_args.pitch;
0274
0275 obj = drm_gem_object_lookup(client->file, dumb_args.handle);
0276 if (!obj) {
0277 ret = -ENOENT;
0278 goto err_delete;
0279 }
0280
0281 buffer->gem = obj;
0282
0283 return buffer;
0284
0285 err_delete:
0286 drm_client_buffer_delete(buffer);
0287
0288 return ERR_PTR(ret);
0289 }
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311 int
0312 drm_client_buffer_vmap(struct drm_client_buffer *buffer,
0313 struct iosys_map *map_copy)
0314 {
0315 struct iosys_map *map = &buffer->map;
0316 int ret;
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326 ret = drm_gem_vmap(buffer->gem, map);
0327 if (ret)
0328 return ret;
0329
0330 *map_copy = *map;
0331
0332 return 0;
0333 }
0334 EXPORT_SYMBOL(drm_client_buffer_vmap);
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344 void drm_client_buffer_vunmap(struct drm_client_buffer *buffer)
0345 {
0346 struct iosys_map *map = &buffer->map;
0347
0348 drm_gem_vunmap(buffer->gem, map);
0349 }
0350 EXPORT_SYMBOL(drm_client_buffer_vunmap);
0351
0352 static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer)
0353 {
0354 int ret;
0355
0356 if (!buffer->fb)
0357 return;
0358
0359 ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file);
0360 if (ret)
0361 drm_err(buffer->client->dev,
0362 "Error removing FB:%u (%d)\n", buffer->fb->base.id, ret);
0363
0364 buffer->fb = NULL;
0365 }
0366
0367 static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
0368 u32 width, u32 height, u32 format)
0369 {
0370 struct drm_client_dev *client = buffer->client;
0371 struct drm_mode_fb_cmd fb_req = { };
0372 const struct drm_format_info *info;
0373 int ret;
0374
0375 info = drm_format_info(format);
0376 fb_req.bpp = info->cpp[0] * 8;
0377 fb_req.depth = info->depth;
0378 fb_req.width = width;
0379 fb_req.height = height;
0380 fb_req.handle = buffer->handle;
0381 fb_req.pitch = buffer->pitch;
0382
0383 ret = drm_mode_addfb(client->dev, &fb_req, client->file);
0384 if (ret)
0385 return ret;
0386
0387 buffer->fb = drm_framebuffer_lookup(client->dev, buffer->client->file, fb_req.fb_id);
0388 if (WARN_ON(!buffer->fb))
0389 return -ENOENT;
0390
0391
0392 drm_framebuffer_put(buffer->fb);
0393
0394 strscpy(buffer->fb->comm, client->name, TASK_COMM_LEN);
0395
0396 return 0;
0397 }
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413 struct drm_client_buffer *
0414 drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
0415 {
0416 struct drm_client_buffer *buffer;
0417 int ret;
0418
0419 buffer = drm_client_buffer_create(client, width, height, format);
0420 if (IS_ERR(buffer))
0421 return buffer;
0422
0423 ret = drm_client_buffer_addfb(buffer, width, height, format);
0424 if (ret) {
0425 drm_client_buffer_delete(buffer);
0426 return ERR_PTR(ret);
0427 }
0428
0429 return buffer;
0430 }
0431 EXPORT_SYMBOL(drm_client_framebuffer_create);
0432
0433
0434
0435
0436
0437 void drm_client_framebuffer_delete(struct drm_client_buffer *buffer)
0438 {
0439 if (!buffer)
0440 return;
0441
0442 drm_client_buffer_rmfb(buffer);
0443 drm_client_buffer_delete(buffer);
0444 }
0445 EXPORT_SYMBOL(drm_client_framebuffer_delete);
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458 int drm_client_framebuffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect)
0459 {
0460 if (!buffer || !buffer->fb || !buffer->fb->funcs->dirty)
0461 return 0;
0462
0463 if (rect) {
0464 struct drm_clip_rect clip = {
0465 .x1 = rect->x1,
0466 .y1 = rect->y1,
0467 .x2 = rect->x2,
0468 .y2 = rect->y2,
0469 };
0470
0471 return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file,
0472 0, 0, &clip, 1);
0473 }
0474
0475 return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file,
0476 0, 0, NULL, 0);
0477 }
0478 EXPORT_SYMBOL(drm_client_framebuffer_flush);
0479
0480 #ifdef CONFIG_DEBUG_FS
0481 static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data)
0482 {
0483 struct drm_info_node *node = m->private;
0484 struct drm_device *dev = node->minor->dev;
0485 struct drm_printer p = drm_seq_file_printer(m);
0486 struct drm_client_dev *client;
0487
0488 mutex_lock(&dev->clientlist_mutex);
0489 list_for_each_entry(client, &dev->clientlist, list)
0490 drm_printf(&p, "%s\n", client->name);
0491 mutex_unlock(&dev->clientlist_mutex);
0492
0493 return 0;
0494 }
0495
0496 static const struct drm_info_list drm_client_debugfs_list[] = {
0497 { "internal_clients", drm_client_debugfs_internal_clients, 0 },
0498 };
0499
0500 void drm_client_debugfs_init(struct drm_minor *minor)
0501 {
0502 drm_debugfs_create_files(drm_client_debugfs_list,
0503 ARRAY_SIZE(drm_client_debugfs_list),
0504 minor->debugfs_root, minor);
0505 }
0506 #endif