gud_connector.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. // SPDX-License-Identifier: MIT
  2. /*
  3. * Copyright 2020 Noralf Trønnes
  4. */
  5. #include <linux/backlight.h>
  6. #include <linux/workqueue.h>
  7. #include <drm/drm_atomic.h>
  8. #include <drm/drm_atomic_state_helper.h>
  9. #include <drm/drm_connector.h>
  10. #include <drm/drm_drv.h>
  11. #include <drm/drm_edid.h>
  12. #include <drm/drm_encoder.h>
  13. #include <drm/drm_file.h>
  14. #include <drm/drm_modeset_helper_vtables.h>
  15. #include <drm/drm_print.h>
  16. #include <drm/drm_probe_helper.h>
  17. #include <drm/drm_simple_kms_helper.h>
  18. #include <drm/gud.h>
  19. #include "gud_internal.h"
  20. struct gud_connector {
  21. struct drm_connector connector;
  22. struct drm_encoder encoder;
  23. struct backlight_device *backlight;
  24. struct work_struct backlight_work;
  25. /* Supported properties */
  26. u16 *properties;
  27. unsigned int num_properties;
  28. /* Initial gadget tv state if applicable, applied on state reset */
  29. struct drm_tv_connector_state initial_tv_state;
  30. /*
  31. * Initial gadget backlight brightness if applicable, applied on state reset.
  32. * The value -ENODEV is used to signal no backlight.
  33. */
  34. int initial_brightness;
  35. };
  36. static inline struct gud_connector *to_gud_connector(struct drm_connector *connector)
  37. {
  38. return container_of(connector, struct gud_connector, connector);
  39. }
  40. static void gud_conn_err(struct drm_connector *connector, const char *msg, int ret)
  41. {
  42. dev_err(connector->dev->dev, "%s: %s (ret=%d)\n", connector->name, msg, ret);
  43. }
  44. /*
  45. * Use a worker to avoid taking kms locks inside the backlight lock.
  46. * Other display drivers use backlight within their kms locks.
  47. * This avoids inconsistent locking rules, which would upset lockdep.
  48. */
  49. static void gud_connector_backlight_update_status_work(struct work_struct *work)
  50. {
  51. struct gud_connector *gconn = container_of(work, struct gud_connector, backlight_work);
  52. struct drm_connector *connector = &gconn->connector;
  53. struct drm_connector_state *connector_state;
  54. struct drm_device *drm = connector->dev;
  55. struct drm_modeset_acquire_ctx ctx;
  56. struct drm_atomic_state *state;
  57. int idx, ret;
  58. if (!drm_dev_enter(drm, &idx))
  59. return;
  60. state = drm_atomic_state_alloc(drm);
  61. if (!state) {
  62. ret = -ENOMEM;
  63. goto exit;
  64. }
  65. drm_modeset_acquire_init(&ctx, 0);
  66. state->acquire_ctx = &ctx;
  67. retry:
  68. connector_state = drm_atomic_get_connector_state(state, connector);
  69. if (IS_ERR(connector_state)) {
  70. ret = PTR_ERR(connector_state);
  71. goto out;
  72. }
  73. /* Reuse tv.brightness to avoid having to subclass */
  74. connector_state->tv.brightness = gconn->backlight->props.brightness;
  75. ret = drm_atomic_commit(state);
  76. out:
  77. if (ret == -EDEADLK) {
  78. drm_atomic_state_clear(state);
  79. drm_modeset_backoff(&ctx);
  80. goto retry;
  81. }
  82. drm_atomic_state_put(state);
  83. drm_modeset_drop_locks(&ctx);
  84. drm_modeset_acquire_fini(&ctx);
  85. exit:
  86. drm_dev_exit(idx);
  87. if (ret)
  88. dev_err(drm->dev, "Failed to update backlight, err=%d\n", ret);
  89. }
  90. static int gud_connector_backlight_update_status(struct backlight_device *bd)
  91. {
  92. struct drm_connector *connector = bl_get_data(bd);
  93. struct gud_connector *gconn = to_gud_connector(connector);
  94. /* The USB timeout is 5 seconds so use system_long_wq for worst case scenario */
  95. queue_work(system_long_wq, &gconn->backlight_work);
  96. return 0;
  97. }
  98. static const struct backlight_ops gud_connector_backlight_ops = {
  99. .update_status = gud_connector_backlight_update_status,
  100. };
  101. static int gud_connector_backlight_register(struct gud_connector *gconn)
  102. {
  103. struct drm_connector *connector = &gconn->connector;
  104. struct backlight_device *bd;
  105. const char *name;
  106. const struct backlight_properties props = {
  107. .type = BACKLIGHT_RAW,
  108. .scale = BACKLIGHT_SCALE_NON_LINEAR,
  109. .max_brightness = 100,
  110. .brightness = gconn->initial_brightness,
  111. };
  112. name = kasprintf(GFP_KERNEL, "card%d-%s-backlight",
  113. connector->dev->primary->index, connector->name);
  114. if (!name)
  115. return -ENOMEM;
  116. bd = backlight_device_register(name, connector->kdev, connector,
  117. &gud_connector_backlight_ops, &props);
  118. kfree(name);
  119. if (IS_ERR(bd))
  120. return PTR_ERR(bd);
  121. gconn->backlight = bd;
  122. return 0;
  123. }
  124. static int gud_connector_detect(struct drm_connector *connector,
  125. struct drm_modeset_acquire_ctx *ctx, bool force)
  126. {
  127. struct gud_device *gdrm = to_gud_device(connector->dev);
  128. int idx, ret;
  129. u8 status;
  130. if (!drm_dev_enter(connector->dev, &idx))
  131. return connector_status_disconnected;
  132. if (force) {
  133. ret = gud_usb_set(gdrm, GUD_REQ_SET_CONNECTOR_FORCE_DETECT,
  134. connector->index, NULL, 0);
  135. if (ret) {
  136. ret = connector_status_unknown;
  137. goto exit;
  138. }
  139. }
  140. ret = gud_usb_get_u8(gdrm, GUD_REQ_GET_CONNECTOR_STATUS, connector->index, &status);
  141. if (ret) {
  142. ret = connector_status_unknown;
  143. goto exit;
  144. }
  145. switch (status & GUD_CONNECTOR_STATUS_CONNECTED_MASK) {
  146. case GUD_CONNECTOR_STATUS_DISCONNECTED:
  147. ret = connector_status_disconnected;
  148. break;
  149. case GUD_CONNECTOR_STATUS_CONNECTED:
  150. ret = connector_status_connected;
  151. break;
  152. default:
  153. ret = connector_status_unknown;
  154. break;
  155. }
  156. if (status & GUD_CONNECTOR_STATUS_CHANGED)
  157. connector->epoch_counter += 1;
  158. exit:
  159. drm_dev_exit(idx);
  160. return ret;
  161. }
  162. struct gud_connector_get_edid_ctx {
  163. void *buf;
  164. size_t len;
  165. bool edid_override;
  166. };
  167. static int gud_connector_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
  168. {
  169. struct gud_connector_get_edid_ctx *ctx = data;
  170. size_t start = block * EDID_LENGTH;
  171. ctx->edid_override = false;
  172. if (start + len > ctx->len)
  173. return -1;
  174. memcpy(buf, ctx->buf + start, len);
  175. return 0;
  176. }
  177. static int gud_connector_get_modes(struct drm_connector *connector)
  178. {
  179. struct gud_device *gdrm = to_gud_device(connector->dev);
  180. struct gud_display_mode_req *reqmodes = NULL;
  181. struct gud_connector_get_edid_ctx edid_ctx;
  182. unsigned int i, num_modes = 0;
  183. const struct drm_edid *drm_edid = NULL;
  184. int idx, ret;
  185. if (!drm_dev_enter(connector->dev, &idx))
  186. return 0;
  187. edid_ctx.edid_override = true;
  188. edid_ctx.buf = kmalloc(GUD_CONNECTOR_MAX_EDID_LEN, GFP_KERNEL);
  189. if (!edid_ctx.buf)
  190. goto out;
  191. ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_EDID, connector->index,
  192. edid_ctx.buf, GUD_CONNECTOR_MAX_EDID_LEN);
  193. if (ret > 0 && ret % EDID_LENGTH) {
  194. gud_conn_err(connector, "Invalid EDID size", ret);
  195. } else if (ret > 0) {
  196. edid_ctx.len = ret;
  197. drm_edid = drm_edid_read_custom(connector, gud_connector_get_edid_block, &edid_ctx);
  198. }
  199. kfree(edid_ctx.buf);
  200. drm_edid_connector_update(connector, drm_edid);
  201. if (drm_edid && edid_ctx.edid_override)
  202. goto out;
  203. reqmodes = kmalloc_array(GUD_CONNECTOR_MAX_NUM_MODES, sizeof(*reqmodes), GFP_KERNEL);
  204. if (!reqmodes)
  205. goto out;
  206. ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_MODES, connector->index,
  207. reqmodes, GUD_CONNECTOR_MAX_NUM_MODES * sizeof(*reqmodes));
  208. if (ret <= 0)
  209. goto out;
  210. if (ret % sizeof(*reqmodes)) {
  211. gud_conn_err(connector, "Invalid display mode array size", ret);
  212. goto out;
  213. }
  214. num_modes = ret / sizeof(*reqmodes);
  215. for (i = 0; i < num_modes; i++) {
  216. struct drm_display_mode *mode;
  217. mode = drm_mode_create(connector->dev);
  218. if (!mode) {
  219. num_modes = i;
  220. goto out;
  221. }
  222. gud_to_display_mode(mode, &reqmodes[i]);
  223. drm_mode_probed_add(connector, mode);
  224. }
  225. out:
  226. if (!num_modes)
  227. num_modes = drm_edid_connector_add_modes(connector);
  228. kfree(reqmodes);
  229. drm_edid_free(drm_edid);
  230. drm_dev_exit(idx);
  231. return num_modes;
  232. }
  233. static int gud_connector_atomic_check(struct drm_connector *connector,
  234. struct drm_atomic_state *state)
  235. {
  236. struct drm_connector_state *new_state;
  237. struct drm_crtc_state *new_crtc_state;
  238. struct drm_connector_state *old_state;
  239. new_state = drm_atomic_get_new_connector_state(state, connector);
  240. if (!new_state->crtc)
  241. return 0;
  242. old_state = drm_atomic_get_old_connector_state(state, connector);
  243. new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
  244. if (old_state->tv.margins.left != new_state->tv.margins.left ||
  245. old_state->tv.margins.right != new_state->tv.margins.right ||
  246. old_state->tv.margins.top != new_state->tv.margins.top ||
  247. old_state->tv.margins.bottom != new_state->tv.margins.bottom ||
  248. old_state->tv.legacy_mode != new_state->tv.legacy_mode ||
  249. old_state->tv.brightness != new_state->tv.brightness ||
  250. old_state->tv.contrast != new_state->tv.contrast ||
  251. old_state->tv.flicker_reduction != new_state->tv.flicker_reduction ||
  252. old_state->tv.overscan != new_state->tv.overscan ||
  253. old_state->tv.saturation != new_state->tv.saturation ||
  254. old_state->tv.hue != new_state->tv.hue)
  255. new_crtc_state->connectors_changed = true;
  256. return 0;
  257. }
  258. static const struct drm_connector_helper_funcs gud_connector_helper_funcs = {
  259. .detect_ctx = gud_connector_detect,
  260. .get_modes = gud_connector_get_modes,
  261. .atomic_check = gud_connector_atomic_check,
  262. };
  263. static int gud_connector_late_register(struct drm_connector *connector)
  264. {
  265. struct gud_connector *gconn = to_gud_connector(connector);
  266. if (gconn->initial_brightness < 0)
  267. return 0;
  268. return gud_connector_backlight_register(gconn);
  269. }
  270. static void gud_connector_early_unregister(struct drm_connector *connector)
  271. {
  272. struct gud_connector *gconn = to_gud_connector(connector);
  273. backlight_device_unregister(gconn->backlight);
  274. cancel_work_sync(&gconn->backlight_work);
  275. }
  276. static void gud_connector_destroy(struct drm_connector *connector)
  277. {
  278. struct gud_connector *gconn = to_gud_connector(connector);
  279. drm_connector_cleanup(connector);
  280. kfree(gconn->properties);
  281. kfree(gconn);
  282. }
  283. static void gud_connector_reset(struct drm_connector *connector)
  284. {
  285. struct gud_connector *gconn = to_gud_connector(connector);
  286. drm_atomic_helper_connector_reset(connector);
  287. connector->state->tv = gconn->initial_tv_state;
  288. /* Set margins from command line */
  289. drm_atomic_helper_connector_tv_margins_reset(connector);
  290. if (gconn->initial_brightness >= 0)
  291. connector->state->tv.brightness = gconn->initial_brightness;
  292. }
  293. static const struct drm_connector_funcs gud_connector_funcs = {
  294. .fill_modes = drm_helper_probe_single_connector_modes,
  295. .late_register = gud_connector_late_register,
  296. .early_unregister = gud_connector_early_unregister,
  297. .destroy = gud_connector_destroy,
  298. .reset = gud_connector_reset,
  299. .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
  300. .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
  301. };
  302. /*
  303. * The tv.mode property is shared among the connectors and its enum names are
  304. * driver specific. This means that if more than one connector uses tv.mode,
  305. * the enum names has to be the same.
  306. */
  307. static int gud_connector_add_tv_mode(struct gud_device *gdrm, struct drm_connector *connector)
  308. {
  309. size_t buf_len = GUD_CONNECTOR_TV_MODE_MAX_NUM * GUD_CONNECTOR_TV_MODE_NAME_LEN;
  310. const char *modes[GUD_CONNECTOR_TV_MODE_MAX_NUM];
  311. unsigned int i, num_modes;
  312. char *buf;
  313. int ret;
  314. buf = kmalloc(buf_len, GFP_KERNEL);
  315. if (!buf)
  316. return -ENOMEM;
  317. ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_TV_MODE_VALUES,
  318. connector->index, buf, buf_len);
  319. if (ret < 0)
  320. goto free;
  321. if (!ret || ret % GUD_CONNECTOR_TV_MODE_NAME_LEN) {
  322. ret = -EIO;
  323. goto free;
  324. }
  325. num_modes = ret / GUD_CONNECTOR_TV_MODE_NAME_LEN;
  326. for (i = 0; i < num_modes; i++)
  327. modes[i] = &buf[i * GUD_CONNECTOR_TV_MODE_NAME_LEN];
  328. ret = drm_mode_create_tv_properties_legacy(connector->dev, num_modes, modes);
  329. free:
  330. kfree(buf);
  331. if (ret < 0)
  332. gud_conn_err(connector, "Failed to add TV modes", ret);
  333. return ret;
  334. }
  335. static struct drm_property *
  336. gud_connector_property_lookup(struct drm_connector *connector, u16 prop)
  337. {
  338. struct drm_mode_config *config = &connector->dev->mode_config;
  339. switch (prop) {
  340. case GUD_PROPERTY_TV_LEFT_MARGIN:
  341. return config->tv_left_margin_property;
  342. case GUD_PROPERTY_TV_RIGHT_MARGIN:
  343. return config->tv_right_margin_property;
  344. case GUD_PROPERTY_TV_TOP_MARGIN:
  345. return config->tv_top_margin_property;
  346. case GUD_PROPERTY_TV_BOTTOM_MARGIN:
  347. return config->tv_bottom_margin_property;
  348. case GUD_PROPERTY_TV_MODE:
  349. return config->legacy_tv_mode_property;
  350. case GUD_PROPERTY_TV_BRIGHTNESS:
  351. return config->tv_brightness_property;
  352. case GUD_PROPERTY_TV_CONTRAST:
  353. return config->tv_contrast_property;
  354. case GUD_PROPERTY_TV_FLICKER_REDUCTION:
  355. return config->tv_flicker_reduction_property;
  356. case GUD_PROPERTY_TV_OVERSCAN:
  357. return config->tv_overscan_property;
  358. case GUD_PROPERTY_TV_SATURATION:
  359. return config->tv_saturation_property;
  360. case GUD_PROPERTY_TV_HUE:
  361. return config->tv_hue_property;
  362. default:
  363. return ERR_PTR(-EINVAL);
  364. }
  365. }
  366. static unsigned int *gud_connector_tv_state_val(u16 prop, struct drm_tv_connector_state *state)
  367. {
  368. switch (prop) {
  369. case GUD_PROPERTY_TV_LEFT_MARGIN:
  370. return &state->margins.left;
  371. case GUD_PROPERTY_TV_RIGHT_MARGIN:
  372. return &state->margins.right;
  373. case GUD_PROPERTY_TV_TOP_MARGIN:
  374. return &state->margins.top;
  375. case GUD_PROPERTY_TV_BOTTOM_MARGIN:
  376. return &state->margins.bottom;
  377. case GUD_PROPERTY_TV_MODE:
  378. return &state->legacy_mode;
  379. case GUD_PROPERTY_TV_BRIGHTNESS:
  380. return &state->brightness;
  381. case GUD_PROPERTY_TV_CONTRAST:
  382. return &state->contrast;
  383. case GUD_PROPERTY_TV_FLICKER_REDUCTION:
  384. return &state->flicker_reduction;
  385. case GUD_PROPERTY_TV_OVERSCAN:
  386. return &state->overscan;
  387. case GUD_PROPERTY_TV_SATURATION:
  388. return &state->saturation;
  389. case GUD_PROPERTY_TV_HUE:
  390. return &state->hue;
  391. default:
  392. return ERR_PTR(-EINVAL);
  393. }
  394. }
  395. static int gud_connector_add_properties(struct gud_device *gdrm, struct gud_connector *gconn)
  396. {
  397. struct drm_connector *connector = &gconn->connector;
  398. struct drm_device *drm = &gdrm->drm;
  399. struct gud_property_req *properties;
  400. unsigned int i, num_properties;
  401. int ret;
  402. properties = kcalloc(GUD_CONNECTOR_PROPERTIES_MAX_NUM, sizeof(*properties), GFP_KERNEL);
  403. if (!properties)
  404. return -ENOMEM;
  405. ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_PROPERTIES, connector->index,
  406. properties, GUD_CONNECTOR_PROPERTIES_MAX_NUM * sizeof(*properties));
  407. if (ret <= 0)
  408. goto out;
  409. if (ret % sizeof(*properties)) {
  410. ret = -EIO;
  411. goto out;
  412. }
  413. num_properties = ret / sizeof(*properties);
  414. ret = 0;
  415. gconn->properties = kcalloc(num_properties, sizeof(*gconn->properties), GFP_KERNEL);
  416. if (!gconn->properties) {
  417. ret = -ENOMEM;
  418. goto out;
  419. }
  420. for (i = 0; i < num_properties; i++) {
  421. u16 prop = le16_to_cpu(properties[i].prop);
  422. u64 val = le64_to_cpu(properties[i].val);
  423. struct drm_property *property;
  424. unsigned int *state_val;
  425. drm_dbg(drm, "property: %u = %llu(0x%llx)\n", prop, val, val);
  426. switch (prop) {
  427. case GUD_PROPERTY_TV_LEFT_MARGIN:
  428. fallthrough;
  429. case GUD_PROPERTY_TV_RIGHT_MARGIN:
  430. fallthrough;
  431. case GUD_PROPERTY_TV_TOP_MARGIN:
  432. fallthrough;
  433. case GUD_PROPERTY_TV_BOTTOM_MARGIN:
  434. ret = drm_mode_create_tv_margin_properties(drm);
  435. if (ret)
  436. goto out;
  437. break;
  438. case GUD_PROPERTY_TV_MODE:
  439. ret = gud_connector_add_tv_mode(gdrm, connector);
  440. if (ret)
  441. goto out;
  442. break;
  443. case GUD_PROPERTY_TV_BRIGHTNESS:
  444. fallthrough;
  445. case GUD_PROPERTY_TV_CONTRAST:
  446. fallthrough;
  447. case GUD_PROPERTY_TV_FLICKER_REDUCTION:
  448. fallthrough;
  449. case GUD_PROPERTY_TV_OVERSCAN:
  450. fallthrough;
  451. case GUD_PROPERTY_TV_SATURATION:
  452. fallthrough;
  453. case GUD_PROPERTY_TV_HUE:
  454. /* This is a no-op if already added. */
  455. ret = drm_mode_create_tv_properties_legacy(drm, 0, NULL);
  456. if (ret)
  457. goto out;
  458. break;
  459. case GUD_PROPERTY_BACKLIGHT_BRIGHTNESS:
  460. if (val > 100) {
  461. ret = -EINVAL;
  462. goto out;
  463. }
  464. gconn->initial_brightness = val;
  465. break;
  466. default:
  467. /* New ones might show up in future devices, skip those we don't know. */
  468. drm_dbg(drm, "Ignoring unknown property: %u\n", prop);
  469. continue;
  470. }
  471. gconn->properties[gconn->num_properties++] = prop;
  472. if (prop == GUD_PROPERTY_BACKLIGHT_BRIGHTNESS)
  473. continue; /* not a DRM property */
  474. property = gud_connector_property_lookup(connector, prop);
  475. if (WARN_ON(IS_ERR(property)))
  476. continue;
  477. state_val = gud_connector_tv_state_val(prop, &gconn->initial_tv_state);
  478. if (WARN_ON(IS_ERR(state_val)))
  479. continue;
  480. *state_val = val;
  481. drm_object_attach_property(&connector->base, property, 0);
  482. }
  483. out:
  484. kfree(properties);
  485. return ret;
  486. }
  487. int gud_connector_fill_properties(struct drm_connector_state *connector_state,
  488. struct gud_property_req *properties)
  489. {
  490. struct gud_connector *gconn = to_gud_connector(connector_state->connector);
  491. unsigned int i;
  492. for (i = 0; i < gconn->num_properties; i++) {
  493. u16 prop = gconn->properties[i];
  494. u64 val;
  495. if (prop == GUD_PROPERTY_BACKLIGHT_BRIGHTNESS) {
  496. val = connector_state->tv.brightness;
  497. } else {
  498. unsigned int *state_val;
  499. state_val = gud_connector_tv_state_val(prop, &connector_state->tv);
  500. if (WARN_ON_ONCE(IS_ERR(state_val)))
  501. return PTR_ERR(state_val);
  502. val = *state_val;
  503. }
  504. properties[i].prop = cpu_to_le16(prop);
  505. properties[i].val = cpu_to_le64(val);
  506. }
  507. return gconn->num_properties;
  508. }
  509. static int gud_connector_create(struct gud_device *gdrm, unsigned int index,
  510. struct gud_connector_descriptor_req *desc)
  511. {
  512. struct drm_device *drm = &gdrm->drm;
  513. struct gud_connector *gconn;
  514. struct drm_connector *connector;
  515. struct drm_encoder *encoder;
  516. int ret, connector_type;
  517. u32 flags;
  518. gconn = kzalloc(sizeof(*gconn), GFP_KERNEL);
  519. if (!gconn)
  520. return -ENOMEM;
  521. INIT_WORK(&gconn->backlight_work, gud_connector_backlight_update_status_work);
  522. gconn->initial_brightness = -ENODEV;
  523. flags = le32_to_cpu(desc->flags);
  524. connector = &gconn->connector;
  525. drm_dbg(drm, "Connector: index=%u type=%u flags=0x%x\n", index, desc->connector_type, flags);
  526. switch (desc->connector_type) {
  527. case GUD_CONNECTOR_TYPE_PANEL:
  528. connector_type = DRM_MODE_CONNECTOR_USB;
  529. break;
  530. case GUD_CONNECTOR_TYPE_VGA:
  531. connector_type = DRM_MODE_CONNECTOR_VGA;
  532. break;
  533. case GUD_CONNECTOR_TYPE_DVI:
  534. connector_type = DRM_MODE_CONNECTOR_DVID;
  535. break;
  536. case GUD_CONNECTOR_TYPE_COMPOSITE:
  537. connector_type = DRM_MODE_CONNECTOR_Composite;
  538. break;
  539. case GUD_CONNECTOR_TYPE_SVIDEO:
  540. connector_type = DRM_MODE_CONNECTOR_SVIDEO;
  541. break;
  542. case GUD_CONNECTOR_TYPE_COMPONENT:
  543. connector_type = DRM_MODE_CONNECTOR_Component;
  544. break;
  545. case GUD_CONNECTOR_TYPE_DISPLAYPORT:
  546. connector_type = DRM_MODE_CONNECTOR_DisplayPort;
  547. break;
  548. case GUD_CONNECTOR_TYPE_HDMI:
  549. connector_type = DRM_MODE_CONNECTOR_HDMIA;
  550. break;
  551. default: /* future types */
  552. connector_type = DRM_MODE_CONNECTOR_USB;
  553. break;
  554. }
  555. drm_connector_helper_add(connector, &gud_connector_helper_funcs);
  556. ret = drm_connector_init(drm, connector, &gud_connector_funcs, connector_type);
  557. if (ret) {
  558. kfree(connector);
  559. return ret;
  560. }
  561. if (WARN_ON(connector->index != index))
  562. return -EINVAL;
  563. if (flags & GUD_CONNECTOR_FLAGS_POLL_STATUS)
  564. connector->polled = (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT);
  565. if (flags & GUD_CONNECTOR_FLAGS_INTERLACE)
  566. connector->interlace_allowed = true;
  567. if (flags & GUD_CONNECTOR_FLAGS_DOUBLESCAN)
  568. connector->doublescan_allowed = true;
  569. ret = gud_connector_add_properties(gdrm, gconn);
  570. if (ret) {
  571. gud_conn_err(connector, "Failed to add properties", ret);
  572. return ret;
  573. }
  574. /* The first connector is attached to the existing simple pipe encoder */
  575. if (!connector->index) {
  576. encoder = &gdrm->pipe.encoder;
  577. } else {
  578. encoder = &gconn->encoder;
  579. ret = drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_NONE);
  580. if (ret)
  581. return ret;
  582. encoder->possible_crtcs = 1;
  583. }
  584. return drm_connector_attach_encoder(connector, encoder);
  585. }
  586. int gud_get_connectors(struct gud_device *gdrm)
  587. {
  588. struct gud_connector_descriptor_req *descs;
  589. unsigned int i, num_connectors;
  590. int ret;
  591. descs = kmalloc_array(GUD_CONNECTORS_MAX_NUM, sizeof(*descs), GFP_KERNEL);
  592. if (!descs)
  593. return -ENOMEM;
  594. ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTORS, 0,
  595. descs, GUD_CONNECTORS_MAX_NUM * sizeof(*descs));
  596. if (ret < 0)
  597. goto free;
  598. if (!ret || ret % sizeof(*descs)) {
  599. ret = -EIO;
  600. goto free;
  601. }
  602. num_connectors = ret / sizeof(*descs);
  603. for (i = 0; i < num_connectors; i++) {
  604. ret = gud_connector_create(gdrm, i, &descs[i]);
  605. if (ret)
  606. goto free;
  607. }
  608. free:
  609. kfree(descs);
  610. return ret;
  611. }