2
0

char-parallel.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /*
  2. * QEMU System Emulator
  3. *
  4. * Copyright (c) 2003-2008 Fabrice Bellard
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "qemu/osdep.h"
  25. #include "chardev/char.h"
  26. #include "qapi/error.h"
  27. #include <sys/ioctl.h>
  28. #ifdef CONFIG_BSD
  29. #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
  30. #include <dev/ppbus/ppi.h>
  31. #include <dev/ppbus/ppbconf.h>
  32. #elif defined(__DragonFly__)
  33. #include <dev/misc/ppi/ppi.h>
  34. #include <bus/ppbus/ppbconf.h>
  35. #endif
  36. #else
  37. #ifdef __linux__
  38. #include <linux/ppdev.h>
  39. #include <linux/parport.h>
  40. #endif
  41. #endif
  42. #include "chardev/char-fd.h"
  43. #include "chardev/char-parallel.h"
  44. #if defined(__linux__)
  45. typedef struct {
  46. Chardev parent;
  47. int fd;
  48. int mode;
  49. } ParallelChardev;
  50. #define PARALLEL_CHARDEV(obj) \
  51. OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
  52. static int pp_hw_mode(ParallelChardev *s, uint16_t mode)
  53. {
  54. if (s->mode != mode) {
  55. int m = mode;
  56. if (ioctl(s->fd, PPSETMODE, &m) < 0) {
  57. return 0;
  58. }
  59. s->mode = mode;
  60. }
  61. return 1;
  62. }
  63. static int pp_ioctl(Chardev *chr, int cmd, void *arg)
  64. {
  65. ParallelChardev *drv = PARALLEL_CHARDEV(chr);
  66. int fd = drv->fd;
  67. uint8_t b;
  68. switch (cmd) {
  69. case CHR_IOCTL_PP_READ_DATA:
  70. if (ioctl(fd, PPRDATA, &b) < 0) {
  71. return -ENOTSUP;
  72. }
  73. *(uint8_t *)arg = b;
  74. break;
  75. case CHR_IOCTL_PP_WRITE_DATA:
  76. b = *(uint8_t *)arg;
  77. if (ioctl(fd, PPWDATA, &b) < 0) {
  78. return -ENOTSUP;
  79. }
  80. break;
  81. case CHR_IOCTL_PP_READ_CONTROL:
  82. if (ioctl(fd, PPRCONTROL, &b) < 0) {
  83. return -ENOTSUP;
  84. }
  85. /* Linux gives only the lowest bits, and no way to know data
  86. direction! For better compatibility set the fixed upper
  87. bits. */
  88. *(uint8_t *)arg = b | 0xc0;
  89. break;
  90. case CHR_IOCTL_PP_WRITE_CONTROL:
  91. b = *(uint8_t *)arg;
  92. if (ioctl(fd, PPWCONTROL, &b) < 0) {
  93. return -ENOTSUP;
  94. }
  95. break;
  96. case CHR_IOCTL_PP_READ_STATUS:
  97. if (ioctl(fd, PPRSTATUS, &b) < 0) {
  98. return -ENOTSUP;
  99. }
  100. *(uint8_t *)arg = b;
  101. break;
  102. case CHR_IOCTL_PP_DATA_DIR:
  103. if (ioctl(fd, PPDATADIR, (int *)arg) < 0) {
  104. return -ENOTSUP;
  105. }
  106. break;
  107. case CHR_IOCTL_PP_EPP_READ_ADDR:
  108. if (pp_hw_mode(drv, IEEE1284_MODE_EPP | IEEE1284_ADDR)) {
  109. struct ParallelIOArg *parg = arg;
  110. int n = read(fd, parg->buffer, parg->count);
  111. if (n != parg->count) {
  112. return -EIO;
  113. }
  114. }
  115. break;
  116. case CHR_IOCTL_PP_EPP_READ:
  117. if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
  118. struct ParallelIOArg *parg = arg;
  119. int n = read(fd, parg->buffer, parg->count);
  120. if (n != parg->count) {
  121. return -EIO;
  122. }
  123. }
  124. break;
  125. case CHR_IOCTL_PP_EPP_WRITE_ADDR:
  126. if (pp_hw_mode(drv, IEEE1284_MODE_EPP | IEEE1284_ADDR)) {
  127. struct ParallelIOArg *parg = arg;
  128. int n = write(fd, parg->buffer, parg->count);
  129. if (n != parg->count) {
  130. return -EIO;
  131. }
  132. }
  133. break;
  134. case CHR_IOCTL_PP_EPP_WRITE:
  135. if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
  136. struct ParallelIOArg *parg = arg;
  137. int n = write(fd, parg->buffer, parg->count);
  138. if (n != parg->count) {
  139. return -EIO;
  140. }
  141. }
  142. break;
  143. default:
  144. return -ENOTSUP;
  145. }
  146. return 0;
  147. }
  148. static void qemu_chr_open_pp_fd(Chardev *chr,
  149. int fd,
  150. bool *be_opened,
  151. Error **errp)
  152. {
  153. ParallelChardev *drv = PARALLEL_CHARDEV(chr);
  154. if (ioctl(fd, PPCLAIM) < 0) {
  155. error_setg_errno(errp, errno, "not a parallel port");
  156. close(fd);
  157. return;
  158. }
  159. drv->fd = fd;
  160. drv->mode = IEEE1284_MODE_COMPAT;
  161. }
  162. #endif /* __linux__ */
  163. #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
  164. typedef struct {
  165. Chardev parent;
  166. int fd;
  167. } ParallelChardev;
  168. #define PARALLEL_CHARDEV(obj) \
  169. OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
  170. static int pp_ioctl(Chardev *chr, int cmd, void *arg)
  171. {
  172. ParallelChardev *drv = PARALLEL_CHARDEV(chr);
  173. uint8_t b;
  174. switch (cmd) {
  175. case CHR_IOCTL_PP_READ_DATA:
  176. if (ioctl(drv->fd, PPIGDATA, &b) < 0) {
  177. return -ENOTSUP;
  178. }
  179. *(uint8_t *)arg = b;
  180. break;
  181. case CHR_IOCTL_PP_WRITE_DATA:
  182. b = *(uint8_t *)arg;
  183. if (ioctl(drv->fd, PPISDATA, &b) < 0) {
  184. return -ENOTSUP;
  185. }
  186. break;
  187. case CHR_IOCTL_PP_READ_CONTROL:
  188. if (ioctl(drv->fd, PPIGCTRL, &b) < 0) {
  189. return -ENOTSUP;
  190. }
  191. *(uint8_t *)arg = b;
  192. break;
  193. case CHR_IOCTL_PP_WRITE_CONTROL:
  194. b = *(uint8_t *)arg;
  195. if (ioctl(drv->fd, PPISCTRL, &b) < 0) {
  196. return -ENOTSUP;
  197. }
  198. break;
  199. case CHR_IOCTL_PP_READ_STATUS:
  200. if (ioctl(drv->fd, PPIGSTATUS, &b) < 0) {
  201. return -ENOTSUP;
  202. }
  203. *(uint8_t *)arg = b;
  204. break;
  205. default:
  206. return -ENOTSUP;
  207. }
  208. return 0;
  209. }
  210. static void qemu_chr_open_pp_fd(Chardev *chr,
  211. int fd,
  212. bool *be_opened,
  213. Error **errp)
  214. {
  215. ParallelChardev *drv = PARALLEL_CHARDEV(chr);
  216. drv->fd = fd;
  217. *be_opened = false;
  218. }
  219. #endif
  220. #ifdef HAVE_CHARDEV_PARPORT
  221. static void qmp_chardev_open_parallel(Chardev *chr,
  222. ChardevBackend *backend,
  223. bool *be_opened,
  224. Error **errp)
  225. {
  226. ChardevHostdev *parallel = backend->u.parallel.data;
  227. int fd;
  228. fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp);
  229. if (fd < 0) {
  230. return;
  231. }
  232. qemu_chr_open_pp_fd(chr, fd, be_opened, errp);
  233. }
  234. static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend,
  235. Error **errp)
  236. {
  237. const char *device = qemu_opt_get(opts, "path");
  238. ChardevHostdev *parallel;
  239. if (device == NULL) {
  240. error_setg(errp, "chardev: parallel: no device path given");
  241. return;
  242. }
  243. backend->type = CHARDEV_BACKEND_KIND_PARALLEL;
  244. parallel = backend->u.parallel.data = g_new0(ChardevHostdev, 1);
  245. qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(parallel));
  246. parallel->device = g_strdup(device);
  247. }
  248. static void char_parallel_class_init(ObjectClass *oc, void *data)
  249. {
  250. ChardevClass *cc = CHARDEV_CLASS(oc);
  251. cc->parse = qemu_chr_parse_parallel;
  252. cc->open = qmp_chardev_open_parallel;
  253. #if defined(__linux__)
  254. cc->chr_ioctl = pp_ioctl;
  255. #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
  256. defined(__DragonFly__)
  257. cc->chr_ioctl = pp_ioctl;
  258. #endif
  259. }
  260. static void char_parallel_finalize(Object *obj)
  261. {
  262. #if defined(__linux__)
  263. Chardev *chr = CHARDEV(obj);
  264. ParallelChardev *drv = PARALLEL_CHARDEV(chr);
  265. int fd = drv->fd;
  266. pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
  267. ioctl(fd, PPRELEASE);
  268. close(fd);
  269. qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
  270. #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
  271. defined(__DragonFly__)
  272. /* FIXME: close fd? */
  273. #endif
  274. }
  275. static const TypeInfo char_parallel_type_info = {
  276. .name = TYPE_CHARDEV_PARALLEL,
  277. .parent = TYPE_CHARDEV,
  278. .instance_size = sizeof(ParallelChardev),
  279. .instance_finalize = char_parallel_finalize,
  280. .class_init = char_parallel_class_init,
  281. };
  282. static void register_types(void)
  283. {
  284. type_register_static(&char_parallel_type_info);
  285. }
  286. type_init(register_types);
  287. #endif