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