interface.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. /*
  2. * interface to user space for the gigaset driver
  3. *
  4. * Copyright (c) 2004 by Hansjoerg Lipp <hjlipp@web.de>
  5. *
  6. * =====================================================================
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. * =====================================================================
  12. */
  13. #include "gigaset.h"
  14. #include <linux/gigaset_dev.h>
  15. #include <linux/tty.h>
  16. #include <linux/tty_flip.h>
  17. /*** our ioctls ***/
  18. static int if_lock(struct cardstate *cs, int *arg)
  19. {
  20. int cmd = *arg;
  21. gig_dbg(DEBUG_IF, "%u: if_lock (%d)", cs->minor_index, cmd);
  22. if (cmd > 1)
  23. return -EINVAL;
  24. if (cmd < 0) {
  25. *arg = cs->mstate == MS_LOCKED;
  26. return 0;
  27. }
  28. if (!cmd && cs->mstate == MS_LOCKED && cs->connected) {
  29. cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
  30. cs->ops->baud_rate(cs, B115200);
  31. cs->ops->set_line_ctrl(cs, CS8);
  32. cs->control_state = TIOCM_DTR|TIOCM_RTS;
  33. }
  34. cs->waiting = 1;
  35. if (!gigaset_add_event(cs, &cs->at_state, EV_IF_LOCK,
  36. NULL, cmd, NULL)) {
  37. cs->waiting = 0;
  38. return -ENOMEM;
  39. }
  40. gig_dbg(DEBUG_CMD, "scheduling IF_LOCK");
  41. gigaset_schedule_event(cs);
  42. wait_event(cs->waitqueue, !cs->waiting);
  43. if (cs->cmd_result >= 0) {
  44. *arg = cs->cmd_result;
  45. return 0;
  46. }
  47. return cs->cmd_result;
  48. }
  49. static int if_version(struct cardstate *cs, unsigned arg[4])
  50. {
  51. static const unsigned version[4] = GIG_VERSION;
  52. static const unsigned compat[4] = GIG_COMPAT;
  53. unsigned cmd = arg[0];
  54. gig_dbg(DEBUG_IF, "%u: if_version (%d)", cs->minor_index, cmd);
  55. switch (cmd) {
  56. case GIGVER_DRIVER:
  57. memcpy(arg, version, sizeof version);
  58. return 0;
  59. case GIGVER_COMPAT:
  60. memcpy(arg, compat, sizeof compat);
  61. return 0;
  62. case GIGVER_FWBASE:
  63. cs->waiting = 1;
  64. if (!gigaset_add_event(cs, &cs->at_state, EV_IF_VER,
  65. NULL, 0, arg)) {
  66. cs->waiting = 0;
  67. return -ENOMEM;
  68. }
  69. gig_dbg(DEBUG_CMD, "scheduling IF_VER");
  70. gigaset_schedule_event(cs);
  71. wait_event(cs->waitqueue, !cs->waiting);
  72. if (cs->cmd_result >= 0)
  73. return 0;
  74. return cs->cmd_result;
  75. default:
  76. return -EINVAL;
  77. }
  78. }
  79. static int if_config(struct cardstate *cs, int *arg)
  80. {
  81. gig_dbg(DEBUG_IF, "%u: if_config (%d)", cs->minor_index, *arg);
  82. if (*arg != 1)
  83. return -EINVAL;
  84. if (cs->mstate != MS_LOCKED)
  85. return -EBUSY;
  86. if (!cs->connected) {
  87. err("not connected!");
  88. return -ENODEV;
  89. }
  90. *arg = 0;
  91. return gigaset_enterconfigmode(cs);
  92. }
  93. /*** the terminal driver ***/
  94. /* stolen from usbserial and some other tty drivers */
  95. static int if_open(struct tty_struct *tty, struct file *filp);
  96. static void if_close(struct tty_struct *tty, struct file *filp);
  97. static int if_ioctl(struct tty_struct *tty, struct file *file,
  98. unsigned int cmd, unsigned long arg);
  99. static int if_write_room(struct tty_struct *tty);
  100. static int if_chars_in_buffer(struct tty_struct *tty);
  101. static void if_throttle(struct tty_struct *tty);
  102. static void if_unthrottle(struct tty_struct *tty);
  103. static void if_set_termios(struct tty_struct *tty, struct ktermios *old);
  104. static int if_tiocmget(struct tty_struct *tty, struct file *file);
  105. static int if_tiocmset(struct tty_struct *tty, struct file *file,
  106. unsigned int set, unsigned int clear);
  107. static int if_write(struct tty_struct *tty,
  108. const unsigned char *buf, int count);
  109. static const struct tty_operations if_ops = {
  110. .open = if_open,
  111. .close = if_close,
  112. .ioctl = if_ioctl,
  113. .write = if_write,
  114. .write_room = if_write_room,
  115. .chars_in_buffer = if_chars_in_buffer,
  116. .set_termios = if_set_termios,
  117. .throttle = if_throttle,
  118. .unthrottle = if_unthrottle,
  119. #if 0
  120. .break_ctl = serial_break,
  121. #endif
  122. .tiocmget = if_tiocmget,
  123. .tiocmset = if_tiocmset,
  124. };
  125. static int if_open(struct tty_struct *tty, struct file *filp)
  126. {
  127. struct cardstate *cs;
  128. unsigned long flags;
  129. gig_dbg(DEBUG_IF, "%d+%d: %s()",
  130. tty->driver->minor_start, tty->index, __func__);
  131. tty->driver_data = NULL;
  132. cs = gigaset_get_cs_by_tty(tty);
  133. if (!cs)
  134. return -ENODEV;
  135. if (mutex_lock_interruptible(&cs->mutex))
  136. return -ERESTARTSYS; // FIXME -EINTR?
  137. tty->driver_data = cs;
  138. ++cs->open_count;
  139. if (cs->open_count == 1) {
  140. spin_lock_irqsave(&cs->lock, flags);
  141. cs->tty = tty;
  142. spin_unlock_irqrestore(&cs->lock, flags);
  143. tty->low_latency = 1; //FIXME test
  144. }
  145. mutex_unlock(&cs->mutex);
  146. return 0;
  147. }
  148. static void if_close(struct tty_struct *tty, struct file *filp)
  149. {
  150. struct cardstate *cs;
  151. unsigned long flags;
  152. cs = (struct cardstate *) tty->driver_data;
  153. if (!cs) {
  154. err("cs==NULL in %s", __func__);
  155. return;
  156. }
  157. gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
  158. mutex_lock(&cs->mutex);
  159. if (!cs->open_count)
  160. warn("%s: device not opened", __func__);
  161. else {
  162. if (!--cs->open_count) {
  163. spin_lock_irqsave(&cs->lock, flags);
  164. cs->tty = NULL;
  165. spin_unlock_irqrestore(&cs->lock, flags);
  166. }
  167. }
  168. mutex_unlock(&cs->mutex);
  169. }
  170. static int if_ioctl(struct tty_struct *tty, struct file *file,
  171. unsigned int cmd, unsigned long arg)
  172. {
  173. struct cardstate *cs;
  174. int retval = -ENODEV;
  175. int int_arg;
  176. unsigned char buf[6];
  177. unsigned version[4];
  178. cs = (struct cardstate *) tty->driver_data;
  179. if (!cs) {
  180. err("cs==NULL in %s", __func__);
  181. return -ENODEV;
  182. }
  183. gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd);
  184. if (mutex_lock_interruptible(&cs->mutex))
  185. return -ERESTARTSYS; // FIXME -EINTR?
  186. if (!cs->open_count)
  187. warn("%s: device not opened", __func__);
  188. else {
  189. retval = 0;
  190. switch (cmd) {
  191. case GIGASET_REDIR:
  192. retval = get_user(int_arg, (int __user *) arg);
  193. if (retval >= 0)
  194. retval = if_lock(cs, &int_arg);
  195. if (retval >= 0)
  196. retval = put_user(int_arg, (int __user *) arg);
  197. break;
  198. case GIGASET_CONFIG:
  199. retval = get_user(int_arg, (int __user *) arg);
  200. if (retval >= 0)
  201. retval = if_config(cs, &int_arg);
  202. if (retval >= 0)
  203. retval = put_user(int_arg, (int __user *) arg);
  204. break;
  205. case GIGASET_BRKCHARS:
  206. //FIXME test if MS_LOCKED
  207. if (!cs->connected) {
  208. gig_dbg(DEBUG_ANY,
  209. "can't communicate with unplugged device");
  210. retval = -ENODEV;
  211. break;
  212. }
  213. retval = copy_from_user(&buf,
  214. (const unsigned char __user *) arg, 6)
  215. ? -EFAULT : 0;
  216. if (retval >= 0) {
  217. gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS",
  218. 6, (const unsigned char *) arg);
  219. retval = cs->ops->brkchars(cs, buf);
  220. }
  221. break;
  222. case GIGASET_VERSION:
  223. retval = copy_from_user(version,
  224. (unsigned __user *) arg, sizeof version)
  225. ? -EFAULT : 0;
  226. if (retval >= 0)
  227. retval = if_version(cs, version);
  228. if (retval >= 0)
  229. retval = copy_to_user((unsigned __user *) arg,
  230. version, sizeof version)
  231. ? -EFAULT : 0;
  232. break;
  233. default:
  234. gig_dbg(DEBUG_ANY, "%s: arg not supported - 0x%04x",
  235. __func__, cmd);
  236. retval = -ENOIOCTLCMD;
  237. }
  238. }
  239. mutex_unlock(&cs->mutex);
  240. return retval;
  241. }
  242. static int if_tiocmget(struct tty_struct *tty, struct file *file)
  243. {
  244. struct cardstate *cs;
  245. int retval;
  246. cs = (struct cardstate *) tty->driver_data;
  247. if (!cs) {
  248. err("cs==NULL in %s", __func__);
  249. return -ENODEV;
  250. }
  251. gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
  252. if (mutex_lock_interruptible(&cs->mutex))
  253. return -ERESTARTSYS; // FIXME -EINTR?
  254. // FIXME read from device?
  255. retval = cs->control_state & (TIOCM_RTS|TIOCM_DTR);
  256. mutex_unlock(&cs->mutex);
  257. return retval;
  258. }
  259. static int if_tiocmset(struct tty_struct *tty, struct file *file,
  260. unsigned int set, unsigned int clear)
  261. {
  262. struct cardstate *cs;
  263. int retval;
  264. unsigned mc;
  265. cs = (struct cardstate *) tty->driver_data;
  266. if (!cs) {
  267. err("cs==NULL in %s", __func__);
  268. return -ENODEV;
  269. }
  270. gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)",
  271. cs->minor_index, __func__, set, clear);
  272. if (mutex_lock_interruptible(&cs->mutex))
  273. return -ERESTARTSYS; // FIXME -EINTR?
  274. if (!cs->connected) {
  275. gig_dbg(DEBUG_ANY, "can't communicate with unplugged device");
  276. retval = -ENODEV;
  277. } else {
  278. mc = (cs->control_state | set) & ~clear & (TIOCM_RTS|TIOCM_DTR);
  279. retval = cs->ops->set_modem_ctrl(cs, cs->control_state, mc);
  280. cs->control_state = mc;
  281. }
  282. mutex_unlock(&cs->mutex);
  283. return retval;
  284. }
  285. static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
  286. {
  287. struct cardstate *cs;
  288. int retval = -ENODEV;
  289. cs = (struct cardstate *) tty->driver_data;
  290. if (!cs) {
  291. err("cs==NULL in %s", __func__);
  292. return -ENODEV;
  293. }
  294. gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
  295. if (mutex_lock_interruptible(&cs->mutex))
  296. return -ERESTARTSYS; // FIXME -EINTR?
  297. if (!cs->open_count)
  298. warn("%s: device not opened", __func__);
  299. else if (cs->mstate != MS_LOCKED) {
  300. warn("can't write to unlocked device");
  301. retval = -EBUSY;
  302. } else if (!cs->connected) {
  303. gig_dbg(DEBUG_ANY, "can't write to unplugged device");
  304. retval = -EBUSY; //FIXME
  305. } else {
  306. retval = cs->ops->write_cmd(cs, buf, count,
  307. &cs->if_wake_tasklet);
  308. }
  309. mutex_unlock(&cs->mutex);
  310. return retval;
  311. }
  312. static int if_write_room(struct tty_struct *tty)
  313. {
  314. struct cardstate *cs;
  315. int retval = -ENODEV;
  316. cs = (struct cardstate *) tty->driver_data;
  317. if (!cs) {
  318. err("cs==NULL in %s", __func__);
  319. return -ENODEV;
  320. }
  321. gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
  322. if (mutex_lock_interruptible(&cs->mutex))
  323. return -ERESTARTSYS; // FIXME -EINTR?
  324. if (!cs->open_count)
  325. warn("%s: device not opened", __func__);
  326. else if (cs->mstate != MS_LOCKED) {
  327. warn("can't write to unlocked device");
  328. retval = -EBUSY;
  329. } else if (!cs->connected) {
  330. gig_dbg(DEBUG_ANY, "can't write to unplugged device");
  331. retval = -EBUSY; //FIXME
  332. } else
  333. retval = cs->ops->write_room(cs);
  334. mutex_unlock(&cs->mutex);
  335. return retval;
  336. }
  337. static int if_chars_in_buffer(struct tty_struct *tty)
  338. {
  339. struct cardstate *cs;
  340. int retval = -ENODEV;
  341. cs = (struct cardstate *) tty->driver_data;
  342. if (!cs) {
  343. err("cs==NULL in %s", __func__);
  344. return -ENODEV;
  345. }
  346. gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
  347. if (mutex_lock_interruptible(&cs->mutex))
  348. return -ERESTARTSYS; // FIXME -EINTR?
  349. if (!cs->open_count)
  350. warn("%s: device not opened", __func__);
  351. else if (cs->mstate != MS_LOCKED) {
  352. warn("can't write to unlocked device");
  353. retval = -EBUSY;
  354. } else if (!cs->connected) {
  355. gig_dbg(DEBUG_ANY, "can't write to unplugged device");
  356. retval = -EBUSY; //FIXME
  357. } else
  358. retval = cs->ops->chars_in_buffer(cs);
  359. mutex_unlock(&cs->mutex);
  360. return retval;
  361. }
  362. static void if_throttle(struct tty_struct *tty)
  363. {
  364. struct cardstate *cs;
  365. cs = (struct cardstate *) tty->driver_data;
  366. if (!cs) {
  367. err("cs==NULL in %s", __func__);
  368. return;
  369. }
  370. gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
  371. mutex_lock(&cs->mutex);
  372. if (!cs->open_count)
  373. warn("%s: device not opened", __func__);
  374. else {
  375. //FIXME
  376. }
  377. mutex_unlock(&cs->mutex);
  378. }
  379. static void if_unthrottle(struct tty_struct *tty)
  380. {
  381. struct cardstate *cs;
  382. cs = (struct cardstate *) tty->driver_data;
  383. if (!cs) {
  384. err("cs==NULL in %s", __func__);
  385. return;
  386. }
  387. gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
  388. mutex_lock(&cs->mutex);
  389. if (!cs->open_count)
  390. warn("%s: device not opened", __func__);
  391. else {
  392. //FIXME
  393. }
  394. mutex_unlock(&cs->mutex);
  395. }
  396. static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
  397. {
  398. struct cardstate *cs;
  399. unsigned int iflag;
  400. unsigned int cflag;
  401. unsigned int old_cflag;
  402. unsigned int control_state, new_state;
  403. cs = (struct cardstate *) tty->driver_data;
  404. if (!cs) {
  405. err("cs==NULL in %s", __func__);
  406. return;
  407. }
  408. gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
  409. mutex_lock(&cs->mutex);
  410. if (!cs->open_count) {
  411. warn("%s: device not opened", __func__);
  412. goto out;
  413. }
  414. if (!cs->connected) {
  415. gig_dbg(DEBUG_ANY, "can't communicate with unplugged device");
  416. goto out;
  417. }
  418. // stolen from mct_u232.c
  419. iflag = tty->termios->c_iflag;
  420. cflag = tty->termios->c_cflag;
  421. old_cflag = old ? old->c_cflag : cflag; //FIXME?
  422. gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x",
  423. cs->minor_index, iflag, cflag, old_cflag);
  424. /* get a local copy of the current port settings */
  425. control_state = cs->control_state;
  426. /*
  427. * Update baud rate.
  428. * Do not attempt to cache old rates and skip settings,
  429. * disconnects screw such tricks up completely.
  430. * Premature optimization is the root of all evil.
  431. */
  432. /* reassert DTR and (maybe) RTS on transition from B0 */
  433. if ((old_cflag & CBAUD) == B0) {
  434. new_state = control_state | TIOCM_DTR;
  435. /* don't set RTS if using hardware flow control */
  436. if (!(old_cflag & CRTSCTS))
  437. new_state |= TIOCM_RTS;
  438. gig_dbg(DEBUG_IF, "%u: from B0 - set DTR%s",
  439. cs->minor_index,
  440. (new_state & TIOCM_RTS) ? " only" : "/RTS");
  441. cs->ops->set_modem_ctrl(cs, control_state, new_state);
  442. control_state = new_state;
  443. }
  444. cs->ops->baud_rate(cs, cflag & CBAUD);
  445. if ((cflag & CBAUD) == B0) {
  446. /* Drop RTS and DTR */
  447. gig_dbg(DEBUG_IF, "%u: to B0 - drop DTR/RTS", cs->minor_index);
  448. new_state = control_state & ~(TIOCM_DTR | TIOCM_RTS);
  449. cs->ops->set_modem_ctrl(cs, control_state, new_state);
  450. control_state = new_state;
  451. }
  452. /*
  453. * Update line control register (LCR)
  454. */
  455. cs->ops->set_line_ctrl(cs, cflag);
  456. #if 0
  457. //FIXME this hangs M101 [ts 2005-03-09]
  458. //FIXME do we need this?
  459. /*
  460. * Set flow control: well, I do not really now how to handle DTR/RTS.
  461. * Just do what we have seen with SniffUSB on Win98.
  462. */
  463. /* Drop DTR/RTS if no flow control otherwise assert */
  464. gig_dbg(DEBUG_IF, "%u: control_state %x",
  465. cs->minor_index, control_state);
  466. new_state = control_state;
  467. if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
  468. new_state |= TIOCM_DTR | TIOCM_RTS;
  469. else
  470. new_state &= ~(TIOCM_DTR | TIOCM_RTS);
  471. if (new_state != control_state) {
  472. gig_dbg(DEBUG_IF, "%u: new_state %x",
  473. cs->minor_index, new_state);
  474. gigaset_set_modem_ctrl(cs, control_state, new_state);
  475. control_state = new_state;
  476. }
  477. #endif
  478. /* save off the modified port settings */
  479. cs->control_state = control_state;
  480. out:
  481. mutex_unlock(&cs->mutex);
  482. }
  483. /* wakeup tasklet for the write operation */
  484. static void if_wake(unsigned long data)
  485. {
  486. struct cardstate *cs = (struct cardstate *) data;
  487. if (cs->tty)
  488. tty_wakeup(cs->tty);
  489. }
  490. /*** interface to common ***/
  491. void gigaset_if_init(struct cardstate *cs)
  492. {
  493. struct gigaset_driver *drv;
  494. drv = cs->driver;
  495. if (!drv->have_tty)
  496. return;
  497. tasklet_init(&cs->if_wake_tasklet, &if_wake, (unsigned long) cs);
  498. mutex_lock(&cs->mutex);
  499. cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL);
  500. if (!IS_ERR(cs->tty_dev))
  501. dev_set_drvdata(cs->tty_dev, cs);
  502. else {
  503. warn("could not register device to the tty subsystem");
  504. cs->tty_dev = NULL;
  505. }
  506. mutex_unlock(&cs->mutex);
  507. }
  508. void gigaset_if_free(struct cardstate *cs)
  509. {
  510. struct gigaset_driver *drv;
  511. drv = cs->driver;
  512. if (!drv->have_tty)
  513. return;
  514. tasklet_disable(&cs->if_wake_tasklet);
  515. tasklet_kill(&cs->if_wake_tasklet);
  516. cs->tty_dev = NULL;
  517. tty_unregister_device(drv->tty, cs->minor_index);
  518. }
  519. void gigaset_if_receive(struct cardstate *cs,
  520. unsigned char *buffer, size_t len)
  521. {
  522. unsigned long flags;
  523. struct tty_struct *tty;
  524. spin_lock_irqsave(&cs->lock, flags);
  525. if ((tty = cs->tty) == NULL)
  526. gig_dbg(DEBUG_ANY, "receive on closed device");
  527. else {
  528. tty_buffer_request_room(tty, len);
  529. tty_insert_flip_string(tty, buffer, len);
  530. tty_flip_buffer_push(tty);
  531. }
  532. spin_unlock_irqrestore(&cs->lock, flags);
  533. }
  534. EXPORT_SYMBOL_GPL(gigaset_if_receive);
  535. /* gigaset_if_initdriver
  536. * Initialize tty interface.
  537. * parameters:
  538. * drv Driver
  539. * procname Name of the driver (e.g. for /proc/tty/drivers)
  540. * devname Name of the device files (prefix without minor number)
  541. */
  542. void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
  543. const char *devname)
  544. {
  545. unsigned minors = drv->minors;
  546. int ret;
  547. struct tty_driver *tty;
  548. drv->have_tty = 0;
  549. if ((drv->tty = alloc_tty_driver(minors)) == NULL)
  550. goto enomem;
  551. tty = drv->tty;
  552. tty->magic = TTY_DRIVER_MAGIC,
  553. tty->major = GIG_MAJOR,
  554. tty->type = TTY_DRIVER_TYPE_SERIAL,
  555. tty->subtype = SERIAL_TYPE_NORMAL,
  556. tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
  557. tty->driver_name = procname;
  558. tty->name = devname;
  559. tty->minor_start = drv->minor;
  560. tty->num = drv->minors;
  561. tty->owner = THIS_MODULE;
  562. tty->init_termios = tty_std_termios; //FIXME
  563. tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; //FIXME
  564. tty_set_operations(tty, &if_ops);
  565. ret = tty_register_driver(tty);
  566. if (ret < 0) {
  567. warn("failed to register tty driver (error %d)", ret);
  568. goto error;
  569. }
  570. gig_dbg(DEBUG_IF, "tty driver initialized");
  571. drv->have_tty = 1;
  572. return;
  573. enomem:
  574. warn("could not allocate tty structures");
  575. error:
  576. if (drv->tty)
  577. put_tty_driver(drv->tty);
  578. }
  579. void gigaset_if_freedriver(struct gigaset_driver *drv)
  580. {
  581. if (!drv->have_tty)
  582. return;
  583. drv->have_tty = 0;
  584. tty_unregister_driver(drv->tty);
  585. put_tty_driver(drv->tty);
  586. }