Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.24 1259 lines 32 kB view raw
1/* r3964 linediscipline for linux 2 * 3 * ----------------------------------------------------------- 4 * Copyright by 5 * Philips Automation Projects 6 * Kassel (Germany) 7 * http://www.pap-philips.de 8 * ----------------------------------------------------------- 9 * This software may be used and distributed according to the terms of 10 * the GNU General Public License, incorporated herein by reference. 11 * 12 * Author: 13 * L. Haag 14 * 15 * $Log: n_r3964.c,v $ 16 * Revision 1.10 2001/03/18 13:02:24 dwmw2 17 * Fix timer usage, use spinlocks properly. 18 * 19 * Revision 1.9 2001/03/18 12:52:14 dwmw2 20 * Merge changes in 2.4.2 21 * 22 * Revision 1.8 2000/03/23 14:14:54 dwmw2 23 * Fix race in sleeping in r3964_read() 24 * 25 * Revision 1.7 1999/28/08 11:41:50 dwmw2 26 * Port to 2.3 kernel 27 * 28 * Revision 1.6 1998/09/30 00:40:40 dwmw2 29 * Fixed compilation on 2.0.x kernels 30 * Updated to newly registered tty-ldisc number 9 31 * 32 * Revision 1.5 1998/09/04 21:57:36 dwmw2 33 * Signal handling bug fixes, port to 2.1.x. 34 * 35 * Revision 1.4 1998/04/02 20:26:59 lhaag 36 * select, blocking, ... 37 * 38 * Revision 1.3 1998/02/12 18:58:43 root 39 * fixed some memory leaks 40 * calculation of checksum characters 41 * 42 * Revision 1.2 1998/02/07 13:03:34 root 43 * ioctl read_telegram 44 * 45 * Revision 1.1 1998/02/06 19:21:03 root 46 * Initial revision 47 * 48 * 49 */ 50 51#include <linux/module.h> 52#include <linux/kernel.h> 53#include <linux/sched.h> 54#include <linux/types.h> 55#include <linux/fcntl.h> 56#include <linux/interrupt.h> 57#include <linux/ptrace.h> 58#include <linux/ioport.h> 59#include <linux/in.h> 60#include <linux/slab.h> 61#include <linux/tty.h> 62#include <linux/errno.h> 63#include <linux/string.h> /* used in new tty drivers */ 64#include <linux/signal.h> /* used in new tty drivers */ 65#include <linux/ioctl.h> 66#include <linux/n_r3964.h> 67#include <linux/poll.h> 68#include <linux/init.h> 69#include <asm/uaccess.h> 70 71/*#define DEBUG_QUEUE*/ 72 73/* Log successful handshake and protocol operations */ 74/*#define DEBUG_PROTO_S*/ 75 76/* Log handshake and protocol errors: */ 77/*#define DEBUG_PROTO_E*/ 78 79/* Log Linediscipline operations (open, close, read, write...): */ 80/*#define DEBUG_LDISC*/ 81 82/* Log module and memory operations (init, cleanup; kmalloc, kfree): */ 83/*#define DEBUG_MODUL*/ 84 85/* Macro helpers for debug output: */ 86#define TRACE(format, args...) printk("r3964: " format "\n" , ## args) 87 88#ifdef DEBUG_MODUL 89#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args) 90#else 91#define TRACE_M(fmt, arg...) do {} while (0) 92#endif 93#ifdef DEBUG_PROTO_S 94#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args) 95#else 96#define TRACE_PS(fmt, arg...) do {} while (0) 97#endif 98#ifdef DEBUG_PROTO_E 99#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args) 100#else 101#define TRACE_PE(fmt, arg...) do {} while (0) 102#endif 103#ifdef DEBUG_LDISC 104#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args) 105#else 106#define TRACE_L(fmt, arg...) do {} while (0) 107#endif 108#ifdef DEBUG_QUEUE 109#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args) 110#else 111#define TRACE_Q(fmt, arg...) do {} while (0) 112#endif 113static void add_tx_queue(struct r3964_info *, struct r3964_block_header *); 114static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code); 115static void put_char(struct r3964_info *pInfo, unsigned char ch); 116static void trigger_transmit(struct r3964_info *pInfo); 117static void retry_transmit(struct r3964_info *pInfo); 118static void transmit_block(struct r3964_info *pInfo); 119static void receive_char(struct r3964_info *pInfo, const unsigned char c); 120static void receive_error(struct r3964_info *pInfo, const char flag); 121static void on_timeout(unsigned long priv); 122static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg); 123static int read_telegram(struct r3964_info *pInfo, struct pid *pid, 124 unsigned char __user * buf); 125static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, 126 int error_code, struct r3964_block_header *pBlock); 127static struct r3964_message *remove_msg(struct r3964_info *pInfo, 128 struct r3964_client_info *pClient); 129static void remove_client_block(struct r3964_info *pInfo, 130 struct r3964_client_info *pClient); 131 132static int r3964_open(struct tty_struct *tty); 133static void r3964_close(struct tty_struct *tty); 134static ssize_t r3964_read(struct tty_struct *tty, struct file *file, 135 unsigned char __user * buf, size_t nr); 136static ssize_t r3964_write(struct tty_struct *tty, struct file *file, 137 const unsigned char *buf, size_t nr); 138static int r3964_ioctl(struct tty_struct *tty, struct file *file, 139 unsigned int cmd, unsigned long arg); 140static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old); 141static unsigned int r3964_poll(struct tty_struct *tty, struct file *file, 142 struct poll_table_struct *wait); 143static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, 144 char *fp, int count); 145 146static struct tty_ldisc tty_ldisc_N_R3964 = { 147 .owner = THIS_MODULE, 148 .magic = TTY_LDISC_MAGIC, 149 .name = "R3964", 150 .open = r3964_open, 151 .close = r3964_close, 152 .read = r3964_read, 153 .write = r3964_write, 154 .ioctl = r3964_ioctl, 155 .set_termios = r3964_set_termios, 156 .poll = r3964_poll, 157 .receive_buf = r3964_receive_buf, 158}; 159 160static void dump_block(const unsigned char *block, unsigned int length) 161{ 162 unsigned int i, j; 163 char linebuf[16 * 3 + 1]; 164 165 for (i = 0; i < length; i += 16) { 166 for (j = 0; (j < 16) && (j + i < length); j++) { 167 sprintf(linebuf + 3 * j, "%02x ", block[i + j]); 168 } 169 linebuf[3 * j] = '\0'; 170 TRACE_PS("%s", linebuf); 171 } 172} 173 174/************************************************************* 175 * Driver initialisation 176 *************************************************************/ 177 178/************************************************************* 179 * Module support routines 180 *************************************************************/ 181 182static void __exit r3964_exit(void) 183{ 184 int status; 185 186 TRACE_M("cleanup_module()"); 187 188 status = tty_unregister_ldisc(N_R3964); 189 190 if (status != 0) { 191 printk(KERN_ERR "r3964: error unregistering linediscipline: " 192 "%d\n", status); 193 } else { 194 TRACE_L("linediscipline successfully unregistered"); 195 } 196} 197 198static int __init r3964_init(void) 199{ 200 int status; 201 202 printk("r3964: Philips r3964 Driver $Revision: 1.10 $\n"); 203 204 /* 205 * Register the tty line discipline 206 */ 207 208 status = tty_register_ldisc(N_R3964, &tty_ldisc_N_R3964); 209 if (status == 0) { 210 TRACE_L("line discipline %d registered", N_R3964); 211 TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags, 212 tty_ldisc_N_R3964.num); 213 TRACE_L("open=%p", tty_ldisc_N_R3964.open); 214 TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964); 215 } else { 216 printk(KERN_ERR "r3964: error registering line discipline: " 217 "%d\n", status); 218 } 219 return status; 220} 221 222module_init(r3964_init); 223module_exit(r3964_exit); 224 225/************************************************************* 226 * Protocol implementation routines 227 *************************************************************/ 228 229static void add_tx_queue(struct r3964_info *pInfo, 230 struct r3964_block_header *pHeader) 231{ 232 unsigned long flags; 233 234 spin_lock_irqsave(&pInfo->lock, flags); 235 236 pHeader->next = NULL; 237 238 if (pInfo->tx_last == NULL) { 239 pInfo->tx_first = pInfo->tx_last = pHeader; 240 } else { 241 pInfo->tx_last->next = pHeader; 242 pInfo->tx_last = pHeader; 243 } 244 245 spin_unlock_irqrestore(&pInfo->lock, flags); 246 247 TRACE_Q("add_tx_queue %p, length %d, tx_first = %p", 248 pHeader, pHeader->length, pInfo->tx_first); 249} 250 251static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code) 252{ 253 struct r3964_block_header *pHeader; 254 unsigned long flags; 255#ifdef DEBUG_QUEUE 256 struct r3964_block_header *pDump; 257#endif 258 259 pHeader = pInfo->tx_first; 260 261 if (pHeader == NULL) 262 return; 263 264#ifdef DEBUG_QUEUE 265 printk("r3964: remove_from_tx_queue: %p, length %u - ", 266 pHeader, pHeader->length); 267 for (pDump = pHeader; pDump; pDump = pDump->next) 268 printk("%p ", pDump); 269 printk("\n"); 270#endif 271 272 if (pHeader->owner) { 273 if (error_code) { 274 add_msg(pHeader->owner, R3964_MSG_ACK, 0, 275 error_code, NULL); 276 } else { 277 add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length, 278 error_code, NULL); 279 } 280 wake_up_interruptible(&pInfo->read_wait); 281 } 282 283 spin_lock_irqsave(&pInfo->lock, flags); 284 285 pInfo->tx_first = pHeader->next; 286 if (pInfo->tx_first == NULL) { 287 pInfo->tx_last = NULL; 288 } 289 290 spin_unlock_irqrestore(&pInfo->lock, flags); 291 292 kfree(pHeader); 293 TRACE_M("remove_from_tx_queue - kfree %p", pHeader); 294 295 TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p", 296 pInfo->tx_first, pInfo->tx_last); 297} 298 299static void add_rx_queue(struct r3964_info *pInfo, 300 struct r3964_block_header *pHeader) 301{ 302 unsigned long flags; 303 304 spin_lock_irqsave(&pInfo->lock, flags); 305 306 pHeader->next = NULL; 307 308 if (pInfo->rx_last == NULL) { 309 pInfo->rx_first = pInfo->rx_last = pHeader; 310 } else { 311 pInfo->rx_last->next = pHeader; 312 pInfo->rx_last = pHeader; 313 } 314 pInfo->blocks_in_rx_queue++; 315 316 spin_unlock_irqrestore(&pInfo->lock, flags); 317 318 TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d", 319 pHeader, pHeader->length, 320 pInfo->rx_first, pInfo->blocks_in_rx_queue); 321} 322 323static void remove_from_rx_queue(struct r3964_info *pInfo, 324 struct r3964_block_header *pHeader) 325{ 326 unsigned long flags; 327 struct r3964_block_header *pFind; 328 329 if (pHeader == NULL) 330 return; 331 332 TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d", 333 pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue); 334 TRACE_Q("remove_from_rx_queue: %p, length %u", 335 pHeader, pHeader->length); 336 337 spin_lock_irqsave(&pInfo->lock, flags); 338 339 if (pInfo->rx_first == pHeader) { 340 /* Remove the first block in the linked list: */ 341 pInfo->rx_first = pHeader->next; 342 343 if (pInfo->rx_first == NULL) { 344 pInfo->rx_last = NULL; 345 } 346 pInfo->blocks_in_rx_queue--; 347 } else { 348 /* Find block to remove: */ 349 for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) { 350 if (pFind->next == pHeader) { 351 /* Got it. */ 352 pFind->next = pHeader->next; 353 pInfo->blocks_in_rx_queue--; 354 if (pFind->next == NULL) { 355 /* Oh, removed the last one! */ 356 pInfo->rx_last = pFind; 357 } 358 break; 359 } 360 } 361 } 362 363 spin_unlock_irqrestore(&pInfo->lock, flags); 364 365 kfree(pHeader); 366 TRACE_M("remove_from_rx_queue - kfree %p", pHeader); 367 368 TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d", 369 pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue); 370} 371 372static void put_char(struct r3964_info *pInfo, unsigned char ch) 373{ 374 struct tty_struct *tty = pInfo->tty; 375 376 if (tty == NULL) 377 return; 378 379 if (tty->driver->put_char) { 380 tty->driver->put_char(tty, ch); 381 } 382 pInfo->bcc ^= ch; 383} 384 385static void flush(struct r3964_info *pInfo) 386{ 387 struct tty_struct *tty = pInfo->tty; 388 389 if (tty == NULL) 390 return; 391 392 if (tty->driver->flush_chars) { 393 tty->driver->flush_chars(tty); 394 } 395} 396 397static void trigger_transmit(struct r3964_info *pInfo) 398{ 399 unsigned long flags; 400 401 spin_lock_irqsave(&pInfo->lock, flags); 402 403 if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) { 404 pInfo->state = R3964_TX_REQUEST; 405 pInfo->nRetry = 0; 406 pInfo->flags &= ~R3964_ERROR; 407 mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ); 408 409 spin_unlock_irqrestore(&pInfo->lock, flags); 410 411 TRACE_PS("trigger_transmit - sent STX"); 412 413 put_char(pInfo, STX); 414 flush(pInfo); 415 416 pInfo->bcc = 0; 417 } else { 418 spin_unlock_irqrestore(&pInfo->lock, flags); 419 } 420} 421 422static void retry_transmit(struct r3964_info *pInfo) 423{ 424 if (pInfo->nRetry < R3964_MAX_RETRIES) { 425 TRACE_PE("transmission failed. Retry #%d", pInfo->nRetry); 426 pInfo->bcc = 0; 427 put_char(pInfo, STX); 428 flush(pInfo); 429 pInfo->state = R3964_TX_REQUEST; 430 pInfo->nRetry++; 431 mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ); 432 } else { 433 TRACE_PE("transmission failed after %d retries", 434 R3964_MAX_RETRIES); 435 436 remove_from_tx_queue(pInfo, R3964_TX_FAIL); 437 438 put_char(pInfo, NAK); 439 flush(pInfo); 440 pInfo->state = R3964_IDLE; 441 442 trigger_transmit(pInfo); 443 } 444} 445 446static void transmit_block(struct r3964_info *pInfo) 447{ 448 struct tty_struct *tty = pInfo->tty; 449 struct r3964_block_header *pBlock = pInfo->tx_first; 450 int room = 0; 451 452 if ((tty == NULL) || (pBlock == NULL)) { 453 return; 454 } 455 456 if (tty->driver->write_room) 457 room = tty->driver->write_room(tty); 458 459 TRACE_PS("transmit_block %p, room %d, length %d", 460 pBlock, room, pBlock->length); 461 462 while (pInfo->tx_position < pBlock->length) { 463 if (room < 2) 464 break; 465 466 if (pBlock->data[pInfo->tx_position] == DLE) { 467 /* send additional DLE char: */ 468 put_char(pInfo, DLE); 469 } 470 put_char(pInfo, pBlock->data[pInfo->tx_position++]); 471 472 room--; 473 } 474 475 if ((pInfo->tx_position == pBlock->length) && (room >= 3)) { 476 put_char(pInfo, DLE); 477 put_char(pInfo, ETX); 478 if (pInfo->flags & R3964_BCC) { 479 put_char(pInfo, pInfo->bcc); 480 } 481 pInfo->state = R3964_WAIT_FOR_TX_ACK; 482 mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ); 483 } 484 flush(pInfo); 485} 486 487static void on_receive_block(struct r3964_info *pInfo) 488{ 489 unsigned int length; 490 struct r3964_client_info *pClient; 491 struct r3964_block_header *pBlock; 492 493 length = pInfo->rx_position; 494 495 /* compare byte checksum characters: */ 496 if (pInfo->flags & R3964_BCC) { 497 if (pInfo->bcc != pInfo->last_rx) { 498 TRACE_PE("checksum error - got %x but expected %x", 499 pInfo->last_rx, pInfo->bcc); 500 pInfo->flags |= R3964_CHECKSUM; 501 } 502 } 503 504 /* check for errors (parity, overrun,...): */ 505 if (pInfo->flags & R3964_ERROR) { 506 TRACE_PE("on_receive_block - transmission failed error %x", 507 pInfo->flags & R3964_ERROR); 508 509 put_char(pInfo, NAK); 510 flush(pInfo); 511 if (pInfo->nRetry < R3964_MAX_RETRIES) { 512 pInfo->state = R3964_WAIT_FOR_RX_REPEAT; 513 pInfo->nRetry++; 514 mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC); 515 } else { 516 TRACE_PE("on_receive_block - failed after max retries"); 517 pInfo->state = R3964_IDLE; 518 } 519 return; 520 } 521 522 /* received block; submit DLE: */ 523 put_char(pInfo, DLE); 524 flush(pInfo); 525 del_timer_sync(&pInfo->tmr); 526 TRACE_PS(" rx success: got %d chars", length); 527 528 /* prepare struct r3964_block_header: */ 529 pBlock = kmalloc(length + sizeof(struct r3964_block_header), 530 GFP_KERNEL); 531 TRACE_M("on_receive_block - kmalloc %p", pBlock); 532 533 if (pBlock == NULL) 534 return; 535 536 pBlock->length = length; 537 pBlock->data = ((unsigned char *)pBlock) + 538 sizeof(struct r3964_block_header); 539 pBlock->locks = 0; 540 pBlock->next = NULL; 541 pBlock->owner = NULL; 542 543 memcpy(pBlock->data, pInfo->rx_buf, length); 544 545 /* queue block into rx_queue: */ 546 add_rx_queue(pInfo, pBlock); 547 548 /* notify attached client processes: */ 549 for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) { 550 if (pClient->sig_flags & R3964_SIG_DATA) { 551 add_msg(pClient, R3964_MSG_DATA, length, R3964_OK, 552 pBlock); 553 } 554 } 555 wake_up_interruptible(&pInfo->read_wait); 556 557 pInfo->state = R3964_IDLE; 558 559 trigger_transmit(pInfo); 560} 561 562static void receive_char(struct r3964_info *pInfo, const unsigned char c) 563{ 564 switch (pInfo->state) { 565 case R3964_TX_REQUEST: 566 if (c == DLE) { 567 TRACE_PS("TX_REQUEST - got DLE"); 568 569 pInfo->state = R3964_TRANSMITTING; 570 pInfo->tx_position = 0; 571 572 transmit_block(pInfo); 573 } else if (c == STX) { 574 if (pInfo->nRetry == 0) { 575 TRACE_PE("TX_REQUEST - init conflict"); 576 if (pInfo->priority == R3964_SLAVE) { 577 goto start_receiving; 578 } 579 } else { 580 TRACE_PE("TX_REQUEST - secondary init " 581 "conflict!? Switching to SLAVE mode " 582 "for next rx."); 583 goto start_receiving; 584 } 585 } else { 586 TRACE_PE("TX_REQUEST - char != DLE: %x", c); 587 retry_transmit(pInfo); 588 } 589 break; 590 case R3964_TRANSMITTING: 591 if (c == NAK) { 592 TRACE_PE("TRANSMITTING - got NAK"); 593 retry_transmit(pInfo); 594 } else { 595 TRACE_PE("TRANSMITTING - got invalid char"); 596 597 pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY; 598 mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ); 599 } 600 break; 601 case R3964_WAIT_FOR_TX_ACK: 602 if (c == DLE) { 603 TRACE_PS("WAIT_FOR_TX_ACK - got DLE"); 604 remove_from_tx_queue(pInfo, R3964_OK); 605 606 pInfo->state = R3964_IDLE; 607 trigger_transmit(pInfo); 608 } else { 609 retry_transmit(pInfo); 610 } 611 break; 612 case R3964_WAIT_FOR_RX_REPEAT: 613 /* FALLTROUGH */ 614 case R3964_IDLE: 615 if (c == STX) { 616 /* Prevent rx_queue from overflow: */ 617 if (pInfo->blocks_in_rx_queue >= 618 R3964_MAX_BLOCKS_IN_RX_QUEUE) { 619 TRACE_PE("IDLE - got STX but no space in " 620 "rx_queue!"); 621 pInfo->state = R3964_WAIT_FOR_RX_BUF; 622 mod_timer(&pInfo->tmr, 623 jiffies + R3964_TO_NO_BUF); 624 break; 625 } 626start_receiving: 627 /* Ok, start receiving: */ 628 TRACE_PS("IDLE - got STX"); 629 pInfo->rx_position = 0; 630 pInfo->last_rx = 0; 631 pInfo->flags &= ~R3964_ERROR; 632 pInfo->state = R3964_RECEIVING; 633 mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ); 634 pInfo->nRetry = 0; 635 put_char(pInfo, DLE); 636 flush(pInfo); 637 pInfo->bcc = 0; 638 } 639 break; 640 case R3964_RECEIVING: 641 if (pInfo->rx_position < RX_BUF_SIZE) { 642 pInfo->bcc ^= c; 643 644 if (c == DLE) { 645 if (pInfo->last_rx == DLE) { 646 pInfo->last_rx = 0; 647 goto char_to_buf; 648 } 649 pInfo->last_rx = DLE; 650 break; 651 } else if ((c == ETX) && (pInfo->last_rx == DLE)) { 652 if (pInfo->flags & R3964_BCC) { 653 pInfo->state = R3964_WAIT_FOR_BCC; 654 mod_timer(&pInfo->tmr, 655 jiffies + R3964_TO_ZVZ); 656 } else { 657 on_receive_block(pInfo); 658 } 659 } else { 660 pInfo->last_rx = c; 661char_to_buf: 662 pInfo->rx_buf[pInfo->rx_position++] = c; 663 mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ); 664 } 665 } 666 /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */ 667 break; 668 case R3964_WAIT_FOR_BCC: 669 pInfo->last_rx = c; 670 on_receive_block(pInfo); 671 break; 672 } 673} 674 675static void receive_error(struct r3964_info *pInfo, const char flag) 676{ 677 switch (flag) { 678 case TTY_NORMAL: 679 break; 680 case TTY_BREAK: 681 TRACE_PE("received break"); 682 pInfo->flags |= R3964_BREAK; 683 break; 684 case TTY_PARITY: 685 TRACE_PE("parity error"); 686 pInfo->flags |= R3964_PARITY; 687 break; 688 case TTY_FRAME: 689 TRACE_PE("frame error"); 690 pInfo->flags |= R3964_FRAME; 691 break; 692 case TTY_OVERRUN: 693 TRACE_PE("frame overrun"); 694 pInfo->flags |= R3964_OVERRUN; 695 break; 696 default: 697 TRACE_PE("receive_error - unknown flag %d", flag); 698 pInfo->flags |= R3964_UNKNOWN; 699 break; 700 } 701} 702 703static void on_timeout(unsigned long priv) 704{ 705 struct r3964_info *pInfo = (void *)priv; 706 707 switch (pInfo->state) { 708 case R3964_TX_REQUEST: 709 TRACE_PE("TX_REQUEST - timeout"); 710 retry_transmit(pInfo); 711 break; 712 case R3964_WAIT_ZVZ_BEFORE_TX_RETRY: 713 put_char(pInfo, NAK); 714 flush(pInfo); 715 retry_transmit(pInfo); 716 break; 717 case R3964_WAIT_FOR_TX_ACK: 718 TRACE_PE("WAIT_FOR_TX_ACK - timeout"); 719 retry_transmit(pInfo); 720 break; 721 case R3964_WAIT_FOR_RX_BUF: 722 TRACE_PE("WAIT_FOR_RX_BUF - timeout"); 723 put_char(pInfo, NAK); 724 flush(pInfo); 725 pInfo->state = R3964_IDLE; 726 break; 727 case R3964_RECEIVING: 728 TRACE_PE("RECEIVING - timeout after %d chars", 729 pInfo->rx_position); 730 put_char(pInfo, NAK); 731 flush(pInfo); 732 pInfo->state = R3964_IDLE; 733 break; 734 case R3964_WAIT_FOR_RX_REPEAT: 735 TRACE_PE("WAIT_FOR_RX_REPEAT - timeout"); 736 pInfo->state = R3964_IDLE; 737 break; 738 case R3964_WAIT_FOR_BCC: 739 TRACE_PE("WAIT_FOR_BCC - timeout"); 740 put_char(pInfo, NAK); 741 flush(pInfo); 742 pInfo->state = R3964_IDLE; 743 break; 744 } 745} 746 747static struct r3964_client_info *findClient(struct r3964_info *pInfo, 748 struct pid *pid) 749{ 750 struct r3964_client_info *pClient; 751 752 for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) { 753 if (pClient->pid == pid) { 754 return pClient; 755 } 756 } 757 return NULL; 758} 759 760static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) 761{ 762 struct r3964_client_info *pClient; 763 struct r3964_client_info **ppClient; 764 struct r3964_message *pMsg; 765 766 if ((arg & R3964_SIG_ALL) == 0) { 767 /* Remove client from client list */ 768 for (ppClient = &pInfo->firstClient; *ppClient; 769 ppClient = &(*ppClient)->next) { 770 pClient = *ppClient; 771 772 if (pClient->pid == pid) { 773 TRACE_PS("removing client %d from client list", 774 pid_nr(pid)); 775 *ppClient = pClient->next; 776 while (pClient->msg_count) { 777 pMsg = remove_msg(pInfo, pClient); 778 if (pMsg) { 779 kfree(pMsg); 780 TRACE_M("enable_signals - msg " 781 "kfree %p", pMsg); 782 } 783 } 784 put_pid(pClient->pid); 785 kfree(pClient); 786 TRACE_M("enable_signals - kfree %p", pClient); 787 return 0; 788 } 789 } 790 return -EINVAL; 791 } else { 792 pClient = findClient(pInfo, pid); 793 if (pClient) { 794 /* update signal options */ 795 pClient->sig_flags = arg; 796 } else { 797 /* add client to client list */ 798 pClient = kmalloc(sizeof(struct r3964_client_info), 799 GFP_KERNEL); 800 TRACE_M("enable_signals - kmalloc %p", pClient); 801 if (pClient == NULL) 802 return -ENOMEM; 803 804 TRACE_PS("add client %d to client list", pid_nr(pid)); 805 spin_lock_init(&pClient->lock); 806 pClient->sig_flags = arg; 807 pClient->pid = get_pid(pid); 808 pClient->next = pInfo->firstClient; 809 pClient->first_msg = NULL; 810 pClient->last_msg = NULL; 811 pClient->next_block_to_read = NULL; 812 pClient->msg_count = 0; 813 pInfo->firstClient = pClient; 814 } 815 } 816 817 return 0; 818} 819 820static int read_telegram(struct r3964_info *pInfo, struct pid *pid, 821 unsigned char __user * buf) 822{ 823 struct r3964_client_info *pClient; 824 struct r3964_block_header *block; 825 826 if (!buf) { 827 return -EINVAL; 828 } 829 830 pClient = findClient(pInfo, pid); 831 if (pClient == NULL) { 832 return -EINVAL; 833 } 834 835 block = pClient->next_block_to_read; 836 if (!block) { 837 return 0; 838 } else { 839 if (copy_to_user(buf, block->data, block->length)) 840 return -EFAULT; 841 842 remove_client_block(pInfo, pClient); 843 return block->length; 844 } 845 846 return -EINVAL; 847} 848 849static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, 850 int error_code, struct r3964_block_header *pBlock) 851{ 852 struct r3964_message *pMsg; 853 unsigned long flags; 854 855 if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) { 856queue_the_message: 857 858 pMsg = kmalloc(sizeof(struct r3964_message), 859 error_code ? GFP_ATOMIC : GFP_KERNEL); 860 TRACE_M("add_msg - kmalloc %p", pMsg); 861 if (pMsg == NULL) { 862 return; 863 } 864 865 spin_lock_irqsave(&pClient->lock, flags); 866 867 pMsg->msg_id = msg_id; 868 pMsg->arg = arg; 869 pMsg->error_code = error_code; 870 pMsg->block = pBlock; 871 pMsg->next = NULL; 872 873 if (pClient->last_msg == NULL) { 874 pClient->first_msg = pClient->last_msg = pMsg; 875 } else { 876 pClient->last_msg->next = pMsg; 877 pClient->last_msg = pMsg; 878 } 879 880 pClient->msg_count++; 881 882 if (pBlock != NULL) { 883 pBlock->locks++; 884 } 885 spin_unlock_irqrestore(&pClient->lock, flags); 886 } else { 887 if ((pClient->last_msg->msg_id == R3964_MSG_ACK) 888 && (pClient->last_msg->error_code == R3964_OVERFLOW)) { 889 pClient->last_msg->arg++; 890 TRACE_PE("add_msg - inc prev OVERFLOW-msg"); 891 } else { 892 msg_id = R3964_MSG_ACK; 893 arg = 0; 894 error_code = R3964_OVERFLOW; 895 pBlock = NULL; 896 TRACE_PE("add_msg - queue OVERFLOW-msg"); 897 goto queue_the_message; 898 } 899 } 900 /* Send SIGIO signal to client process: */ 901 if (pClient->sig_flags & R3964_USE_SIGIO) { 902 kill_pid(pClient->pid, SIGIO, 1); 903 } 904} 905 906static struct r3964_message *remove_msg(struct r3964_info *pInfo, 907 struct r3964_client_info *pClient) 908{ 909 struct r3964_message *pMsg = NULL; 910 unsigned long flags; 911 912 if (pClient->first_msg) { 913 spin_lock_irqsave(&pClient->lock, flags); 914 915 pMsg = pClient->first_msg; 916 pClient->first_msg = pMsg->next; 917 if (pClient->first_msg == NULL) { 918 pClient->last_msg = NULL; 919 } 920 921 pClient->msg_count--; 922 if (pMsg->block) { 923 remove_client_block(pInfo, pClient); 924 pClient->next_block_to_read = pMsg->block; 925 } 926 spin_unlock_irqrestore(&pClient->lock, flags); 927 } 928 return pMsg; 929} 930 931static void remove_client_block(struct r3964_info *pInfo, 932 struct r3964_client_info *pClient) 933{ 934 struct r3964_block_header *block; 935 936 TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid)); 937 938 block = pClient->next_block_to_read; 939 if (block) { 940 block->locks--; 941 if (block->locks == 0) { 942 remove_from_rx_queue(pInfo, block); 943 } 944 } 945 pClient->next_block_to_read = NULL; 946} 947 948/************************************************************* 949 * Line discipline routines 950 *************************************************************/ 951 952static int r3964_open(struct tty_struct *tty) 953{ 954 struct r3964_info *pInfo; 955 956 TRACE_L("open"); 957 TRACE_L("tty=%p, PID=%d, disc_data=%p", 958 tty, current->pid, tty->disc_data); 959 960 pInfo = kmalloc(sizeof(struct r3964_info), GFP_KERNEL); 961 TRACE_M("r3964_open - info kmalloc %p", pInfo); 962 963 if (!pInfo) { 964 printk(KERN_ERR "r3964: failed to alloc info structure\n"); 965 return -ENOMEM; 966 } 967 968 pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL); 969 TRACE_M("r3964_open - rx_buf kmalloc %p", pInfo->rx_buf); 970 971 if (!pInfo->rx_buf) { 972 printk(KERN_ERR "r3964: failed to alloc receive buffer\n"); 973 kfree(pInfo); 974 TRACE_M("r3964_open - info kfree %p", pInfo); 975 return -ENOMEM; 976 } 977 978 pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL); 979 TRACE_M("r3964_open - tx_buf kmalloc %p", pInfo->tx_buf); 980 981 if (!pInfo->tx_buf) { 982 printk(KERN_ERR "r3964: failed to alloc transmit buffer\n"); 983 kfree(pInfo->rx_buf); 984 TRACE_M("r3964_open - rx_buf kfree %p", pInfo->rx_buf); 985 kfree(pInfo); 986 TRACE_M("r3964_open - info kfree %p", pInfo); 987 return -ENOMEM; 988 } 989 990 spin_lock_init(&pInfo->lock); 991 pInfo->tty = tty; 992 init_waitqueue_head(&pInfo->read_wait); 993 pInfo->priority = R3964_MASTER; 994 pInfo->rx_first = pInfo->rx_last = NULL; 995 pInfo->tx_first = pInfo->tx_last = NULL; 996 pInfo->rx_position = 0; 997 pInfo->tx_position = 0; 998 pInfo->last_rx = 0; 999 pInfo->blocks_in_rx_queue = 0; 1000 pInfo->firstClient = NULL; 1001 pInfo->state = R3964_IDLE; 1002 pInfo->flags = R3964_DEBUG; 1003 pInfo->nRetry = 0; 1004 1005 tty->disc_data = pInfo; 1006 tty->receive_room = 65536; 1007 1008 setup_timer(&pInfo->tmr, on_timeout, (unsigned long)pInfo); 1009 1010 return 0; 1011} 1012 1013static void r3964_close(struct tty_struct *tty) 1014{ 1015 struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; 1016 struct r3964_client_info *pClient, *pNext; 1017 struct r3964_message *pMsg; 1018 struct r3964_block_header *pHeader, *pNextHeader; 1019 unsigned long flags; 1020 1021 TRACE_L("close"); 1022 1023 /* 1024 * Make sure that our task queue isn't activated. If it 1025 * is, take it out of the linked list. 1026 */ 1027 del_timer_sync(&pInfo->tmr); 1028 1029 /* Remove client-structs and message queues: */ 1030 pClient = pInfo->firstClient; 1031 while (pClient) { 1032 pNext = pClient->next; 1033 while (pClient->msg_count) { 1034 pMsg = remove_msg(pInfo, pClient); 1035 if (pMsg) { 1036 kfree(pMsg); 1037 TRACE_M("r3964_close - msg kfree %p", pMsg); 1038 } 1039 } 1040 put_pid(pClient->pid); 1041 kfree(pClient); 1042 TRACE_M("r3964_close - client kfree %p", pClient); 1043 pClient = pNext; 1044 } 1045 /* Remove jobs from tx_queue: */ 1046 spin_lock_irqsave(&pInfo->lock, flags); 1047 pHeader = pInfo->tx_first; 1048 pInfo->tx_first = pInfo->tx_last = NULL; 1049 spin_unlock_irqrestore(&pInfo->lock, flags); 1050 1051 while (pHeader) { 1052 pNextHeader = pHeader->next; 1053 kfree(pHeader); 1054 pHeader = pNextHeader; 1055 } 1056 1057 /* Free buffers: */ 1058 wake_up_interruptible(&pInfo->read_wait); 1059 kfree(pInfo->rx_buf); 1060 TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf); 1061 kfree(pInfo->tx_buf); 1062 TRACE_M("r3964_close - tx_buf kfree %p", pInfo->tx_buf); 1063 kfree(pInfo); 1064 TRACE_M("r3964_close - info kfree %p", pInfo); 1065} 1066 1067static ssize_t r3964_read(struct tty_struct *tty, struct file *file, 1068 unsigned char __user * buf, size_t nr) 1069{ 1070 struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; 1071 struct r3964_client_info *pClient; 1072 struct r3964_message *pMsg; 1073 struct r3964_client_message theMsg; 1074 int count; 1075 1076 TRACE_L("read()"); 1077 1078 pClient = findClient(pInfo, task_pid(current)); 1079 if (pClient) { 1080 pMsg = remove_msg(pInfo, pClient); 1081 if (pMsg == NULL) { 1082 /* no messages available. */ 1083 if (file->f_flags & O_NONBLOCK) { 1084 return -EAGAIN; 1085 } 1086 /* block until there is a message: */ 1087 wait_event_interruptible(pInfo->read_wait, 1088 (pMsg = remove_msg(pInfo, pClient))); 1089 } 1090 1091 /* If we still haven't got a message, we must have been signalled */ 1092 1093 if (!pMsg) 1094 return -EINTR; 1095 1096 /* deliver msg to client process: */ 1097 theMsg.msg_id = pMsg->msg_id; 1098 theMsg.arg = pMsg->arg; 1099 theMsg.error_code = pMsg->error_code; 1100 count = sizeof(struct r3964_client_message); 1101 1102 kfree(pMsg); 1103 TRACE_M("r3964_read - msg kfree %p", pMsg); 1104 1105 if (copy_to_user(buf, &theMsg, count)) 1106 return -EFAULT; 1107 1108 TRACE_PS("read - return %d", count); 1109 return count; 1110 } 1111 return -EPERM; 1112} 1113 1114static ssize_t r3964_write(struct tty_struct *tty, struct file *file, 1115 const unsigned char *data, size_t count) 1116{ 1117 struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; 1118 struct r3964_block_header *pHeader; 1119 struct r3964_client_info *pClient; 1120 unsigned char *new_data; 1121 1122 TRACE_L("write request, %d characters", count); 1123/* 1124 * Verify the pointers 1125 */ 1126 1127 if (!pInfo) 1128 return -EIO; 1129 1130/* 1131 * Ensure that the caller does not wish to send too much. 1132 */ 1133 if (count > R3964_MTU) { 1134 if (pInfo->flags & R3964_DEBUG) { 1135 TRACE_L(KERN_WARNING "r3964_write: truncating user " 1136 "packet from %u to mtu %d", count, R3964_MTU); 1137 } 1138 count = R3964_MTU; 1139 } 1140/* 1141 * Allocate a buffer for the data and copy it from the buffer with header prepended 1142 */ 1143 new_data = kmalloc(count + sizeof(struct r3964_block_header), 1144 GFP_KERNEL); 1145 TRACE_M("r3964_write - kmalloc %p", new_data); 1146 if (new_data == NULL) { 1147 if (pInfo->flags & R3964_DEBUG) { 1148 printk(KERN_ERR "r3964_write: no memory\n"); 1149 } 1150 return -ENOSPC; 1151 } 1152 1153 pHeader = (struct r3964_block_header *)new_data; 1154 pHeader->data = new_data + sizeof(struct r3964_block_header); 1155 pHeader->length = count; 1156 pHeader->locks = 0; 1157 pHeader->owner = NULL; 1158 1159 pClient = findClient(pInfo, task_pid(current)); 1160 if (pClient) { 1161 pHeader->owner = pClient; 1162 } 1163 1164 memcpy(pHeader->data, data, count); /* We already verified this */ 1165 1166 if (pInfo->flags & R3964_DEBUG) { 1167 dump_block(pHeader->data, count); 1168 } 1169 1170/* 1171 * Add buffer to transmit-queue: 1172 */ 1173 add_tx_queue(pInfo, pHeader); 1174 trigger_transmit(pInfo); 1175 1176 return 0; 1177} 1178 1179static int r3964_ioctl(struct tty_struct *tty, struct file *file, 1180 unsigned int cmd, unsigned long arg) 1181{ 1182 struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; 1183 if (pInfo == NULL) 1184 return -EINVAL; 1185 switch (cmd) { 1186 case R3964_ENABLE_SIGNALS: 1187 return enable_signals(pInfo, task_pid(current), arg); 1188 case R3964_SETPRIORITY: 1189 if (arg < R3964_MASTER || arg > R3964_SLAVE) 1190 return -EINVAL; 1191 pInfo->priority = arg & 0xff; 1192 return 0; 1193 case R3964_USE_BCC: 1194 if (arg) 1195 pInfo->flags |= R3964_BCC; 1196 else 1197 pInfo->flags &= ~R3964_BCC; 1198 return 0; 1199 case R3964_READ_TELEGRAM: 1200 return read_telegram(pInfo, task_pid(current), 1201 (unsigned char __user *)arg); 1202 default: 1203 return -ENOIOCTLCMD; 1204 } 1205} 1206 1207static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old) 1208{ 1209 TRACE_L("set_termios"); 1210} 1211 1212/* Called without the kernel lock held - fine */ 1213static unsigned int r3964_poll(struct tty_struct *tty, struct file *file, 1214 struct poll_table_struct *wait) 1215{ 1216 struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; 1217 struct r3964_client_info *pClient; 1218 struct r3964_message *pMsg = NULL; 1219 unsigned long flags; 1220 int result = POLLOUT; 1221 1222 TRACE_L("POLL"); 1223 1224 pClient = findClient(pInfo, task_pid(current)); 1225 if (pClient) { 1226 poll_wait(file, &pInfo->read_wait, wait); 1227 spin_lock_irqsave(&pInfo->lock, flags); 1228 pMsg = pClient->first_msg; 1229 spin_unlock_irqrestore(&pInfo->lock, flags); 1230 if (pMsg) 1231 result |= POLLIN | POLLRDNORM; 1232 } else { 1233 result = -EINVAL; 1234 } 1235 return result; 1236} 1237 1238static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, 1239 char *fp, int count) 1240{ 1241 struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; 1242 const unsigned char *p; 1243 char *f, flags = 0; 1244 int i; 1245 1246 for (i = count, p = cp, f = fp; i; i--, p++) { 1247 if (f) 1248 flags = *f++; 1249 if (flags == TTY_NORMAL) { 1250 receive_char(pInfo, *p); 1251 } else { 1252 receive_error(pInfo, flags); 1253 } 1254 1255 } 1256} 1257 1258MODULE_LICENSE("GPL"); 1259MODULE_ALIAS_LDISC(N_R3964);