Skip to content
This repository was archived by the owner on Jan 27, 2026. It is now read-only.

Commit c45eb7c

Browse files
committed
Support backlight device in virtio gpu
Enable virtio backlight function, it will expose sysfs node /sys/class/backlight/virtio-gpu-backlight0 for guest user. Tracked-On: OAM-117147 Signed-off-by: Xue, Bosheng <bosheng.xue@intel.com>
1 parent 4c19e9e commit c45eb7c

6 files changed

Lines changed: 280 additions & 0 deletions

File tree

drivers/gpu/drm/virtio/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ config DRM_VIRTIO_GPU
66
select DRM_KMS_HELPER
77
select DRM_GEM_SHMEM_HELPER
88
select VIRTIO_DMA_SHARED_BUFFER
9+
select BACKLIGHT_CLASS_DEVICE
910
help
1011
This is the virtual GPU driver for virtio. It can be used with
1112
QEMU based VMMs (like KVM or Xen).

drivers/gpu/drm/virtio/virtgpu_drv.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ static unsigned int features[] = {
163163
VIRTIO_GPU_F_MODIFIER,
164164
VIRTIO_GPU_F_SCALING,
165165
VIRTIO_GPU_F_VBLANK,
166+
VIRTIO_GPU_F_BACKLIGHT,
166167
};
167168

168169
#ifdef CONFIG_PM_SLEEP

drivers/gpu/drm/virtio/virtgpu_drv.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <linux/virtio_ids.h>
3232
#include <linux/virtio_config.h>
3333
#include <linux/virtio_gpu.h>
34+
#include <linux/backlight.h>
3435

3536
#include <drm/drm_atomic.h>
3637
#include <drm/drm_drv.h>
@@ -173,6 +174,7 @@ struct virtio_gpu_vbuffer {
173174
struct list_head list;
174175

175176
uint32_t seqno;
177+
struct completion notify;
176178
};
177179

178180
struct virtio_gpu_output {
@@ -224,12 +226,26 @@ struct virtio_gpu_vblank {
224226
uint32_t buf[4];
225227
};
226228

229+
#define MAX_BACKLIGHT_NUM 4
230+
struct virtio_gpu_backlight {
231+
struct virtio_gpu_device *vgdev;
232+
struct backlight_device *bd;
233+
uint32_t backlight_id;
234+
int32_t brightness;
235+
int32_t max_brightness;
236+
int32_t power;
237+
enum backlight_type type;
238+
enum backlight_scale scale;
239+
};
240+
227241
struct virtio_gpu_device {
228242
struct drm_device *ddev;
229243

230244
struct virtio_device *vdev;
231245

232246
struct virtio_gpu_output outputs[VIRTIO_GPU_MAX_SCANOUTS];
247+
struct virtio_gpu_backlight backlight[MAX_BACKLIGHT_NUM];
248+
uint32_t num_backlight;
233249
uint32_t num_scanouts;
234250
uint32_t num_vblankq;
235251
struct virtio_gpu_queue ctrlq;
@@ -255,6 +271,7 @@ struct virtio_gpu_device {
255271
bool has_modifier;
256272
bool has_scaling;
257273
bool has_vblank;
274+
bool has_backlight;
258275
bool has_indirect;
259276
bool has_resource_assign_uuid;
260277
bool has_resource_blob;
@@ -450,6 +467,15 @@ void virtio_gpu_cmd_set_scaling(struct virtio_gpu_device *vgdev,
450467
uint32_t scanout_id,
451468
struct drm_rect *rect_dst);
452469

470+
int virtio_gpu_cmd_backlight_update_status(struct virtio_gpu_device *vgdev,
471+
uint32_t backlight_id);
472+
473+
int virtio_gpu_cmd_get_brightness(struct virtio_gpu_device *vgdev,
474+
uint32_t backlight_id);
475+
476+
int virtio_gpu_cmd_backlight_query(struct virtio_gpu_device *vgdev,
477+
uint32_t backlight_id);
478+
453479
/* virtgpu_display.c */
454480
int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev);
455481
void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev);

drivers/gpu/drm/virtio/virtgpu_kms.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,65 @@ int virtio_gpu_find_vqs(struct virtio_gpu_device *vgdev)
161161
return ret;
162162
}
163163

164+
static int virtio_backlight_device_update_status(struct backlight_device *bd)
165+
{
166+
int ret = 0;
167+
struct virtio_gpu_backlight *backlight = bl_get_data(bd);
168+
backlight->power = bd->props.power;
169+
backlight->brightness = bd->props.brightness;
170+
ret = virtio_gpu_cmd_backlight_update_status(backlight->vgdev, backlight->backlight_id);
171+
return ret;
172+
}
173+
174+
static int virtio_backlight_device_get_brightness(struct backlight_device *bd)
175+
{
176+
int ret = 0;
177+
struct virtio_gpu_backlight *backlight = bl_get_data(bd);
178+
ret = virtio_gpu_cmd_get_brightness(backlight->vgdev, backlight->backlight_id);
179+
return backlight->brightness;
180+
}
181+
182+
static const struct backlight_ops virtio_backlight_device_ops = {
183+
.update_status = virtio_backlight_device_update_status,
184+
.get_brightness = virtio_backlight_device_get_brightness,
185+
};
186+
187+
int virtio_backlight_device_register(struct virtio_gpu_device *vgdev, int index)
188+
{
189+
struct backlight_properties props;
190+
char *name;
191+
struct backlight_device *bd;
192+
int ret = 0;
193+
memset(&props, 0, sizeof(props));
194+
if (index >= vgdev->num_backlight) {
195+
return -EINVAL;
196+
}
197+
vgdev->backlight[index].vgdev = vgdev;
198+
ret = virtio_gpu_cmd_backlight_query(vgdev, index);
199+
if (ret) {
200+
pr_err("fail to query backlight(%d) device config, ret:%d", index, ret);
201+
return ret;
202+
}
203+
204+
props.type = vgdev->backlight[index].type;
205+
props.power = vgdev->backlight[index].power;
206+
props.scale = vgdev->backlight[index].scale;
207+
props.brightness = vgdev->backlight[index].brightness;
208+
props.max_brightness = vgdev->backlight[index].max_brightness;
209+
name = kasprintf(GFP_KERNEL, "virtio-gpu-backlight%d", index);
210+
bd = devm_backlight_device_register(&vgdev->vdev->dev, name, &vgdev->vdev->dev,
211+
&vgdev->backlight[index], &virtio_backlight_device_ops, &props);
212+
if (IS_ERR(bd)) {
213+
DRM_ERROR("failed to register backlight device\n");
214+
kfree(name);
215+
return PTR_ERR(bd);
216+
}
217+
vgdev->backlight[index].bd = bd;
218+
DRM_INFO("backlight device:%s registered\n", name);
219+
kfree(name);
220+
return 0;
221+
}
222+
164223
int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev)
165224
{
166225
struct virtio_gpu_device *vgdev;
@@ -220,6 +279,9 @@ int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev)
220279
if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_VBLANK)) {
221280
vgdev->has_vblank = true;
222281
}
282+
if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_BACKLIGHT)) {
283+
vgdev->has_backlight = true;
284+
}
223285
if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_RESOURCE_BLOB)) {
224286
vgdev->has_resource_blob = true;
225287
if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_MODIFIER)) {
@@ -296,6 +358,18 @@ int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev)
296358
num_capsets, &num_capsets);
297359
DRM_INFO("number of cap sets: %d\n", num_capsets);
298360

361+
vgdev->num_backlight = 0;
362+
if (vgdev->has_backlight) {
363+
virtio_cread_le(vgdev->vdev, struct virtio_gpu_config,
364+
num_backlight, &vgdev->num_backlight);
365+
if (vgdev->num_backlight > MAX_BACKLIGHT_NUM)
366+
vgdev->num_backlight = MAX_BACKLIGHT_NUM;
367+
}
368+
DRM_INFO("number of virtio backlight: %d\n", vgdev->num_backlight);
369+
for(i = 0; i < vgdev->num_backlight; i++) {
370+
virtio_backlight_device_register(vgdev, i);
371+
}
372+
299373
ret = virtio_gpu_modeset_init(vgdev);
300374
if (ret) {
301375
DRM_ERROR("modeset init failed\n");

drivers/gpu/drm/virtio/virtgpu_vq.c

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,3 +1416,132 @@ void virtio_gpu_cmd_set_scaling(struct virtio_gpu_device *vgdev,
14161416

14171417
virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
14181418
}
1419+
1420+
int virtio_gpu_cmd_backlight_update_status(struct virtio_gpu_device *vgdev,
1421+
uint32_t backlight_id)
1422+
{
1423+
struct virtio_gpu_backlight_update_status *cmd_p;
1424+
struct virtio_gpu_vbuffer *vbuf;
1425+
1426+
if (backlight_id >= vgdev->num_backlight) {
1427+
return -EINVAL;
1428+
}
1429+
cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p));
1430+
memset(cmd_p, 0, sizeof(*cmd_p));
1431+
cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_BACKLIGHT_UPDATE_STATUS);
1432+
cmd_p->backlight_id = cpu_to_le32(backlight_id);
1433+
cmd_p->brightness = cpu_to_le32(vgdev->backlight[backlight_id].brightness);
1434+
cmd_p->power = cpu_to_le32(vgdev->backlight[backlight_id].power);
1435+
1436+
virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
1437+
virtio_gpu_notify(vgdev);
1438+
return 0;
1439+
}
1440+
1441+
static void virtio_gpu_cmd_get_backlightness_cb(struct virtio_gpu_device *vgdev,
1442+
struct virtio_gpu_vbuffer *vbuf)
1443+
{
1444+
struct virtio_gpu_get_brightness *cmd_p =
1445+
(struct virtio_gpu_get_brightness *)vbuf->buf;
1446+
struct virtio_gpu_resp_brightness *resp =
1447+
(struct virtio_gpu_resp_brightness *)vbuf->resp_buf;
1448+
int32_t brightness = le32_to_cpu(resp->brightness);
1449+
uint32_t backlight_id = cmd_p->backlight_id;
1450+
if (backlight_id < vgdev->num_backlight) {
1451+
vgdev->backlight[backlight_id].brightness = brightness;
1452+
}
1453+
complete(&vbuf->notify);
1454+
}
1455+
1456+
int virtio_gpu_cmd_get_brightness(struct virtio_gpu_device *vgdev,
1457+
uint32_t backlight_id)
1458+
{
1459+
struct virtio_gpu_get_brightness *cmd_p;
1460+
struct virtio_gpu_vbuffer *vbuf;
1461+
void *resp_buf;
1462+
int ret = 0;
1463+
1464+
if (backlight_id >= vgdev->num_backlight)
1465+
return -EINVAL;
1466+
resp_buf = kzalloc(sizeof(struct virtio_gpu_resp_brightness),
1467+
GFP_KERNEL);
1468+
if (!resp_buf)
1469+
return -ENOMEM;
1470+
1471+
cmd_p = virtio_gpu_alloc_cmd_resp
1472+
(vgdev, &virtio_gpu_cmd_get_backlightness_cb, &vbuf,
1473+
sizeof(*cmd_p), sizeof(struct virtio_gpu_resp_brightness),
1474+
resp_buf);
1475+
memset(cmd_p, 0, sizeof(*cmd_p));
1476+
1477+
init_completion(&vbuf->notify);
1478+
cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_BACKLIGHT_GET);
1479+
cmd_p->backlight_id = backlight_id;
1480+
virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
1481+
virtio_gpu_notify(vgdev);
1482+
ret = wait_for_completion_interruptible_timeout(&vbuf->notify, 100*HZ);
1483+
if (ret <= 0)
1484+
return -ETIME;
1485+
return 0;
1486+
}
1487+
1488+
static void virtio_gpu_cmd_get_backlight_info_cb(struct virtio_gpu_device *vgdev,
1489+
struct virtio_gpu_vbuffer *vbuf)
1490+
{
1491+
struct virtio_gpu_get_backlight_info *cmd_p =
1492+
(struct virtio_gpu_get_backlight_info *)vbuf->buf;
1493+
struct virtio_gpu_resp_backlight_info *resp =
1494+
(struct virtio_gpu_resp_backlight_info *)vbuf->resp_buf;
1495+
int32_t brightness = le32_to_cpu(resp->brightness);
1496+
int32_t max_brightness = le32_to_cpu(resp->max_brightness);
1497+
int32_t power = le32_to_cpu(resp->power);
1498+
int32_t type = le32_to_cpu(resp->type);
1499+
int32_t scale = le32_to_cpu(resp->scale);
1500+
uint32_t backlight_id = cmd_p->backlight_id;
1501+
if (backlight_id < vgdev->num_backlight) {
1502+
vgdev->backlight[backlight_id].brightness = brightness;
1503+
vgdev->backlight[backlight_id].max_brightness = max_brightness;
1504+
vgdev->backlight[backlight_id].power = power;
1505+
if (type > 0 && type < BACKLIGHT_TYPE_MAX)
1506+
vgdev->backlight[backlight_id].type = type;
1507+
else
1508+
vgdev->backlight[backlight_id].type = BACKLIGHT_RAW;
1509+
if (scale >= BACKLIGHT_SCALE_UNKNOWN && scale <= BACKLIGHT_SCALE_NON_LINEAR)
1510+
vgdev->backlight[backlight_id].scale = scale;
1511+
else
1512+
vgdev->backlight[backlight_id].scale = BACKLIGHT_SCALE_UNKNOWN;
1513+
}
1514+
complete(&vbuf->notify);
1515+
}
1516+
1517+
int virtio_gpu_cmd_backlight_query(struct virtio_gpu_device *vgdev,
1518+
uint32_t backlight_id)
1519+
{
1520+
struct virtio_gpu_get_backlight_info *cmd_p;
1521+
struct virtio_gpu_vbuffer *vbuf;
1522+
void *resp_buf;
1523+
int ret = 0;
1524+
1525+
if (backlight_id >= vgdev->num_backlight)
1526+
return -EINVAL;
1527+
resp_buf = kzalloc(sizeof(struct virtio_gpu_resp_backlight_info),
1528+
GFP_KERNEL);
1529+
if (!resp_buf)
1530+
return -ENOMEM;
1531+
1532+
cmd_p = virtio_gpu_alloc_cmd_resp
1533+
(vgdev, &virtio_gpu_cmd_get_backlight_info_cb, &vbuf,
1534+
sizeof(*cmd_p), sizeof(struct virtio_gpu_resp_backlight_info),
1535+
resp_buf);
1536+
init_completion(&vbuf->notify);
1537+
memset(cmd_p, 0, sizeof(*cmd_p));
1538+
1539+
cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_BACKLIGHT_QUERY);
1540+
cmd_p->backlight_id = backlight_id;
1541+
virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
1542+
virtio_gpu_notify(vgdev);
1543+
ret = wait_for_completion_interruptible_timeout(&vbuf->notify, 100*HZ);
1544+
if (ret <= 0)
1545+
return -ETIME;
1546+
return 0;
1547+
}

include/uapi/linux/virtio_gpu.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@
7575

7676
#define VIRTIO_GPU_F_VBLANK 7
7777

78+
#define VIRTIO_GPU_F_BACKLIGHT 8
79+
7880
enum virtio_gpu_ctrl_type {
7981
VIRTIO_GPU_UNDEFINED = 0,
8082

@@ -112,6 +114,11 @@ enum virtio_gpu_ctrl_type {
112114
VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
113115
VIRTIO_GPU_CMD_MOVE_CURSOR,
114116

117+
/* backlight cmd */
118+
VIRTIO_GPU_CMD_BACKLIGHT_UPDATE_STATUS = 0x0400,
119+
VIRTIO_GPU_CMD_BACKLIGHT_GET,
120+
VIRTIO_GPU_CMD_BACKLIGHT_QUERY,
121+
115122
/* success responses */
116123
VIRTIO_GPU_RESP_OK_NODATA = 0x1100,
117124
VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
@@ -120,6 +127,8 @@ enum virtio_gpu_ctrl_type {
120127
VIRTIO_GPU_RESP_OK_EDID,
121128
VIRTIO_GPU_RESP_OK_RESOURCE_UUID,
122129
VIRTIO_GPU_RESP_OK_MAP_INFO,
130+
VIRTIO_GPU_RESP_OK_BACKLIGHT_GET,
131+
VIRTIO_GPU_RESP_OK_BACKLIGHT,
123132

124133
/* error responses */
125134
VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
@@ -223,6 +232,45 @@ struct virtio_gpu_set_scaling {
223232
__le32 padding;
224233
};
225234

235+
/* VIRTIO_GPU_CMD_BACKLIGHT_UPDATE_STATUS */
236+
struct virtio_gpu_backlight_update_status {
237+
struct virtio_gpu_ctrl_hdr hdr;
238+
__le32 backlight_id;
239+
__le32 brightness;
240+
__le32 power;
241+
__le32 padding;
242+
};
243+
244+
/* VIRTIO_GPU_CMD_BACKLIGHT_GET */
245+
struct virtio_gpu_get_brightness {
246+
struct virtio_gpu_ctrl_hdr hdr;
247+
__le32 backlight_id;
248+
__le32 padding;
249+
};
250+
251+
struct virtio_gpu_resp_brightness {
252+
struct virtio_gpu_ctrl_hdr hdr;
253+
__le32 brightness;
254+
__le32 padding;
255+
};
256+
257+
/* VIRTIO_GPU_CMD_BACKLIGHT_QUERY */
258+
struct virtio_gpu_get_backlight_info {
259+
struct virtio_gpu_ctrl_hdr hdr;
260+
__le32 backlight_id;
261+
__le32 padding;
262+
};
263+
264+
struct virtio_gpu_resp_backlight_info {
265+
struct virtio_gpu_ctrl_hdr hdr;
266+
__le32 brightness;
267+
__le32 max_brightness;
268+
__le32 power;
269+
__le32 type;
270+
__le32 scale;
271+
__le32 padding;
272+
};
273+
226274
/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: simple transfer to_host */
227275
struct virtio_gpu_transfer_to_host_2d {
228276
struct virtio_gpu_ctrl_hdr hdr;
@@ -382,6 +430,7 @@ struct virtio_gpu_config {
382430
__le32 num_scanouts;
383431
__le32 num_capsets;
384432
__le32 num_pipe;
433+
__le32 num_backlight;
385434
};
386435

387436
/* simple formats for fbcon/X use */

0 commit comments

Comments
 (0)