1 /* 2 * IPWireless 3G PCMCIA Network Driver 3 * 4 * Original code 5 * by Stephen Blackheath <stephen@blacksapphire.com>, 6 * Ben Martel <benm@symmetric.co.nz> 7 * 8 * Copyrighted as follows: 9 * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) 10 * 11 * Various driver changes and rewrites, port to new kernels 12 * Copyright (C) 2006-2007 Jiri Kosina 13 * 14 * Misc code cleanups and updates 15 * Copyright (C) 2007 David Sterba 16 */ 17 18 #include <linux/init.h> 19 #include <linux/kernel.h> 20 #include <linux/module.h> 21 #include <linux/mutex.h> 22 #include <linux/ppp_defs.h> 23 #include <linux/if.h> 24 #include <linux/if_ppp.h> 25 #include <linux/sched.h> 26 #include <linux/serial.h> 27 #include <linux/slab.h> 28 #include <linux/tty.h> 29 #include <linux/tty_driver.h> 30 #include <linux/tty_flip.h> 31 #include <linux/uaccess.h> 32 33 #include "tty.h" 34 #include "network.h" 35 #include "hardware.h" 36 #include "main.h" 37 38 #define IPWIRELESS_PCMCIA_START (0) 39 #define IPWIRELESS_PCMCIA_MINORS (24) 40 #define IPWIRELESS_PCMCIA_MINOR_RANGE (8) 41 42 #define TTYTYPE_MODEM (0) 43 #define TTYTYPE_MONITOR (1) 44 #define TTYTYPE_RAS_RAW (2) 45 46 struct ipw_tty { 47 int index; 48 struct ipw_hardware *hardware; 49 unsigned int channel_idx; 50 unsigned int secondary_channel_idx; 51 int tty_type; 52 struct ipw_network *network; 53 struct tty_struct *linux_tty; 54 int open_count; 55 unsigned int control_lines; 56 struct mutex ipw_tty_mutex; 57 int tx_bytes_queued; 58 int closing; 59 }; 60 61 static struct ipw_tty *ttys[IPWIRELESS_PCMCIA_MINORS]; 62 63 static struct tty_driver *ipw_tty_driver; 64 65 static char *tty_type_name(int tty_type) 66 { 67 static char *channel_names[] = { 68 "modem", 69 "monitor", 70 "RAS-raw" 71 }; 72 73 return channel_names[tty_type]; 74 } 75 76 static void report_registering(struct ipw_tty *tty) 77 { 78 char *iftype = tty_type_name(tty->tty_type); 79 80 printk(KERN_INFO IPWIRELESS_PCCARD_NAME 81 ": registering %s device ttyIPWp%d\n", iftype, tty->index); 82 } 83 84 static void report_deregistering(struct ipw_tty *tty) 85 { 86 char *iftype = tty_type_name(tty->tty_type); 87 88 printk(KERN_INFO IPWIRELESS_PCCARD_NAME 89 ": deregistering %s device ttyIPWp%d\n", iftype, 90 tty->index); 91 } 92 93 static struct ipw_tty *get_tty(int minor) 94 { 95 if (minor < ipw_tty_driver->minor_start 96 || minor >= ipw_tty_driver->minor_start + 97 IPWIRELESS_PCMCIA_MINORS) 98 return NULL; 99 else { 100 int minor_offset = minor - ipw_tty_driver->minor_start; 101 102 /* 103 * The 'ras_raw' channel is only available when 'loopback' mode 104 * is enabled. 105 * Number of minor starts with 16 (_RANGE * _RAS_RAW). 106 */ 107 if (!ipwireless_loopback && 108 minor_offset >= 109 IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW) 110 return NULL; 111 112 return ttys[minor_offset]; 113 } 114 } 115 116 static int ipw_open(struct tty_struct *linux_tty, struct file *filp) 117 { 118 int minor = linux_tty->index; 119 struct ipw_tty *tty = get_tty(minor); 120 121 if (!tty) 122 return -ENODEV; 123 124 mutex_lock(&tty->ipw_tty_mutex); 125 126 if (tty->closing) { 127 mutex_unlock(&tty->ipw_tty_mutex); 128 return -ENODEV; 129 } 130 if (tty->open_count == 0) 131 tty->tx_bytes_queued = 0; 132 133 tty->open_count++; 134 135 tty->linux_tty = linux_tty; 136 linux_tty->driver_data = tty; 137 linux_tty->low_latency = 1; 138 139 if (tty->tty_type == TTYTYPE_MODEM) 140 ipwireless_ppp_open(tty->network); 141 142 mutex_unlock(&tty->ipw_tty_mutex); 143 144 return 0; 145 } 146 147 static void do_ipw_close(struct ipw_tty *tty) 148 { 149 tty->open_count--; 150 151 if (tty->open_count == 0) { 152 struct tty_struct *linux_tty = tty->linux_tty; 153 154 if (linux_tty != NULL) { 155 tty->linux_tty = NULL; 156 linux_tty->driver_data = NULL; 157 158 if (tty->tty_type == TTYTYPE_MODEM) 159 ipwireless_ppp_close(tty->network); 160 } 161 } 162 } 163 164 static void ipw_hangup(struct tty_struct *linux_tty) 165 { 166 struct ipw_tty *tty = linux_tty->driver_data; 167 168 if (!tty) 169 return; 170 171 mutex_lock(&tty->ipw_tty_mutex); 172 if (tty->open_count == 0) { 173 mutex_unlock(&tty->ipw_tty_mutex); 174 return; 175 } 176 177 do_ipw_close(tty); 178 179 mutex_unlock(&tty->ipw_tty_mutex); 180 } 181 182 static void ipw_close(struct tty_struct *linux_tty, struct file *filp) 183 { 184 ipw_hangup(linux_tty); 185 } 186 187 /* Take data received from hardware, and send it out the tty */ 188 void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, 189 unsigned int length) 190 { 191 struct tty_struct *linux_tty; 192 int work = 0; 193 194 mutex_lock(&tty->ipw_tty_mutex); 195 linux_tty = tty->linux_tty; 196 if (linux_tty == NULL) { 197 mutex_unlock(&tty->ipw_tty_mutex); 198 return; 199 } 200 201 if (!tty->open_count) { 202 mutex_unlock(&tty->ipw_tty_mutex); 203 return; 204 } 205 mutex_unlock(&tty->ipw_tty_mutex); 206 207 work = tty_insert_flip_string(linux_tty, data, length); 208 209 if (work != length) 210 printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME 211 ": %d chars not inserted to flip buffer!\n", 212 length - work); 213 214 /* 215 * This may sleep if ->low_latency is set 216 */ 217 if (work) 218 tty_flip_buffer_push(linux_tty); 219 } 220 221 static void ipw_write_packet_sent_callback(void *callback_data, 222 unsigned int packet_length) 223 { 224 struct ipw_tty *tty = callback_data; 225 226 /* 227 * Packet has been sent, so we subtract the number of bytes from our 228 * tally of outstanding TX bytes. 229 */ 230 tty->tx_bytes_queued -= packet_length; 231 } 232 233 static int ipw_write(struct tty_struct *linux_tty, 234 const unsigned char *buf, int count) 235 { 236 struct ipw_tty *tty = linux_tty->driver_data; 237 int room, ret; 238 239 if (!tty) 240 return -ENODEV; 241 242 mutex_lock(&tty->ipw_tty_mutex); 243 if (!tty->open_count) { 244 mutex_unlock(&tty->ipw_tty_mutex); 245 return -EINVAL; 246 } 247 248 room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; 249 if (room < 0) 250 room = 0; 251 /* Don't allow caller to write any more than we have room for */ 252 if (count > room) 253 count = room; 254 255 if (count == 0) { 256 mutex_unlock(&tty->ipw_tty_mutex); 257 return 0; 258 } 259 260 ret = ipwireless_send_packet(tty->hardware, IPW_CHANNEL_RAS, 261 buf, count, 262 ipw_write_packet_sent_callback, tty); 263 if (ret == -1) { 264 mutex_unlock(&tty->ipw_tty_mutex); 265 return 0; 266 } 267 268 tty->tx_bytes_queued += count; 269 mutex_unlock(&tty->ipw_tty_mutex); 270 271 return count; 272 } 273 274 static int ipw_write_room(struct tty_struct *linux_tty) 275 { 276 struct ipw_tty *tty = linux_tty->driver_data; 277 int room; 278 279 /* FIXME: Exactly how is the tty object locked here .. */ 280 if (!tty) 281 return -ENODEV; 282 283 if (!tty->open_count) 284 return -EINVAL; 285 286 room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; 287 if (room < 0) 288 room = 0; 289 290 return room; 291 } 292 293 static int ipwireless_get_serial_info(struct ipw_tty *tty, 294 struct serial_struct __user *retinfo) 295 { 296 struct serial_struct tmp; 297 298 if (!retinfo) 299 return (-EFAULT); 300 301 memset(&tmp, 0, sizeof(tmp)); 302 tmp.type = PORT_UNKNOWN; 303 tmp.line = tty->index; 304 tmp.port = 0; 305 tmp.irq = 0; 306 tmp.flags = 0; 307 tmp.baud_base = 115200; 308 tmp.close_delay = 0; 309 tmp.closing_wait = 0; 310 tmp.custom_divisor = 0; 311 tmp.hub6 = 0; 312 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) 313 return -EFAULT; 314 315 return 0; 316 } 317 318 static int ipw_chars_in_buffer(struct tty_struct *linux_tty) 319 { 320 struct ipw_tty *tty = linux_tty->driver_data; 321 322 if (!tty) 323 return 0; 324 325 if (!tty->open_count) 326 return 0; 327 328 return tty->tx_bytes_queued; 329 } 330 331 static int get_control_lines(struct ipw_tty *tty) 332 { 333 unsigned int my = tty->control_lines; 334 unsigned int out = 0; 335 336 if (my & IPW_CONTROL_LINE_RTS) 337 out |= TIOCM_RTS; 338 if (my & IPW_CONTROL_LINE_DTR) 339 out |= TIOCM_DTR; 340 if (my & IPW_CONTROL_LINE_CTS) 341 out |= TIOCM_CTS; 342 if (my & IPW_CONTROL_LINE_DSR) 343 out |= TIOCM_DSR; 344 if (my & IPW_CONTROL_LINE_DCD) 345 out |= TIOCM_CD; 346 347 return out; 348 } 349 350 static int set_control_lines(struct ipw_tty *tty, unsigned int set, 351 unsigned int clear) 352 { 353 int ret; 354 355 if (set & TIOCM_RTS) { 356 ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 1); 357 if (ret) 358 return ret; 359 if (tty->secondary_channel_idx != -1) { 360 ret = ipwireless_set_RTS(tty->hardware, 361 tty->secondary_channel_idx, 1); 362 if (ret) 363 return ret; 364 } 365 } 366 if (set & TIOCM_DTR) { 367 ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 1); 368 if (ret) 369 return ret; 370 if (tty->secondary_channel_idx != -1) { 371 ret = ipwireless_set_DTR(tty->hardware, 372 tty->secondary_channel_idx, 1); 373 if (ret) 374 return ret; 375 } 376 } 377 if (clear & TIOCM_RTS) { 378 ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 0); 379 if (tty->secondary_channel_idx != -1) { 380 ret = ipwireless_set_RTS(tty->hardware, 381 tty->secondary_channel_idx, 0); 382 if (ret) 383 return ret; 384 } 385 } 386 if (clear & TIOCM_DTR) { 387 ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 0); 388 if (tty->secondary_channel_idx != -1) { 389 ret = ipwireless_set_DTR(tty->hardware, 390 tty->secondary_channel_idx, 0); 391 if (ret) 392 return ret; 393 } 394 } 395 return 0; 396 } 397 398 static int ipw_tiocmget(struct tty_struct *linux_tty) 399 { 400 struct ipw_tty *tty = linux_tty->driver_data; 401 /* FIXME: Exactly how is the tty object locked here .. */ 402 403 if (!tty) 404 return -ENODEV; 405 406 if (!tty->open_count) 407 return -EINVAL; 408 409 return get_control_lines(tty); 410 } 411 412 static int 413 ipw_tiocmset(struct tty_struct *linux_tty, 414 unsigned int set, unsigned int clear) 415 { 416 struct ipw_tty *tty = linux_tty->driver_data; 417 /* FIXME: Exactly how is the tty object locked here .. */ 418 419 if (!tty) 420 return -ENODEV; 421 422 if (!tty->open_count) 423 return -EINVAL; 424 425 return set_control_lines(tty, set, clear); 426 } 427 428 static int ipw_ioctl(struct tty_struct *linux_tty, 429 unsigned int cmd, unsigned long arg) 430 { 431 struct ipw_tty *tty = linux_tty->driver_data; 432 433 if (!tty) 434 return -ENODEV; 435 436 if (!tty->open_count) 437 return -EINVAL; 438 439 /* FIXME: Exactly how is the tty object locked here .. */ 440 441 switch (cmd) { 442 case TIOCGSERIAL: 443 return ipwireless_get_serial_info(tty, (void __user *) arg); 444 445 case TIOCSSERIAL: 446 return 0; /* Keeps the PCMCIA scripts happy. */ 447 } 448 449 if (tty->tty_type == TTYTYPE_MODEM) { 450 switch (cmd) { 451 case PPPIOCGCHAN: 452 { 453 int chan = ipwireless_ppp_channel_index( 454 tty->network); 455 456 if (chan < 0) 457 return -ENODEV; 458 if (put_user(chan, (int __user *) arg)) 459 return -EFAULT; 460 } 461 return 0; 462 463 case PPPIOCGUNIT: 464 { 465 int unit = ipwireless_ppp_unit_number( 466 tty->network); 467 468 if (unit < 0) 469 return -ENODEV; 470 if (put_user(unit, (int __user *) arg)) 471 return -EFAULT; 472 } 473 return 0; 474 475 case FIONREAD: 476 { 477 int val = 0; 478 479 if (put_user(val, (int __user *) arg)) 480 return -EFAULT; 481 } 482 return 0; 483 case TCFLSH: 484 return tty_perform_flush(linux_tty, arg); 485 } 486 } 487 return -ENOIOCTLCMD; 488 } 489 490 static int add_tty(int j, 491 struct ipw_hardware *hardware, 492 struct ipw_network *network, int channel_idx, 493 int secondary_channel_idx, int tty_type) 494 { 495 ttys[j] = kzalloc(sizeof(struct ipw_tty), GFP_KERNEL); 496 if (!ttys[j]) 497 return -ENOMEM; 498 ttys[j]->index = j; 499 ttys[j]->hardware = hardware; 500 ttys[j]->channel_idx = channel_idx; 501 ttys[j]->secondary_channel_idx = secondary_channel_idx; 502 ttys[j]->network = network; 503 ttys[j]->tty_type = tty_type; 504 mutex_init(&ttys[j]->ipw_tty_mutex); 505 506 tty_register_device(ipw_tty_driver, j, NULL); 507 ipwireless_associate_network_tty(network, channel_idx, ttys[j]); 508 509 if (secondary_channel_idx != -1) 510 ipwireless_associate_network_tty(network, 511 secondary_channel_idx, 512 ttys[j]); 513 if (get_tty(j + ipw_tty_driver->minor_start) == ttys[j]) 514 report_registering(ttys[j]); 515 return 0; 516 } 517 518 struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hardware, 519 struct ipw_network *network) 520 { 521 int i, j; 522 523 for (i = 0; i < IPWIRELESS_PCMCIA_MINOR_RANGE; i++) { 524 int allfree = 1; 525 526 for (j = i; j < IPWIRELESS_PCMCIA_MINORS; 527 j += IPWIRELESS_PCMCIA_MINOR_RANGE) 528 if (ttys[j] != NULL) { 529 allfree = 0; 530 break; 531 } 532 533 if (allfree) { 534 j = i; 535 536 if (add_tty(j, hardware, network, 537 IPW_CHANNEL_DIALLER, IPW_CHANNEL_RAS, 538 TTYTYPE_MODEM)) 539 return NULL; 540 541 j += IPWIRELESS_PCMCIA_MINOR_RANGE; 542 if (add_tty(j, hardware, network, 543 IPW_CHANNEL_DIALLER, -1, 544 TTYTYPE_MONITOR)) 545 return NULL; 546 547 j += IPWIRELESS_PCMCIA_MINOR_RANGE; 548 if (add_tty(j, hardware, network, 549 IPW_CHANNEL_RAS, -1, 550 TTYTYPE_RAS_RAW)) 551 return NULL; 552 553 return ttys[i]; 554 } 555 } 556 return NULL; 557 } 558 559 /* 560 * Must be called before ipwireless_network_free(). 561 */ 562 void ipwireless_tty_free(struct ipw_tty *tty) 563 { 564 int j; 565 struct ipw_network *network = ttys[tty->index]->network; 566 567 for (j = tty->index; j < IPWIRELESS_PCMCIA_MINORS; 568 j += IPWIRELESS_PCMCIA_MINOR_RANGE) { 569 struct ipw_tty *ttyj = ttys[j]; 570 571 if (ttyj) { 572 mutex_lock(&ttyj->ipw_tty_mutex); 573 if (get_tty(j + ipw_tty_driver->minor_start) == ttyj) 574 report_deregistering(ttyj); 575 ttyj->closing = 1; 576 if (ttyj->linux_tty != NULL) { 577 mutex_unlock(&ttyj->ipw_tty_mutex); 578 tty_hangup(ttyj->linux_tty); 579 /* Wait till the tty_hangup has completed */ 580 flush_work_sync(&ttyj->linux_tty->hangup_work); 581 /* FIXME: Exactly how is the tty object locked here 582 against a parallel ioctl etc */ 583 mutex_lock(&ttyj->ipw_tty_mutex); 584 } 585 while (ttyj->open_count) 586 do_ipw_close(ttyj); 587 ipwireless_disassociate_network_ttys(network, 588 ttyj->channel_idx); 589 tty_unregister_device(ipw_tty_driver, j); 590 ttys[j] = NULL; 591 mutex_unlock(&ttyj->ipw_tty_mutex); 592 kfree(ttyj); 593 } 594 } 595 } 596 597 static const struct tty_operations tty_ops = { 598 .open = ipw_open, 599 .close = ipw_close, 600 .hangup = ipw_hangup, 601 .write = ipw_write, 602 .write_room = ipw_write_room, 603 .ioctl = ipw_ioctl, 604 .chars_in_buffer = ipw_chars_in_buffer, 605 .tiocmget = ipw_tiocmget, 606 .tiocmset = ipw_tiocmset, 607 }; 608 609 int ipwireless_tty_init(void) 610 { 611 int result; 612 613 ipw_tty_driver = alloc_tty_driver(IPWIRELESS_PCMCIA_MINORS); 614 if (!ipw_tty_driver) 615 return -ENOMEM; 616 617 ipw_tty_driver->owner = THIS_MODULE; 618 ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME; 619 ipw_tty_driver->name = "ttyIPWp"; 620 ipw_tty_driver->major = 0; 621 ipw_tty_driver->minor_start = IPWIRELESS_PCMCIA_START; 622 ipw_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; 623 ipw_tty_driver->subtype = SERIAL_TYPE_NORMAL; 624 ipw_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 625 ipw_tty_driver->init_termios = tty_std_termios; 626 ipw_tty_driver->init_termios.c_cflag = 627 B9600 | CS8 | CREAD | HUPCL | CLOCAL; 628 ipw_tty_driver->init_termios.c_ispeed = 9600; 629 ipw_tty_driver->init_termios.c_ospeed = 9600; 630 tty_set_operations(ipw_tty_driver, &tty_ops); 631 result = tty_register_driver(ipw_tty_driver); 632 if (result) { 633 printk(KERN_ERR IPWIRELESS_PCCARD_NAME 634 ": failed to register tty driver\n"); 635 put_tty_driver(ipw_tty_driver); 636 return result; 637 } 638 639 return 0; 640 } 641 642 void ipwireless_tty_release(void) 643 { 644 int ret; 645 646 ret = tty_unregister_driver(ipw_tty_driver); 647 put_tty_driver(ipw_tty_driver); 648 if (ret != 0) 649 printk(KERN_ERR IPWIRELESS_PCCARD_NAME 650 ": tty_unregister_driver failed with code %d\n", ret); 651 } 652 653 int ipwireless_tty_is_modem(struct ipw_tty *tty) 654 { 655 return tty->tty_type == TTYTYPE_MODEM; 656 } 657 658 void 659 ipwireless_tty_notify_control_line_change(struct ipw_tty *tty, 660 unsigned int channel_idx, 661 unsigned int control_lines, 662 unsigned int changed_mask) 663 { 664 unsigned int old_control_lines = tty->control_lines; 665 666 tty->control_lines = (tty->control_lines & ~changed_mask) 667 | (control_lines & changed_mask); 668 669 /* 670 * If DCD is de-asserted, we close the tty so pppd can tell that we 671 * have gone offline. 672 */ 673 if ((old_control_lines & IPW_CONTROL_LINE_DCD) 674 && !(tty->control_lines & IPW_CONTROL_LINE_DCD) 675 && tty->linux_tty) { 676 tty_hangup(tty->linux_tty); 677 } 678 } 679 680