virtio_console.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-11-11 GuEe-GUI the first version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <cpuport.h>
  13. #ifdef RT_USING_VIRTIO_CONSOLE
  14. #include <virtio_console.h>
  15. struct port_device
  16. {
  17. struct rt_device parent;
  18. rt_list_t node;
  19. rt_uint32_t port_id;
  20. rt_bool_t rx_notify;
  21. rt_bool_t need_destroy;
  22. struct virtio_console_device *console;
  23. struct virtq *queue_rx, *queue_tx;
  24. rt_uint32_t queue_rx_index, queue_tx_index;
  25. #ifdef RT_USING_SMP
  26. struct rt_spinlock spinlock_rx, spinlock_tx;
  27. #endif
  28. struct rt_device_notify rx_notify_helper;
  29. struct
  30. {
  31. char rx_char, tx_char;
  32. } info[VIRTIO_CONSOLE_QUEUE_SIZE];
  33. };
  34. static void virtio_console_send_ctrl(struct virtio_console_device *virtio_console_dev,
  35. struct virtio_console_control *ctrl)
  36. {
  37. rt_uint16_t id;
  38. struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
  39. struct virtq *queue_ctrl_tx;
  40. #ifdef RT_USING_SMP
  41. rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
  42. #endif
  43. queue_ctrl_tx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_TX];
  44. id = queue_ctrl_tx->avail->idx % queue_ctrl_tx->num;
  45. rt_memcpy(&virtio_console_dev->info[id].tx_ctrl, ctrl, sizeof(struct virtio_console_control));
  46. virtio_free_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id);
  47. virtio_fill_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id,
  48. virtio_console_dev->info[id].tx_ctrl_paddr, sizeof(struct virtio_console_control), 0, 0);
  49. virtio_submit_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id);
  50. virtio_queue_notify(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX);
  51. virtio_alloc_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX);
  52. #ifdef RT_USING_SMP
  53. rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
  54. #endif
  55. }
  56. static rt_err_t virtio_console_port_init(rt_device_t dev);
  57. static rt_err_t virtio_console_port_open(rt_device_t dev, rt_uint16_t oflag);
  58. static rt_err_t virtio_console_port_close(rt_device_t dev);
  59. static rt_ssize_t virtio_console_port_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
  60. static rt_ssize_t virtio_console_port_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
  61. static rt_err_t virtio_console_port_control(rt_device_t dev, int cmd, void *args);
  62. #ifdef RT_USING_DEVICE_OPS
  63. const static struct rt_device_ops virtio_console_port_ops =
  64. {
  65. virtio_console_port_init,
  66. virtio_console_port_open,
  67. virtio_console_port_close,
  68. virtio_console_port_read,
  69. virtio_console_port_write,
  70. virtio_console_port_control
  71. };
  72. #endif
  73. static rt_err_t virtio_console_port_create(struct virtio_console_device *virtio_console_dev)
  74. {
  75. rt_uint32_t port_id;
  76. char dev_name[RT_NAME_MAX];
  77. struct port_device *port_dev, *prev_port_dev = RT_NULL;
  78. struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
  79. if (virtio_console_dev->port_nr > 0 && !virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
  80. {
  81. return -RT_ENOSYS;
  82. }
  83. if (virtio_console_dev->port_nr >= virtio_console_dev->max_port_nr)
  84. {
  85. return -RT_EFULL;
  86. }
  87. port_id = 0;
  88. /* The port device list is always ordered, so just find next number for id */
  89. rt_list_for_each_entry(port_dev, &virtio_console_dev->port_head, node)
  90. {
  91. if (port_dev->port_id != port_id)
  92. {
  93. break;
  94. }
  95. ++port_id;
  96. prev_port_dev = port_dev;
  97. }
  98. port_dev = rt_malloc(sizeof(struct port_device));
  99. if (port_dev == RT_NULL)
  100. {
  101. return -RT_ENOMEM;
  102. }
  103. port_dev->parent.type = RT_Device_Class_Char;
  104. #ifdef RT_USING_DEVICE_OPS
  105. port_dev->parent.ops = &virtio_console_port_ops;
  106. #else
  107. port_dev->parent.init = virtio_console_port_init;
  108. port_dev->parent.open = virtio_console_port_open;
  109. port_dev->parent.close = virtio_console_port_close;
  110. port_dev->parent.read = virtio_console_port_read;
  111. port_dev->parent.write = virtio_console_port_write;
  112. port_dev->parent.control = virtio_console_port_control;
  113. #endif
  114. port_dev->parent.rx_indicate = RT_NULL;
  115. port_dev->parent.tx_complete = RT_NULL;
  116. rt_list_init(&port_dev->node);
  117. port_dev->port_id = port_id;
  118. port_dev->need_destroy = RT_FALSE;
  119. port_dev->rx_notify = RT_TRUE;
  120. port_dev->console = virtio_console_dev;
  121. port_dev->queue_rx_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_RX);
  122. port_dev->queue_tx_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_TX);
  123. port_dev->queue_rx = &virtio_dev->queues[port_dev->queue_rx_index];
  124. port_dev->queue_tx = &virtio_dev->queues[port_dev->queue_tx_index];
  125. #ifdef RT_USING_SMP
  126. rt_spin_lock_init(&port_dev->spinlock_rx);
  127. rt_spin_lock_init(&port_dev->spinlock_tx);
  128. #endif
  129. rt_snprintf(dev_name, RT_NAME_MAX, "vport%dp%d", virtio_console_dev->console_id, port_id);
  130. if (rt_device_register((rt_device_t)port_dev, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX) != RT_EOK)
  131. {
  132. rt_free(port_dev);
  133. return -RT_ERROR;
  134. }
  135. if (prev_port_dev != RT_NULL)
  136. {
  137. rt_list_insert_after(&prev_port_dev->node, &port_dev->node);
  138. }
  139. else
  140. {
  141. /* Port0 */
  142. rt_list_insert_after(&virtio_console_dev->port_head, &port_dev->node);
  143. }
  144. virtio_console_dev->port_nr++;
  145. return RT_EOK;
  146. }
  147. static void virtio_console_port_destroy(struct virtio_console_device *virtio_console_dev,
  148. struct port_device *port_dev)
  149. {
  150. struct virtio_console_control set_ctrl;
  151. set_ctrl.id = port_dev->port_id;
  152. set_ctrl.event = VIRTIO_CONSOLE_PORT_OPEN;
  153. set_ctrl.value = 0;
  154. virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
  155. virtio_console_dev->port_nr--;
  156. rt_list_remove(&port_dev->node);
  157. rt_device_unregister((rt_device_t)port_dev);
  158. rt_free(port_dev);
  159. }
  160. static rt_err_t virtio_console_port_init(rt_device_t dev)
  161. {
  162. rt_uint16_t id;
  163. rt_uint16_t idx[VIRTIO_CONSOLE_QUEUE_SIZE];
  164. rt_uint16_t rx_queue_index, tx_queue_index;
  165. struct port_device *port_dev = (struct port_device *)dev;
  166. struct virtio_console_device *virtio_console_dev = port_dev->console;
  167. struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
  168. struct virtq *queue_rx, *queue_tx;
  169. rx_queue_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_RX);
  170. tx_queue_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_TX);
  171. queue_rx = &virtio_dev->queues[rx_queue_index];
  172. queue_tx = &virtio_dev->queues[tx_queue_index];
  173. virtio_alloc_desc_chain(virtio_dev, rx_queue_index, queue_rx->num, idx);
  174. virtio_alloc_desc_chain(virtio_dev, tx_queue_index, queue_tx->num, idx);
  175. for (id = 0; id < queue_rx->num; ++id)
  176. {
  177. void *addr = &port_dev->info[id].rx_char;
  178. virtio_fill_desc(virtio_dev, rx_queue_index, id,
  179. VIRTIO_VA2PA(addr), sizeof(char), VIRTQ_DESC_F_WRITE, 0);
  180. queue_rx->avail->ring[id] = id;
  181. }
  182. rt_hw_dsb();
  183. queue_rx->avail->flags = 0;
  184. queue_rx->avail->idx = queue_rx->num;
  185. queue_rx->used_idx = queue_rx->used->idx;
  186. queue_tx->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
  187. queue_tx->avail->idx = 0;
  188. virtio_queue_notify(virtio_dev, rx_queue_index);
  189. if (virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
  190. {
  191. struct virtio_console_control set_ctrl;
  192. set_ctrl.id = VIRTIO_CONSOLE_PORT_BAD_ID;
  193. set_ctrl.event = VIRTIO_CONSOLE_DEVICE_READY;
  194. set_ctrl.value = 1;
  195. virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
  196. }
  197. return RT_EOK;
  198. }
  199. static rt_err_t virtio_console_port_open(rt_device_t dev, rt_uint16_t oflag)
  200. {
  201. struct port_device *port_dev = (struct port_device *)dev;
  202. if (port_dev->port_id == 0 && virtio_has_feature(&port_dev->console->virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
  203. {
  204. /* Port0 is reserve in multiport */
  205. return -RT_ERROR;
  206. }
  207. port_dev->rx_notify = RT_TRUE;
  208. return RT_EOK;
  209. }
  210. static rt_err_t virtio_console_port_close(rt_device_t dev)
  211. {
  212. struct port_device *port_dev = (struct port_device *)dev;
  213. if (port_dev->need_destroy)
  214. {
  215. virtio_console_port_destroy(port_dev->console, port_dev);
  216. /*
  217. * We released the device memory in virtio_console_port_destroy,
  218. * rt_device_close has not finished yet, make the return value
  219. * to empty so that rt_device_close will not access the device memory.
  220. */
  221. return -RT_EEMPTY;
  222. }
  223. port_dev->rx_notify = RT_FALSE;
  224. return RT_EOK;
  225. }
  226. static rt_ssize_t virtio_console_port_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  227. {
  228. rt_off_t i = 0;
  229. rt_uint16_t id;
  230. rt_uint32_t len;
  231. struct port_device *port_dev = (struct port_device *)dev;
  232. struct virtio_device *virtio_dev = &port_dev->console->virtio_dev;
  233. rt_uint32_t queue_rx_index = port_dev->queue_rx_index;
  234. struct virtq *queue_rx = port_dev->queue_rx;
  235. #ifdef RT_USING_SMP
  236. rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_rx);
  237. #endif
  238. while (i < size)
  239. {
  240. if (queue_rx->used_idx == queue_rx->used->idx)
  241. {
  242. break;
  243. }
  244. rt_hw_dsb();
  245. id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id;
  246. len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len;
  247. if (len > sizeof(char))
  248. {
  249. rt_kprintf("%s: Receive buffer's size = %u is too big!\n", port_dev->parent.parent.name, len);
  250. len = sizeof(char);
  251. }
  252. *((char *)buffer + i) = port_dev->info[id].rx_char;
  253. queue_rx->used_idx++;
  254. virtio_submit_chain(virtio_dev, queue_rx_index, id);
  255. virtio_queue_notify(virtio_dev, queue_rx_index);
  256. i += len;
  257. }
  258. #ifdef RT_USING_SMP
  259. rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level);
  260. #endif
  261. size = i;
  262. return size;
  263. }
  264. static rt_ssize_t virtio_console_port_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  265. {
  266. char ch = 0;
  267. rt_off_t i = 0;
  268. rt_uint16_t id;
  269. struct port_device *port_dev = (struct port_device *)dev;
  270. struct virtio_device *virtio_dev = &port_dev->console->virtio_dev;
  271. rt_uint32_t queue_tx_index = port_dev->queue_tx_index;
  272. struct virtq *queue_tx = port_dev->queue_tx;
  273. #ifdef RT_USING_SMP
  274. rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_tx);
  275. #endif
  276. while (i < size || ch == '\r')
  277. {
  278. id = queue_tx->avail->idx % queue_tx->num;
  279. /* Keep the way until 'new line' are unified */
  280. if (ch != '\r')
  281. {
  282. ch = *((const char *)buffer + i);
  283. }
  284. else
  285. {
  286. i -= sizeof(char);
  287. }
  288. port_dev->info[id].tx_char = ch;
  289. ch = (ch == '\n' ? '\r' : 0);
  290. virtio_free_desc(virtio_dev, queue_tx_index, id);
  291. virtio_fill_desc(virtio_dev, queue_tx_index, id,
  292. VIRTIO_VA2PA(&port_dev->info[id].tx_char), sizeof(char), 0, 0);
  293. virtio_submit_chain(virtio_dev, queue_tx_index, id);
  294. virtio_queue_notify(virtio_dev, queue_tx_index);
  295. virtio_alloc_desc(virtio_dev, queue_tx_index);
  296. i += sizeof(char);
  297. }
  298. #ifdef RT_USING_SMP
  299. rt_spin_unlock_irqrestore(&port_dev->spinlock_tx, level);
  300. #endif
  301. return size;
  302. }
  303. static rt_err_t virtio_console_port_control(rt_device_t dev, int cmd, void *args)
  304. {
  305. rt_err_t status = RT_EOK;
  306. struct port_device *port_dev = (struct port_device *)dev;
  307. switch (cmd)
  308. {
  309. case RT_DEVICE_CTRL_NOTIFY_SET:
  310. if (args == RT_NULL)
  311. {
  312. status = -RT_ERROR;
  313. break;
  314. }
  315. rt_memcpy(&port_dev->rx_notify_helper, args, sizeof(port_dev->rx_notify_helper));
  316. break;
  317. case RT_DEVICE_CTRL_CLR_INT:
  318. /* Disable RX */
  319. port_dev->rx_notify = RT_FALSE;
  320. break;
  321. case RT_DEVICE_CTRL_SET_INT:
  322. /* Enable RX */
  323. port_dev->rx_notify = RT_TRUE;
  324. break;
  325. case VIRTIO_DEVICE_CTRL_CONSOLE_PORT_DESTROY:
  326. {
  327. port_dev->need_destroy = RT_TRUE;
  328. port_dev->rx_notify = RT_FALSE;
  329. }
  330. break;
  331. default:
  332. status = -RT_EINVAL;
  333. break;
  334. }
  335. return status;
  336. }
  337. static rt_err_t virtio_console_init(rt_device_t dev)
  338. {
  339. struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)dev;
  340. struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
  341. if (virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
  342. {
  343. rt_uint16_t id;
  344. rt_uint16_t idx[VIRTIO_CONSOLE_QUEUE_SIZE];
  345. struct virtq *queue_ctrl_rx, *queue_ctrl_tx;
  346. queue_ctrl_rx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_RX];
  347. queue_ctrl_tx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_TX];
  348. virtio_alloc_desc_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX, queue_ctrl_rx->num, idx);
  349. virtio_alloc_desc_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, queue_ctrl_tx->num, idx);
  350. for (id = 0; id < queue_ctrl_rx->num; ++id)
  351. {
  352. void *addr = &virtio_console_dev->info[id].rx_ctrl;
  353. virtio_fill_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX, id,
  354. VIRTIO_VA2PA(addr), sizeof(struct virtio_console_control), VIRTQ_DESC_F_WRITE, 0);
  355. queue_ctrl_rx->avail->ring[id] = id;
  356. }
  357. rt_hw_dsb();
  358. for (id = 0; id < queue_ctrl_tx->num; ++id)
  359. {
  360. virtio_console_dev->info[id].tx_ctrl_paddr = VIRTIO_VA2PA(&virtio_console_dev->info[id].tx_ctrl);
  361. }
  362. queue_ctrl_rx->avail->flags = 0;
  363. queue_ctrl_rx->avail->idx = queue_ctrl_rx->num;
  364. queue_ctrl_rx->used_idx = queue_ctrl_rx->used->idx;
  365. queue_ctrl_tx->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
  366. queue_ctrl_tx->avail->idx = 0;
  367. virtio_queue_notify(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX);
  368. }
  369. return virtio_console_port_create(virtio_console_dev);
  370. }
  371. static rt_err_t virtio_console_control(rt_device_t dev, int cmd, void *args)
  372. {
  373. rt_err_t status = RT_EOK;
  374. struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)dev;
  375. switch (cmd)
  376. {
  377. case VIRTIO_DEVICE_CTRL_CONSOLE_PORT_CREATE:
  378. status = virtio_console_port_create(virtio_console_dev);
  379. break;
  380. default:
  381. status = -RT_EINVAL;
  382. break;
  383. }
  384. return status;
  385. }
  386. #ifdef RT_USING_DEVICE_OPS
  387. const static struct rt_device_ops virtio_console_ops =
  388. {
  389. virtio_console_init,
  390. RT_NULL,
  391. RT_NULL,
  392. RT_NULL,
  393. RT_NULL,
  394. virtio_console_control
  395. };
  396. #endif
  397. static void virtio_console_isr(int irqno, void *param)
  398. {
  399. rt_uint32_t id;
  400. rt_uint32_t len;
  401. struct port_device *port_dev;
  402. struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)param;
  403. struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
  404. const char *dev_name = virtio_console_dev->parent.parent.name;
  405. #ifdef RT_USING_SMP
  406. rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
  407. #endif
  408. virtio_interrupt_ack(virtio_dev);
  409. rt_hw_dsb();
  410. do {
  411. struct virtq *queue_rx;
  412. struct virtio_console_control *ctrl, set_ctrl;
  413. if (!virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
  414. {
  415. break;
  416. }
  417. queue_rx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_RX];
  418. if (queue_rx->used_idx == queue_rx->used->idx)
  419. {
  420. break;
  421. }
  422. rt_hw_dsb();
  423. id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id;
  424. len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len;
  425. queue_rx->used_idx++;
  426. if (len != sizeof(struct virtio_console_control))
  427. {
  428. rt_kprintf("%s: Invalid ctrl!\n", dev_name);
  429. break;
  430. }
  431. ctrl = &virtio_console_dev->info[id].rx_ctrl;
  432. switch (ctrl->event)
  433. {
  434. case VIRTIO_CONSOLE_PORT_ADD:
  435. {
  436. set_ctrl.id = ctrl->id;
  437. set_ctrl.event = VIRTIO_CONSOLE_PORT_READY;
  438. set_ctrl.value = 1;
  439. #ifdef RT_USING_SMP
  440. rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
  441. #endif
  442. virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
  443. #ifdef RT_USING_SMP
  444. level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
  445. #endif
  446. }
  447. break;
  448. case VIRTIO_CONSOLE_PORT_REMOVE:
  449. break;
  450. case VIRTIO_CONSOLE_RESIZE:
  451. break;
  452. case VIRTIO_CONSOLE_PORT_OPEN:
  453. {
  454. set_ctrl.id = ctrl->id;
  455. set_ctrl.event = VIRTIO_CONSOLE_PORT_OPEN;
  456. set_ctrl.value = 1;
  457. #ifdef RT_USING_SMP
  458. rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
  459. #endif
  460. virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
  461. #ifdef RT_USING_SMP
  462. level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
  463. #endif
  464. }
  465. break;
  466. case VIRTIO_CONSOLE_PORT_NAME:
  467. break;
  468. default:
  469. rt_kprintf("%s: Unsupport ctrl[id: %d, event: %d, value: %d]!\n",
  470. dev_name, ctrl->id, ctrl->event, ctrl->value);
  471. break;
  472. }
  473. } while (0);
  474. #ifdef RT_USING_SMP
  475. rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
  476. #endif
  477. rt_list_for_each_entry(port_dev, &virtio_console_dev->port_head, node)
  478. {
  479. rt_uint32_t queue_rx_index = port_dev->queue_rx_index;
  480. struct virtq *queue_rx = port_dev->queue_rx;
  481. #ifdef RT_USING_SMP
  482. rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_rx);
  483. #endif
  484. if (queue_rx->used_idx != queue_rx->used->idx)
  485. {
  486. rt_hw_dsb();
  487. id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id;
  488. len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len;
  489. if (port_dev->rx_notify)
  490. {
  491. #ifdef RT_USING_SMP
  492. rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level);
  493. #endif
  494. /* Will call virtio_console_port_read to inc used_idx */
  495. if (port_dev->parent.rx_indicate != RT_NULL)
  496. {
  497. port_dev->parent.rx_indicate(&port_dev->parent, len);
  498. }
  499. if (port_dev->rx_notify_helper.notify != RT_NULL)
  500. {
  501. port_dev->rx_notify_helper.notify(port_dev->rx_notify_helper.dev);
  502. }
  503. #ifdef RT_USING_SMP
  504. level = rt_spin_lock_irqsave(&port_dev->spinlock_rx);
  505. #endif
  506. }
  507. else
  508. {
  509. queue_rx->used_idx++;
  510. virtio_submit_chain(virtio_dev, queue_rx_index, id);
  511. virtio_queue_notify(virtio_dev, queue_rx_index);
  512. }
  513. }
  514. #ifdef RT_USING_SMP
  515. rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level);
  516. #endif
  517. }
  518. }
  519. rt_err_t rt_virtio_console_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
  520. {
  521. int i;
  522. rt_size_t queues_num;
  523. static int dev_no = 0;
  524. char dev_name[RT_NAME_MAX];
  525. struct virtio_device *virtio_dev;
  526. struct virtio_console_device *virtio_console_dev;
  527. RT_ASSERT(RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR > 0);
  528. virtio_console_dev = rt_malloc(sizeof(struct virtio_console_device));
  529. if (virtio_console_dev == RT_NULL)
  530. {
  531. goto _alloc_fail;
  532. }
  533. virtio_dev = &virtio_console_dev->virtio_dev;
  534. virtio_dev->irq = irq;
  535. virtio_dev->mmio_base = mmio_base;
  536. virtio_console_dev->config = (struct virtio_console_config *)virtio_dev->mmio_config->config;
  537. #ifdef RT_USING_SMP
  538. rt_spin_lock_init(&virtio_dev->spinlock);
  539. #endif
  540. virtio_reset_device(virtio_dev);
  541. virtio_status_acknowledge_driver(virtio_dev);
  542. virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
  543. (1 << VIRTIO_F_RING_EVENT_IDX) |
  544. (1 << VIRTIO_F_RING_INDIRECT_DESC));
  545. virtio_status_driver_ok(virtio_dev);
  546. if (!virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
  547. {
  548. virtio_console_dev->max_port_nr = 1;
  549. queues_num = 2;
  550. }
  551. else
  552. {
  553. if (virtio_console_dev->config->max_nr_ports > RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR)
  554. {
  555. virtio_console_dev->max_port_nr = RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR;
  556. virtio_console_dev->config->max_nr_ports = virtio_console_dev->max_port_nr;
  557. }
  558. else
  559. {
  560. virtio_console_dev->max_port_nr = virtio_console_dev->config->max_nr_ports;
  561. }
  562. queues_num = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(virtio_console_dev->max_port_nr, VIRTIO_CONSOLE_QUEUE_DATA_RX);
  563. }
  564. if (virtio_queues_alloc(virtio_dev, queues_num) != RT_EOK)
  565. {
  566. goto _alloc_fail;
  567. }
  568. for (i = 0; i < virtio_dev->queues_num; ++i)
  569. {
  570. if (virtio_queue_init(virtio_dev, i, VIRTIO_CONSOLE_QUEUE_SIZE) != RT_EOK)
  571. {
  572. for (; i >= 0; --i)
  573. {
  574. virtio_queue_destroy(virtio_dev, i);
  575. }
  576. goto _alloc_fail;
  577. }
  578. }
  579. virtio_console_dev->parent.type = RT_Device_Class_Char;
  580. #ifdef RT_USING_DEVICE_OPS
  581. virtio_console_dev->parent.ops = &virtio_console_ops;
  582. #else
  583. virtio_console_dev->parent.init = virtio_console_init;
  584. virtio_console_dev->parent.open = RT_NULL;
  585. virtio_console_dev->parent.close = RT_NULL;
  586. virtio_console_dev->parent.read = RT_NULL;
  587. virtio_console_dev->parent.write = RT_NULL;
  588. virtio_console_dev->parent.control = virtio_console_control;
  589. #endif
  590. virtio_console_dev->parent.rx_indicate = RT_NULL;
  591. virtio_console_dev->parent.tx_complete = RT_NULL;
  592. virtio_console_dev->console_id = dev_no;
  593. virtio_console_dev->port_nr = 0;
  594. rt_list_init(&virtio_console_dev->port_head);
  595. rt_snprintf(dev_name, RT_NAME_MAX, "virtio-console%d", dev_no++);
  596. rt_hw_interrupt_install(irq, virtio_console_isr, virtio_console_dev, dev_name);
  597. rt_hw_interrupt_umask(irq);
  598. return rt_device_register((rt_device_t)virtio_console_dev, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
  599. _alloc_fail:
  600. if (virtio_console_dev != RT_NULL)
  601. {
  602. virtio_queues_free(virtio_dev);
  603. rt_free(virtio_console_dev);
  604. }
  605. return -RT_ENOMEM;
  606. }
  607. #endif /* RT_USING_VIRTIO_CONSOLE */