#include <linux/string.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> #include <linux/device.h> //#include <linux/smp_lock.h> #include <linux/cdev.h> #include <linux/spinlock.h> #include <linux/proc_fs.h> #include <linux/err.h> #include <linux/syscalls.h> #include <linux/kthread.h> #include <linux/sched.h> #include <linux/delay.h> #include <linux/skbuff.h> #include <linux/atmdev.h> #include <linux/atm.h> #include "xdsl_ctrl.h" #include "xdsl_ctrl_api.h" #define WAITING 0 #define RUNNING 1 extern int CheckTPScount_Flag; extern void enable_ptm(void); extern void disable_ptm(void); extern void slave_bonding_rx_fifo_full(void); extern void slave_bonding_rx_fifo_check(void); static char xdsl_thread = 0; unsigned char cmd_data_buffer[ DSL_CMD_POOL_SIZE ][ DSL_MAX_BUF_SIZE ]; xdsl_cmd_pool cmd_pool; int xdsl_kthread_pid; spinlock_t rx_lock; extern cmd_t cmdTable[]; static DECLARE_WAIT_QUEUE_HEAD(xdsl_event_waitqueue); extern int xdsl_ctrl_tx_final(uint8 devnum, uint8 category, uint8 protocol, uint32 command, uint32 arg, uint32 argsize, uint32 ret, uint32 seg_num); extern int XDSLCommand(unsigned int command, unsigned long inarg); extern int PTMCommand(unsigned int command, unsigned long inarg); static int xdsl_kthread(void* rx_data) { unsigned char category=0; unsigned int flags; int index=0, ret=0, seg_num=0, size; xdsl_cmd *command; xdsl_arg *argument; DECLARE_WAITQUEUE(wait, current); /* wait queue.entry */ // daemonize("xdsl_kthread"); allow_signal(SIGKILL); add_wait_queue(&xdsl_event_waitqueue, &wait); for (;;){ if (xdsl_thread == WAITING){ set_current_state(TASK_INTERRUPTIBLE); /* kthread:interruptible */ schedule(); /* CPU */ if (signal_pending(current)) { /* SIGKILL signal */ printk("xdsl_kthread: received a SIGKILL signal\n"); break; } } index = cmd_pool.start; command = &cmd_pool.data[index]; switch(command->protocol) { case XDSL_CMD_SET: ret = XDSLCommand(command->cmdId, command->argp); break; case XDSL_CMD_GET: ret = XDSLCommand(command->cmdId, command->argp); if (command->category == CTRL_2DSL_GET){ category = CTRL_2SOC_RET; } else if (command->category == CTRL_2MASTER_GET){ category = CTRL_2SLAVE_RET; } if (command->argp){ argument = (xdsl_arg*)command->argp; size = argument->argsize; seg_num = 0; while (size>0){ if (size > DSL_RXBUF_MAX_SIZE){ xdsl_ctrl_tx_final(category, XDSL_CMD_DATA, command->devnum, command->cmdId, argument->arg, DSL_RXBUF_MAX_SIZE, ret, seg_num); size -= DSL_RXBUF_MAX_SIZE; seg_num++; } else { xdsl_ctrl_tx_final(category, XDSL_CMD_DATA_EOF, command->devnum, command->cmdId, argument->arg, size, ret, seg_num); break; } } } else { xdsl_ctrl_tx_final(category, XDSL_CMD_DATA_EOF, command->devnum, command->cmdId, 0, 0, ret, 0); } break; #if defined(CONFIG_PTM_BONDING_MASTER) case XDSL_ERB_SET: erb_printk("Process XDSL_ERB_SET...\n"); erb_dump_rxbuf(command->buf, command->argument.argsize); re865x_send_slave_ERB(command->buf, command->argument.argsize); kfree(command->buf); break; case SLAVE_XDSL_UP: enable_ptm(); break; case SLAVE_XDSL_DOWN: disable_ptm(); break; case SLAVE_RX_FIFO_FULL: slave_bonding_rx_fifo_full(); break; case SLAVE_RX_FIFO_CHECK: slave_bonding_rx_fifo_check(); break; #endif #if defined(CONFIG_PTM_BONDING_SLAVE) case SLAVE_TPSTC_RX_POLLING: CheckTPScount_Flag = 1; break; #endif case PTM_CMD_SET: ret = PTMCommand(command->cmdId, command->argp); break; case PTM_CMD_GET: ret = PTMCommand(command->cmdId, command->argp); if (command->category == CTRL_2DSL_GET){ category = CTRL_2SOC_RET; xdsl_ctrl_tx_final(category, PTM_CMD_DATA, command->devnum, command->cmdId, 0, 0, ret, 0); } break; default: break; } spin_lock_irqsave(&rx_lock, flags); cmd_pool.start++; cmd_pool.counter--; if (cmd_pool.start == DSL_CMD_POOL_SIZE){ cmd_pool.start = 0; } if (cmd_pool.counter == 0){ xdsl_thread = WAITING; } spin_unlock_irqrestore(&rx_lock, flags); xdsl_ctrl_ret(command->protocol); } set_current_state(TASK_RUNNING); /* kthread running */ remove_wait_queue(&xdsl_event_waitqueue, &wait); /* kthread wait queue */ return 0; } static int xdsl_kthread_init(void) { xdsl_kthread_pid = kernel_thread(xdsl_kthread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); /* ....kthread */ if (xdsl_kthread_pid > 0) { printk("Created xdsl_kthread PID = %d\n", xdsl_kthread_pid); } else { printk("Failed to create xdsl_kthread\n"); } cmd_pool.start = 0; cmd_pool.tail = 0; cmd_pool.counter = 0; printk("xdsl_kthread module loaded\n"); return 0; } void xdsl_ctrl_rx_final(void *data, uint32 pkt_len) { int i, size, index=0; ctrl_pkt_t *ctrlp; ctrlp = get_ctrl_pkt(data); i = cmd_pool.tail; cmd_pool.data[i].devnum = ctrlp->devnum; cmd_pool.data[i].cmdId = ntohl((unsigned int) ctrlp->command); cmd_pool.data[i].protocol = ctrlp->protocol; cmd_pool.data[i].category = ctrlp->category; /*===================== Command/Webpage ============================*/ if (ctrlp->protocol==XDSL_CMD_SET || ctrlp->protocol==XDSL_CMD_GET){ if (ctrlp->command==RLCM_UserSetDslData || ctrlp->command==RLCM_UserGetDslData){ cmd_pool.data[i].argp = (unsigned long) &cmd_pool.data[i].argument; cmd_pool.data[i].argument.argsize = ntohl(ctrlp->argsize); cmd_pool.data[i].message.msg = ntohl(ctrlp->msg); memcpy(cmd_data_buffer[i], (char*)ctrlp->arg, DSL_ARG_MAX_SIZE ); cmd_pool.data[i].message.intVal = (int*)cmd_data_buffer[i]; cmd_pool.data[i].argument.arg = (int)(&cmd_pool.data[i].message); } else if ((ctrlp->command>=ADSL_CMD_BASE && ctrlp->command<=ADSL_CMD_END) || (ctrlp->command>=VDSL_CMD_BASE && ctrlp->command<=VDSL_CMD_END)){ if (ctrlp->argsize==0){ cmd_pool.data[i].argp = 0; cmd_pool.data[i].argument.arg = 0; cmd_pool.data[i].argument.argsize = 0; } else { cmd_pool.data[i].argp = (unsigned long) &cmd_pool.data[i].argument; index = 0; for (size=0; size<ctrlp->argsize; size++){ cmd_data_buffer[cmd_pool.tail][index] = ctrlp->arg[index]; index++; } cmd_pool.data[i].argument.arg = (unsigned long) &cmd_data_buffer[cmd_pool.tail]; cmd_pool.data[i].argument.argsize = ntohl(ctrlp->argsize); } } } else if (ctrlp->protocol==XDSL_ERB_SET) { erb_printk("Receive ERB from slave\n"); erb_dump_ctrlp(ctrlp); cmd_pool.data[i].argument.argsize = ntohl(ctrlp->argsize); cmd_pool.data[i].buf = kmalloc(cmd_pool.data[i].argument.argsize, GFP_KERNEL); if (cmd_pool.data[i].buf == NULL) { printk("alloc memory for cmd_pool.data[%d].buf fail\n", i); free_ctrl_pkt(data); return; } memcpy(cmd_pool.data[i].buf, ctrlp->rxbuf, cmd_pool.data[i].argument.argsize); } else if (ctrlp->protocol==PTM_CMD_SET || ctrlp->protocol==PTM_CMD_GET){ index = 0; for (size=0; size<ctrlp->argsize; size++){ cmd_data_buffer[cmd_pool.tail][index] = ctrlp->arg[index]; index++; } cmd_pool.data[i].argp = (unsigned long) &cmd_data_buffer[cmd_pool.tail]; } else if (ctrlp->protocol==SLAVE_XDSL_UP || ctrlp->protocol==SLAVE_XDSL_DOWN){ if (ctrlp->protocol==SLAVE_XDSL_UP) printk("SLAVE XDSL UP\n"); else printk("SLAVE XDSL DOWN\n"); } else if (ctrlp->category==CTRL_SLAVE_EXECEPTION){ if (ctrlp->protocol==SLAVE_RX_FIFO_FULL) printk("SLAVE RX FIFO FULL\n"); else if (ctrlp->protocol==SLAVE_RX_FIFO_CHECK) printk("SLAVE RX FIFO CHECK\n"); } else { printk("invalid dsl command, do nothing!!\n"); free_ctrl_pkt(data); return; } free_ctrl_pkt(data); spin_lock(&rx_lock); cmd_pool.counter++; cmd_pool.tail++; xdsl_thread = RUNNING; spin_unlock(&rx_lock); if (cmd_pool.tail == DSL_CMD_POOL_SIZE){ cmd_pool.tail = 0; } if (cmd_pool.counter >= DSL_CMD_POOL_SIZE){ printk("xdsl command pool is full!!\n"); } wake_up_interruptible(&xdsl_event_waitqueue); /* wake up kthread */ } void xdsl_ctrl_receive( void *recv_pkt, unsigned long size) { xdsl_ctrl_rx_final( recv_pkt, size ); } void xdsl_ctrl_rx_init(void) { xdsl_kthread_init(); }