50 #include <linux/module.h>
51 #include <linux/kernel.h>
52 #include <linux/sched.h>
53 #include <linux/types.h>
54 #include <linux/fcntl.h>
56 #include <linux/ptrace.h>
59 #include <linux/slab.h>
60 #include <linux/tty.h>
61 #include <linux/errno.h>
62 #include <linux/string.h>
63 #include <linux/signal.h>
65 #include <linux/n_r3964.h>
66 #include <linux/poll.h>
68 #include <asm/uaccess.h>
85 #define TRACE(format, args...) printk("r3964: " format "\n" , ## args)
88 #define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args)
90 #define TRACE_M(fmt, arg...) do {} while (0)
93 #define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args)
95 #define TRACE_PS(fmt, arg...) do {} while (0)
98 #define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args)
100 #define TRACE_PE(fmt, arg...) do {} while (0)
103 #define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args)
105 #define TRACE_L(fmt, arg...) do {} while (0)
108 #define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args)
110 #define TRACE_Q(fmt, arg...) do {} while (0)
114 static void put_char(
struct r3964_info *pInfo,
unsigned char ch);
115 static void trigger_transmit(
struct r3964_info *pInfo);
116 static void retry_transmit(
struct r3964_info *pInfo);
117 static void transmit_block(
struct r3964_info *pInfo);
118 static void receive_char(
struct r3964_info *pInfo,
const unsigned char c);
119 static void receive_error(
struct r3964_info *pInfo,
const char flag);
120 static void on_timeout(
unsigned long priv);
123 unsigned char __user *
buf);
128 static void remove_client_block(
struct r3964_info *pInfo,
131 static int r3964_open(
struct tty_struct *tty);
132 static void r3964_close(
struct tty_struct *tty);
134 unsigned char __user *
buf,
size_t nr);
136 const unsigned char *
buf,
size_t nr);
138 unsigned int cmd,
unsigned long arg);
142 static void r3964_receive_buf(
struct tty_struct *tty,
const unsigned char *
cp,
150 .close = r3964_close,
152 .write = r3964_write,
153 .ioctl = r3964_ioctl,
154 .set_termios = r3964_set_termios,
156 .receive_buf = r3964_receive_buf,
159 static void dump_block(
const unsigned char *
block,
unsigned int length)
162 char linebuf[16 * 3 + 1];
164 for (i = 0; i <
length; i += 16) {
165 for (j = 0; (j < 16) && (j + i < length); j++) {
166 sprintf(linebuf + 3 * j,
"%02x ", block[i + j]);
168 linebuf[3 *
j] =
'\0';
181 static void __exit r3964_exit(
void)
193 TRACE_L(
"linediscipline successfully unregistered");
197 static int __init r3964_init(
void)
201 printk(
"r3964: Philips r3964 Driver $Revision: 1.10 $\n");
211 tty_ldisc_N_R3964.
num);
213 TRACE_L(
"tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964);
228 static void add_tx_queue(
struct r3964_info *pInfo,
240 pInfo->
tx_last->next = pHeader;
244 spin_unlock_irqrestore(&pInfo->
lock, flags);
246 TRACE_Q(
"add_tx_queue %p, length %d, tx_first = %p",
264 printk(
"r3964: remove_from_tx_queue: %p, length %u - ",
265 pHeader, pHeader->
length);
266 for (pDump = pHeader; pDump; pDump = pDump->
next)
271 if (pHeader->
owner) {
289 spin_unlock_irqrestore(&pInfo->
lock, flags);
292 TRACE_M(
"remove_from_tx_queue - kfree %p", pHeader);
294 TRACE_Q(
"remove_from_tx_queue: tx_first = %p, tx_last = %p",
298 static void add_rx_queue(
struct r3964_info *pInfo,
310 pInfo->
rx_last->next = pHeader;
315 spin_unlock_irqrestore(&pInfo->
lock, flags);
317 TRACE_Q(
"add_rx_queue: %p, length = %d, rx_first = %p, count = %d",
322 static void remove_from_rx_queue(
struct r3964_info *pInfo,
331 TRACE_Q(
"remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
333 TRACE_Q(
"remove_from_rx_queue: %p, length %u",
334 pHeader, pHeader->
length);
348 for (pFind = pInfo->
rx_first; pFind; pFind = pFind->
next) {
349 if (pFind->
next == pHeader) {
362 spin_unlock_irqrestore(&pInfo->
lock, flags);
365 TRACE_M(
"remove_from_rx_queue - kfree %p", pHeader);
367 TRACE_Q(
"remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
371 static void put_char(
struct r3964_info *pInfo,
unsigned char ch)
385 tty->
ops->flush_chars(tty);
388 static void trigger_transmit(
struct r3964_info *pInfo)
400 spin_unlock_irqrestore(&pInfo->
lock, flags);
402 TRACE_PS(
"trigger_transmit - sent STX");
404 put_char(pInfo, STX);
409 spin_unlock_irqrestore(&pInfo->
lock, flags);
413 static void retry_transmit(
struct r3964_info *pInfo)
418 put_char(pInfo, STX);
424 TRACE_PE(
"transmission failed after %d retries",
429 put_char(pInfo,
NAK);
433 trigger_transmit(pInfo);
437 static void transmit_block(
struct r3964_info *pInfo)
443 if (tty ==
NULL || pBlock ==
NULL) {
449 TRACE_PS(
"transmit_block %p, room %d, length %d",
450 pBlock, room, pBlock->
length);
458 put_char(pInfo,
DLE);
466 put_char(pInfo,
DLE);
467 put_char(pInfo, ETX);
469 put_char(pInfo, pInfo->
bcc);
477 static void on_receive_block(
struct r3964_info *pInfo)
488 TRACE_PE(
"checksum error - got %x but expected %x",
496 TRACE_PE(
"on_receive_block - transmission failed error %x",
499 put_char(pInfo,
NAK);
506 TRACE_PE(
"on_receive_block - failed after max retries");
513 put_char(pInfo,
DLE);
516 TRACE_PS(
" rx success: got %d chars", length);
521 TRACE_M(
"on_receive_block - kmalloc %p", pBlock);
527 pBlock->
data = ((
unsigned char *)pBlock) +
536 add_rx_queue(pInfo, pBlock);
549 trigger_transmit(pInfo);
552 static void receive_char(
struct r3964_info *pInfo,
const unsigned char c)
554 switch (pInfo->
state) {
562 transmit_block(pInfo);
563 }
else if (c == STX) {
565 TRACE_PE(
"TX_REQUEST - init conflict");
567 goto start_receiving;
570 TRACE_PE(
"TX_REQUEST - secondary init "
571 "conflict!? Switching to SLAVE mode "
573 goto start_receiving;
576 TRACE_PE(
"TX_REQUEST - char != DLE: %x", c);
577 retry_transmit(pInfo);
583 retry_transmit(pInfo);
585 TRACE_PE(
"TRANSMITTING - got invalid char");
593 TRACE_PS(
"WAIT_FOR_TX_ACK - got DLE");
594 remove_from_tx_queue(pInfo,
R3964_OK);
597 trigger_transmit(pInfo);
599 retry_transmit(pInfo);
609 TRACE_PE(
"IDLE - got STX but no space in "
625 put_char(pInfo,
DLE);
641 }
else if ((c == ETX) && (pInfo->
last_rx ==
DLE)) {
647 on_receive_block(pInfo);
660 on_receive_block(pInfo);
665 static void receive_error(
struct r3964_info *pInfo,
const char flag)
687 TRACE_PE(
"receive_error - unknown flag %d", flag);
693 static void on_timeout(
unsigned long priv)
697 switch (pInfo->
state) {
700 retry_transmit(pInfo);
703 put_char(pInfo,
NAK);
705 retry_transmit(pInfo);
708 TRACE_PE(
"WAIT_FOR_TX_ACK - timeout");
709 retry_transmit(pInfo);
712 TRACE_PE(
"WAIT_FOR_RX_BUF - timeout");
713 put_char(pInfo,
NAK);
718 TRACE_PE(
"RECEIVING - timeout after %d chars",
720 put_char(pInfo,
NAK);
725 TRACE_PE(
"WAIT_FOR_RX_REPEAT - timeout");
730 put_char(pInfo,
NAK);
743 if (pClient->
pid == pid) {
750 static int enable_signals(
struct r3964_info *pInfo,
struct pid *pid,
int arg)
759 ppClient = &(*ppClient)->
next) {
762 if (pClient->
pid == pid) {
763 TRACE_PS(
"removing client %d from client list",
765 *ppClient = pClient->
next;
767 pMsg = remove_msg(pInfo, pClient);
770 TRACE_M(
"enable_signals - msg "
776 TRACE_M(
"enable_signals - kfree %p", pClient);
782 pClient = findClient(pInfo, pid);
790 TRACE_M(
"enable_signals - kmalloc %p", pClient);
794 TRACE_PS(
"add client %d to client list", pid_nr(pid));
797 pClient->
pid = get_pid(pid);
810 static int read_telegram(
struct r3964_info *pInfo,
struct pid *pid,
811 unsigned char __user *
buf)
820 pClient = findClient(pInfo, pid);
821 if (pClient ==
NULL) {
832 remove_client_block(pInfo, pClient);
850 TRACE_M(
"add_msg - kmalloc %p", pMsg);
860 pMsg->
block = pBlock;
872 if (pBlock !=
NULL) {
875 spin_unlock_irqrestore(&pClient->
lock, flags);
880 TRACE_PE(
"add_msg - inc prev OVERFLOW-msg");
886 TRACE_PE(
"add_msg - queue OVERFLOW-msg");
887 goto queue_the_message;
913 remove_client_block(pInfo, pClient);
916 spin_unlock_irqrestore(&pClient->
lock, flags);
921 static void remove_client_block(
struct r3964_info *pInfo,
926 TRACE_PS(
"remove_client_block PID %d", pid_nr(pClient->
pid));
931 if (block->
locks == 0) {
932 remove_from_rx_queue(pInfo, block);
947 TRACE_L(
"tty=%p, PID=%d, disc_data=%p",
951 TRACE_M(
"r3964_open - info kmalloc %p", pInfo);
964 TRACE_M(
"r3964_open - info kfree %p", pInfo);
976 TRACE_M(
"r3964_open - info kfree %p", pInfo);
1003 static void r3964_close(
struct tty_struct *tty)
1009 unsigned long flags;
1022 pNext = pClient->
next;
1024 pMsg = remove_msg(pInfo, pClient);
1027 TRACE_M(
"r3964_close - msg kfree %p", pMsg);
1032 TRACE_M(
"r3964_close - client kfree %p", pClient);
1039 spin_unlock_irqrestore(&pInfo->
lock, flags);
1042 pNextHeader = pHeader->
next;
1044 pHeader = pNextHeader;
1054 TRACE_M(
"r3964_close - info kfree %p", pInfo);
1058 unsigned char __user * buf,
size_t nr)
1070 pClient = findClient(pInfo, task_pid(
current));
1072 pMsg = remove_msg(pInfo, pClient);
1081 (pMsg = remove_msg(pInfo, pClient)));
1092 theMsg.msg_id = pMsg->
msg_id;
1093 theMsg.arg = pMsg->
arg;
1098 TRACE_M(
"r3964_read - msg kfree %p", pMsg);
1115 const unsigned char *
data,
size_t count)
1120 unsigned char *new_data;
1122 TRACE_L(
"write request, %d characters", count);
1136 "packet from %u to mtu %d", count,
R3964_MTU);
1145 TRACE_M(
"r3964_write - kmalloc %p", new_data);
1146 if (new_data ==
NULL) {
1161 pClient = findClient(pInfo, task_pid(
current));
1163 pHeader->
owner = pClient;
1169 dump_block(pHeader->
data, count);
1175 add_tx_queue(pInfo, pHeader);
1176 trigger_transmit(pInfo);
1183 static int r3964_ioctl(
struct tty_struct *tty,
struct file *file,
1184 unsigned int cmd,
unsigned long arg)
1191 return enable_signals(pInfo, task_pid(
current), arg);
1204 return read_telegram(pInfo, task_pid(
current),
1205 (
unsigned char __user *)arg);
1217 static unsigned int r3964_poll(
struct tty_struct *tty,
struct file *file,
1223 unsigned long flags;
1228 pClient = findClient(pInfo, task_pid(
current));
1230 poll_wait(file, &pInfo->
read_wait, wait);
1233 spin_unlock_irqrestore(&pInfo->
lock, flags);
1242 static void r3964_receive_buf(
struct tty_struct *tty,
const unsigned char *
cp,
1243 char *
fp,
int count)
1246 const unsigned char *
p;
1250 for (i = count, p = cp, f = fp;
i; i--, p++) {
1254 receive_char(pInfo, *p);
1256 receive_error(pInfo, flags);