?? hso.c
字號:
return; } /* log status, but don't act on it, we don't need to resubmit anything * anyhow */ if (status) log_usb_status(status, __func__);#ifdef CONFIG_HSO_AUTOPM hso_put_activity(odev->parent);#endif /* Tell the network interface we are ready for another frame */ netif_wake_queue(odev->net);}/* called by kernel when we need to transmit a packet */static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net){ struct hso_net *odev = netdev_priv(net); int result; /* Tell the kernel, "No more frames 'til we are done with this one." */ netif_stop_queue(net);#ifdef CONFIG_HSO_AUTOPM if (hso_get_activity(odev->parent) == -EAGAIN) { odev->skb_tx_buf = skb; return 0; }#endif /* log if asked */ DUMP1(skb->data, skb->len); /* Copy it from kernel memory to OUR memory */ memcpy(odev->mux_bulk_tx_buf, skb->data, skb->len); D1("len: %d/%d", skb->len, MUX_BULK_TX_BUF_SIZE); /* Fill in the URB for shipping it out. */ usb_fill_bulk_urb(odev->mux_bulk_tx_urb, odev->parent->usb, usb_sndbulkpipe(odev->parent->usb, odev->out_endp-> bEndpointAddress & 0x7F), odev->mux_bulk_tx_buf, skb->len, write_bulk_callback, odev); /* Deal with the Zero Length packet problem, I hope */ odev->mux_bulk_tx_urb->transfer_flags |= URB_ZERO_PACKET; /* Send the URB on its merry way. */ result = usb_submit_urb(odev->mux_bulk_tx_urb, GFP_ATOMIC); if (result) { dev_warn(&odev->parent->interface->dev, "failed mux_bulk_tx_urb %d\n", result); STATS(net).tx_errors++; netif_start_queue(net); } else { STATS(net).tx_packets++; STATS(net).tx_bytes += skb->len; /* And tell the kernel when the last transmit started. */ net->trans_start = jiffies; } dev_kfree_skb(skb); /* we're done */ return result;}static void hso_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info){ struct hso_net *odev = netdev_priv(net); strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN); strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN); usb_make_path(odev->parent->usb, info->bus_info, sizeof info->bus_info);}static struct ethtool_ops ops = { .get_drvinfo = hso_get_drvinfo, .get_link = ethtool_op_get_link};/*============================================================================= * function: hso_net_ioctl * purpose: *============================================================================= */static int hso_net_ioctl(struct net_device *net, struct ifreq *rq, int cmd){ struct hso_net *odev = netdev_priv(net); u32 usercmd = 0; char tmp[40]; switch (cmd) { case SIOCDEVPRIVATE + 1: /* Chose this one because */ /* SIOCDEVPRIVATE used somewhere else in this code. */ /* return the number of sent bytes */ D5("Transmitted: %lu", STATS(net).tx_bytes); rq->ifr_ifru.ifru_ivalue = STATS(net).tx_bytes; return 0; case SIOCETHTOOL: /* net specific */ if (copy_from_user(&usercmd, rq->ifr_data, sizeof(usercmd))) return -EFAULT; switch (usercmd) { case ETHTOOL_GDRVINFO: { /* get driver info */ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; strncpy(info.driver, driver_name, ETHTOOL_BUSINFO_LEN); strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN); sprintf(tmp, "usb%d:%d", odev->parent->usb->bus->busnum, odev->parent->usb->devnum); strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN); sprintf(tmp, "%s ", driver_name); strncpy(info.fw_version, tmp, ETHTOOL_BUSINFO_LEN); if (copy_to_user(rq->ifr_data, &info, sizeof(info))) return -EFAULT; return 0; } case ETHTOOL_GLINK: { /* get link status */ struct ethtool_value edata = { ETHTOOL_GLINK }; edata.data = netif_carrier_ok(net); if (copy_to_user(rq->ifr_data, &edata, sizeof(edata))) return -EFAULT; return 0; } default: { netdev_warn(net, "Got unsupported ioctl: %x\n", usercmd); return -EOPNOTSUPP; /* the ethtool user space tool */ /*relies on this */ } } default: return -ENOTTY; /* per ioctl man page */ }}/*============================================================================= * function: hso_net_get_stats * purpose: *============================================================================= */#if (!NETDEVICE_HAS_STATS)static struct net_device_stats *hso_net_get_stats(struct net_device *net){ return &((struct hso_net *) netdev_priv(net))->stats;}#endif/* called when a packet did not ack after watchdogtimeout */static void hso_net_tx_timeout(struct net_device *net){ struct hso_net *odev = netdev_priv(net); if (!odev) return; /* Tell syslog we are hosed. */ netdev_warn(net, "Tx timed out.\n"); /* Tear the waiting frame off the list */ if (odev->mux_bulk_tx_urb && (odev->mux_bulk_tx_urb->status == -EINPROGRESS)) safe_usb_unlink_urb(odev->mux_bulk_tx_urb); /* Update statistics */ STATS(net).tx_errors++;}/* make a real packet from the received USB buffer */static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, unsigned int count, unsigned char is_eop){ unsigned short temp_bytes; unsigned short buffer_offset = 0; unsigned short frame_len; unsigned char *tmp_rx_buf; /* log if needed */ D1("Rx %d bytes", count); DUMP(ip_pkt, min(128, (int)count)); while (count) { switch (odev->rx_parse_state) { case WAIT_IP: /* waiting for IP header. */ /* wanted bytes - size of ip header */ temp_bytes = (count < odev->rx_buf_missing) ? count : odev-> rx_buf_missing; memcpy(((unsigned char *)(&odev->rx_ip_hdr)) + odev->rx_buf_size, ip_pkt + buffer_offset, temp_bytes); odev->rx_buf_size += temp_bytes; buffer_offset += temp_bytes; odev->rx_buf_missing -= temp_bytes; count -= temp_bytes; if (!odev->rx_buf_missing) { /* header is complete allocate an sk_buffer and * continue to WAIT_DATA */ frame_len = ntohs(odev->rx_ip_hdr.tot_len); if ((frame_len > DEFAULT_MRU) || (frame_len < sizeof(struct iphdr))) { netdev_err(odev->net, "Invalid frame (%d) length\n", frame_len); odev->rx_parse_state = WAIT_SYNC; continue; } /* Allocate an sk_buff */ odev->skb_rx_buf = dev_alloc_skb(frame_len); if (!odev->skb_rx_buf) { /* We got no receive buffer. */ D1("could not allocate memory"); odev->rx_parse_state = WAIT_SYNC; return; } /* Here's where it came from */ odev->skb_rx_buf->dev = odev->net; /* Copy what we got so far. make room for iphdr * after tail. */ tmp_rx_buf = skb_put(odev->skb_rx_buf, sizeof(struct iphdr)); memcpy(tmp_rx_buf, (char *)&(odev->rx_ip_hdr), sizeof(struct iphdr)); /* ETH_HLEN */ odev->rx_buf_size = sizeof(struct iphdr); /* Filip actually use .tot_len */ odev->rx_buf_missing = frame_len - sizeof(struct iphdr); odev->rx_parse_state = WAIT_DATA; } break; case WAIT_DATA: temp_bytes = (count < odev->rx_buf_missing) ? count : odev->rx_buf_missing; /* Copy the rest of the bytes that are left in the * buffer into the waiting sk_buf. */ /* Make room for temp_bytes after tail. */ tmp_rx_buf = skb_put(odev->skb_rx_buf, temp_bytes); memcpy(tmp_rx_buf, ip_pkt + buffer_offset, temp_bytes); odev->rx_buf_missing -= temp_bytes; count -= temp_bytes; buffer_offset += temp_bytes; odev->rx_buf_size += temp_bytes; if (!odev->rx_buf_missing) { /* Packet is complete. Inject into stack. */ /* We have IP packet here */ odev->skb_rx_buf->protocol = __constant_htons(ETH_P_IP); /* don't check it */ odev->skb_rx_buf->ip_summed = CHECKSUM_UNNECESSARY; skb_reset_mac_header(odev->skb_rx_buf); /* Ship it off to the kernel */ netif_rx(odev->skb_rx_buf); /* No longer our buffer. */ odev->skb_rx_buf = NULL; /* update out statistics */ STATS(odev->net).rx_packets++; STATS(odev->net).rx_bytes += odev->rx_buf_size; odev->rx_buf_size = 0; odev->rx_buf_missing = sizeof(struct iphdr); odev->rx_parse_state = WAIT_IP; } break; case WAIT_SYNC: D1(" W_S"); count = 0; break; default: D1(" "); count--; break; } } /* Recovery mechanism for WAIT_SYNC state. */ if (is_eop) { if (odev->rx_parse_state == WAIT_SYNC) { odev->rx_parse_state = WAIT_IP; odev->rx_buf_size = 0; odev->rx_buf_missing = sizeof(struct iphdr); } }}/* Moving data from usb to kernel (in interrupt state) */static void read_bulk_callback(CALLBACK_ARGS){ struct hso_net *odev = urb->context; struct net_device *net; int result; int status = urb->status; /* is al ok? (Filip: Who's Al ?) */ if (status) { log_usb_status(status, __func__); return; } /* Sanity check */ if (!odev || !test_bit(HSO_NET_RUNNING, &odev->flags)) { D1("BULK IN callback but driver is not active!"); return; }#ifdef CONFIG_HSO_AUTOPM usb_mark_last_busy(urb->dev);#endif net = odev->net; if (!netif_device_present(net)) { /* Somebody killed our network interface... */ return; } if (odev->parent->port_spec & HSO_INFO_CRC_BUG) { u32 rest; u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF }; rest = urb->actual_length % odev->in_endp->wMaxPacketSize; if (((rest == 5) || (rest == 6)) && !memcmp(((u8 *) urb->transfer_buffer) + urb->actual_length - 4, crc_check, 4)) { urb->actual_length -= 4; } } /* do we even have a packet? */ if (urb->actual_length) { /* Handle the IP stream, add header and push it onto network * stack if the packet is complete. */ spin_lock(&odev->net_lock); packetizeRx(odev, urb->transfer_buffer, urb->actual_length, (urb->transfer_buffer_length > urb->actual_length) ? 1 : 0); spin_unlock(&odev->net_lock); } /* We are done with this URB, resubmit it. Prep the USB to wait for * another frame. Reuse same as received. */ usb_fill_bulk_urb(urb, odev->parent->usb, usb_rcvbulkpipe(odev->parent->usb, odev->in_endp-> bEndpointAddress & 0x7F), urb->transfer_buffer, MUX_BULK_RX_BUF_SIZE, read_bulk_callback, odev); /* Give this to the USB subsystem so it can tell us when more data * arrives. */ result = usb_submit_urb(urb, GFP_ATOMIC); if (result) dev_warn(&odev->parent->interface->dev, "%s failed submit mux_bulk_rx_urb %d\n", __func__, result);}/* Serial driver functions */static void _hso_serial_set_termios(struct tty_struct *tty, struct TERMIOS *old){ struct hso_serial *serial = get_serial_by_tty(tty); struct TERMIOS *termios; if ((!tty) || (!tty->termios) || (!serial)) { printk(KERN_ERR "%s: no tty structures", __func__); return; } D4("port %d", serial->minor); /* * The default requirements for this device are: */ termios = tty->termios; termios->c_iflag &= ~(IGNBRK /* disable ignore break */ | BRKINT /* disable break causes interrupt */ | PARMRK /* disable mark parity errors */ | ISTRIP /* disable clear high bit of input characters */ | INLCR /* disable translate NL to CR */ | IGNCR /* disable ignore CR */ | ICRNL /* disable translate CR to NL */ | IXON); /* disable enable XON/XOFF flow control */ /* disable postprocess output characters */ termios->c_oflag &= ~OPOST; termios->c_lflag &= ~(ECHO /* disable echo input characters */ | ECHONL /* disable echo new line */ | ICANON /* disable erase, kill, werase, and rprnt special characters */ | ISIG /* disable interrupt, quit, and suspend special characters */ | IEXTEN); /* disable non-POSIX special characters */ termios->c_cflag &= ~(CSIZE /* no size */ | PARENB /* disable parity bit */ | CBAUD /* clear current baud rate */ | CBAUDEX); /* clear current buad rate */ termios->c_cflag |= CS8; /* character size 8 bits */#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 26)) /* baud rate 115200 */ tty_encode_baud_rate(serial->tty, 115200, 115200);#endif /* * Force low_latency on; otherwise the pushes are scheduled; * this is bad as it opens up the possibility of dropping bytes * on the floor. We don't want to drop bytes on the floor. :) */ serial->tty->low_latency = 1;#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 26)) serial->tty->termios->c_cflag |= B115200; /* baud rate 115200 */ serial->tty->ldisc.set_termios(serial->tty, NULL);#endif return;}static void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb){ int result;#ifdef CONFIG_HSO_AUTOPM usb_mark_last_busy(urb->dev);#endif /* We are done with this URB, resubmit it. Prep the USB to wait for * another frame */ usb_fill_bulk_urb(urb, serial->parent->usb, usb_rcvbulkpipe(serial->parent->usb, serial->in_endp-> bEndpointAddress & 0x7F), urb->transfer_buffer, serial->rx_data_length, hso_std_serial_read_bulk_callback, serial); /* Give this to the USB subsystem so it can tell us when more data * arrives. */ result = usb_submit_urb(urb, GFP_ATOMIC); if (result) { dev_err(&urb->dev->dev, "%s failed submit serial rx_urb %d\n", __func__, result); }}static void put_rxbuf_data_and_resubmit_bulk_urb(struct hso_serial *serial){ int count; struct urb *curr_urb; while (serial->rx_urb_filled[serial->curr_rx_urb_idx]) { curr_urb = serial->rx_urb[serial->curr_rx_urb_idx]; count = put_rxbuf_data(curr_urb, serial); if (count == -1) return; if (count == 0) { serial->curr_rx_urb_idx++; if (serial->curr_rx_urb_idx >= serial->num_rx_urbs) serial->curr_rx_urb_idx = 0; hso_resubmit_rx_bulk_urb(serial, curr_urb);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -