📄 usb-cdc-eth-raw.c
字号:
static int usbc_open( struct inode *pInode, struct file *pFile ){ DPRINTK("\n"); usb_ref_count++; MOD_INC_USE_COUNT; kick_start_rx(); return 0;}static ssize_t usbc_read( struct file *pFile, char *pUserBuffer, size_t stCount, loff_t *pPos ){ ssize_t retval; int flags; DECLARE_WAITQUEUE( wait, current ); DPRINTK("\n"); local_irq_save( flags ); if ( last_rx_result == 0 ) { local_irq_restore( flags ); } else { /* an error happended and receiver is paused */ local_irq_restore( flags ); last_rx_result = 0; kick_start_rx(); } add_wait_queue( &wq_read, &wait ); while ( 1 ) { ssize_t bytes_avail; ssize_t bytes_to_end; set_current_state( TASK_INTERRUPTIBLE ); /* snap ring buf state */ local_irq_save( flags ); bytes_avail = CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE ); bytes_to_end = CIRC_CNT_TO_END( rx_ring.in, rx_ring.out, RBUF_SIZE ); local_irq_restore( flags ); if ( bytes_avail != 0 ) { ssize_t bytes_to_move = MIN( stCount, bytes_avail ); retval = 0; // will be bytes transfered if ( bytes_to_move != 0 ) { size_t n = MIN( bytes_to_end, bytes_to_move ); if ( copy_to_user( pUserBuffer, &rx_ring.buf[ rx_ring.out ], n ) ) { retval = -EFAULT; break; } bytes_to_move -= n; retval += n; // might go 1 char off end, so wrap rx_ring.out = ( rx_ring.out + n ) & (RBUF_SIZE-1); if ( copy_to_user( pUserBuffer + n, &rx_ring.buf[ rx_ring.out ], bytes_to_move ) ) { DPRINTK( "copy_to_user() failed\n" ); retval = -EFAULT; break; } rx_ring.out += bytes_to_move; // cannot wrap retval += bytes_to_move; kick_start_rx(); } break; } else if ( last_rx_result ) { retval = last_rx_result; break; } else if ( pFile->f_flags & O_NONBLOCK ) { // no data, can't sleep DPRINTK( "non blocking\n" ); retval = -EAGAIN; break; } else if ( signal_pending( current ) ) { // no data, can sleep, but signal DPRINTK( "signal pending\n" ); retval = -ERESTARTSYS; break; } schedule(); // no data, can sleep } set_current_state( TASK_RUNNING ); remove_wait_queue( &wq_read, &wait ); return retval;}static ssize_t usbc_write( struct file *pFile, const char * pUserBuffer, size_t stCount, loff_t *pPos ){ ssize_t retval = 0; ssize_t stSent = 0; DECLARE_WAITQUEUE( wait, current ); DPRINTK("%d bytes\n", stCount ); down( &xmit_sem ); // only one thread onto the hardware at a time while( stCount != 0 && retval == 0 ) { int nThisTime = MIN( TX_PACKET_SIZE, stCount ); copy_from_user( tx_buf, pUserBuffer, nThisTime ); sending = nThisTime; retval = elfin_usb_send( tx_buf, nThisTime, tx_done_callback ); if ( retval < 0 ) { DPRINTK( "Could not queue xmission. rc=%d\n", retval ); sending = 0; break; } /* now have something on the diving board */ add_wait_queue( &wq_write, &wait ); tx_timer.expires = jiffies + ( HZ * 5 ); add_timer( &tx_timer ); while( 1 ) { set_current_state( TASK_INTERRUPTIBLE ); if ( sending == 0 ) { /* it jumped into the pool */ del_timer( &tx_timer ); retval = last_tx_result; if ( retval == 0 ) { stSent += last_tx_size; pUserBuffer += last_tx_size; stCount -= last_tx_size; } else DPRINTK( "xmission error rc=%d\n", retval ); break; } else if ( signal_pending( current ) ) { del_timer( &tx_timer ); DPRINTK( "signal pending\n" ); retval = -ERESTARTSYS; break; } schedule(); } set_current_state( TASK_RUNNING ); remove_wait_queue( &wq_write, &wait ); } up( &xmit_sem ); if ( retval == 0 ) retval = stSent; return retval;}static unsigned int usbc_poll( struct file *pFile, poll_table * pWait ){ unsigned int retval = 0; DPRINTK("\n"); poll_wait( pFile, &wq_poll, pWait ); if ( CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE ) ) retval |= POLLIN | POLLRDNORM; if ( elfin_usb_xmitter_avail() ) retval |= POLLOUT | POLLWRNORM; return retval;}static int usbc_ioctl( struct inode *pInode, struct file *pFile, unsigned int nCmd, unsigned long argument ){ int retval = 0; DPRINTK("cmd: 0x%08x\n", nCmd); switch( nCmd ) { case USBC_IOC_FLUSH_RECEIVER: elfin_usb_recv_reset(); rx_ring.in = rx_ring.out = 0; break; case USBC_IOC_FLUSH_TRANSMITTER: elfin_usb_send_reset(); break; case USBC_IOC_FLUSH_ALL: elfin_usb_recv_reset(); rx_ring.in = rx_ring.out = 0; elfin_usb_send_reset(); break; default: retval = -ENOIOCTLCMD; break; } return retval;}static int usbc_close( struct inode *pInode, struct file * pFile ){ DPRINTK("\n"); elfin_usb_recv_reset(); usb_ref_count--; MOD_DEC_USE_COUNT; return 0;}//////////////////////////////////////////////////////////////////////////////// Initialization//////////////////////////////////////////////////////////////////////////////static struct file_operations usbc_fops = { owner: THIS_MODULE, open: usbc_open, read: usbc_read, write: usbc_write, poll: usbc_poll, ioctl: usbc_ioctl, release: usbc_close,};static struct miscdevice usbc_misc_device = { USBC_MINOR, "usb_char", &usbc_fops};static int usbc_activate(void){ int retval = 0; /* start usb core */ retval = elfin_usb_open( "usb-cdc-eth-raw" ); if ( retval ) { printk( "usb-cdc-eth-raw: failed to open USB core\n" ); return retval; } twiddle_descriptors(); retval = elfin_usb_start(); if ( retval ) { printk( "usb-cdc-eth-raw: failed to start USB core\n" ); elfin_usb_close(); return retval; } return 0;}static void usbc_deactivate(void){ down( &xmit_sem ); elfin_usb_stop(); del_timer( &tx_timer ); elfin_usb_close(); up( &xmit_sem );}#ifdef CONFIG_PMstatic struct pm_dev *usbc_pm_dev;static int usbc_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data){ DPRINTK("req: %d\n", req); switch (req) { case PM_RESUME: usbc_activate(); break; case PM_SUSPEND: usbc_deactivate(); break; } return 0;}#endif/* * usbc_init() */static int __init usbc_init( void ){ int rc; if ( (rc = misc_register( &usbc_misc_device )) != 0 ) { printk("usb-cdc-eth-raw: failed to register device\n"); return rc; } // initialize wait queues init_waitqueue_head( &wq_read ); init_waitqueue_head( &wq_write ); init_waitqueue_head( &wq_poll ); // initialize tx timeout timer init_timer( &tx_timer ); tx_timer.function = tx_timeout;#ifdef CONFIG_PM usbc_pm_dev = pm_register(PM_SYS_DEV, MZ_PM_SYS, usbc_pm_callback);#endif alloc_txrx_buffers(); usbc_activate(); printk("USB Function CDC Ethernet Driver Raw Access Mode Interface\n"); return rc;}static void __exit usbc_exit( void ){ usbc_deactivate(); free_txrx_buffers(); free_string_descriptors();#ifdef CONFIG_PM if (usbc_pm_dev) pm_unregister(usbc_pm_dev);#endif misc_deregister( &usbc_misc_device );}module_init(usbc_init);module_exit(usbc_exit);EXPORT_NO_SYMBOLS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -