📄 lcs.c
字号:
break; default: PRINT_INFO("UNRECOGNIZED LGW COMMAND\n"); break; } } else lcs_notify_lancmd_waiters(card, cmd);}/** * Unpack network packet. */static voidlcs_get_skb(struct lcs_card *card, char *skb_data, unsigned int skb_len){ struct sk_buff *skb; LCS_DBF_TEXT(5, trace, "getskb"); if (card->dev == NULL || card->state != DEV_STATE_UP) /* The card isn't up. Ignore the packet. */ return; skb = dev_alloc_skb(skb_len); if (skb == NULL) { PRINT_ERR("LCS: alloc_skb failed for device=%s\n", card->dev->name); card->stats.rx_dropped++; return; } skb->dev = card->dev; memcpy(skb_put(skb, skb_len), skb_data, skb_len); skb->protocol = card->lan_type_trans(skb, card->dev); card->stats.rx_bytes += skb_len; card->stats.rx_packets++; *((__u32 *)skb->cb) = ++card->pkt_seq; netif_rx(skb);}/** * LCS main routine to get packets and lancmd replies from the buffers */static voidlcs_get_frames_cb(struct lcs_channel *channel, struct lcs_buffer *buffer){ struct lcs_card *card; struct lcs_header *lcs_hdr; __u16 offset; LCS_DBF_TEXT(5, trace, "lcsgtpkt"); lcs_hdr = (struct lcs_header *) buffer->data; if (lcs_hdr->offset == LCS_ILLEGAL_OFFSET) { LCS_DBF_TEXT(4, trace, "-eiogpkt"); return; } card = (struct lcs_card *) ((char *) channel - offsetof(struct lcs_card, read)); offset = 0; while (lcs_hdr->offset != 0) { if (lcs_hdr->offset <= 0 || lcs_hdr->offset > LCS_IOBUFFERSIZE || lcs_hdr->offset < offset) { /* Offset invalid. */ card->stats.rx_length_errors++; card->stats.rx_errors++; return; } /* What kind of frame is it? */ if (lcs_hdr->type == LCS_FRAME_TYPE_CONTROL) /* Control frame. */ lcs_get_control(card, (struct lcs_cmd *) lcs_hdr); else if (lcs_hdr->type == LCS_FRAME_TYPE_ENET || lcs_hdr->type == LCS_FRAME_TYPE_TR || lcs_hdr->type == LCS_FRAME_TYPE_FDDI) /* Normal network packet. */ lcs_get_skb(card, (char *)(lcs_hdr + 1), lcs_hdr->offset - offset - sizeof(struct lcs_header)); else /* Unknown frame type. */ ; // FIXME: error message ? /* Proceed to next frame. */ offset = lcs_hdr->offset; lcs_hdr->offset = LCS_ILLEGAL_OFFSET; lcs_hdr = (struct lcs_header *) (buffer->data + offset); } /* The buffer is now empty. Make it ready again. */ lcs_ready_buffer(&card->read, buffer);}/** * get network statistics for ifconfig and other user programs */static struct net_device_stats *lcs_getstats(struct net_device *dev){ struct lcs_card *card; LCS_DBF_TEXT(4, trace, "netstats"); card = (struct lcs_card *) dev->priv; return &card->stats;}/** * stop lcs device * This function will be called by user doing ifconfig xxx down */static intlcs_stop_device(struct net_device *dev){ struct lcs_card *card; int rc; LCS_DBF_TEXT(2, trace, "stopdev"); card = (struct lcs_card *) dev->priv; netif_carrier_off(dev); netif_tx_disable(dev); dev->flags &= ~IFF_UP; wait_event(card->write.wait_q, (card->write.state != CH_STATE_RUNNING)); rc = lcs_stopcard(card); if (rc) PRINT_ERR("Try it again!\n "); return rc;}/** * start lcs device and make it runnable * This function will be called by user doing ifconfig xxx up */static intlcs_open_device(struct net_device *dev){ struct lcs_card *card; int rc; LCS_DBF_TEXT(2, trace, "opendev"); card = (struct lcs_card *) dev->priv; /* initialize statistics */ rc = lcs_detect(card); if (rc) { PRINT_ERR("LCS:Error in opening device!\n"); } else { dev->flags |= IFF_UP; netif_carrier_on(dev); netif_wake_queue(dev); card->state = DEV_STATE_UP; } return rc;}/** * show function for portno called by cat or similar things */static ssize_tlcs_portno_show (struct device *dev, struct device_attribute *attr, char *buf){ struct lcs_card *card; card = (struct lcs_card *)dev->driver_data; if (!card) return 0; return sprintf(buf, "%d\n", card->portno);}/** * store the value which is piped to file portno */static ssize_tlcs_portno_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct lcs_card *card; int value; card = (struct lcs_card *)dev->driver_data; if (!card) return 0; sscanf(buf, "%u", &value); /* TODO: sanity checks */ card->portno = value; return count;}static DEVICE_ATTR(portno, 0644, lcs_portno_show, lcs_portno_store);static ssize_tlcs_type_show(struct device *dev, struct device_attribute *attr, char *buf){ struct ccwgroup_device *cgdev; cgdev = to_ccwgroupdev(dev); if (!cgdev) return -ENODEV; return sprintf(buf, "%s\n", cu3088_type[cgdev->cdev[0]->id.driver_info]);}static DEVICE_ATTR(type, 0444, lcs_type_show, NULL);static ssize_tlcs_timeout_show(struct device *dev, struct device_attribute *attr, char *buf){ struct lcs_card *card; card = (struct lcs_card *)dev->driver_data; return card ? sprintf(buf, "%u\n", card->lancmd_timeout) : 0;}static ssize_tlcs_timeout_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct lcs_card *card; int value; card = (struct lcs_card *)dev->driver_data; if (!card) return 0; sscanf(buf, "%u", &value); /* TODO: sanity checks */ card->lancmd_timeout = value; return count;}DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store);static ssize_tlcs_dev_recover_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct lcs_card *card = dev->driver_data; char *tmp; int i; if (!card) return -EINVAL; if (card->state != DEV_STATE_UP) return -EPERM; i = simple_strtoul(buf, &tmp, 16); if (i == 1) lcs_schedule_recovery(card); return count;}static DEVICE_ATTR(recover, 0200, NULL, lcs_dev_recover_store);static struct attribute * lcs_attrs[] = { &dev_attr_portno.attr, &dev_attr_type.attr, &dev_attr_lancmd_timeout.attr, &dev_attr_recover.attr, NULL,};static struct attribute_group lcs_attr_group = { .attrs = lcs_attrs,};/** * lcs_probe_device is called on establishing a new ccwgroup_device. */static intlcs_probe_device(struct ccwgroup_device *ccwgdev){ struct lcs_card *card; int ret; if (!get_device(&ccwgdev->dev)) return -ENODEV; LCS_DBF_TEXT(2, setup, "add_dev"); card = lcs_alloc_card(); if (!card) { PRINT_ERR("Allocation of lcs card failed\n"); put_device(&ccwgdev->dev); return -ENOMEM; } ret = sysfs_create_group(&ccwgdev->dev.kobj, &lcs_attr_group); if (ret) { PRINT_ERR("Creating attributes failed"); lcs_free_card(card); put_device(&ccwgdev->dev); return ret; } ccwgdev->dev.driver_data = card; ccwgdev->cdev[0]->handler = lcs_irq; ccwgdev->cdev[1]->handler = lcs_irq; card->gdev = ccwgdev; INIT_WORK(&card->kernel_thread_starter, (void *) lcs_start_kernel_thread, card); card->thread_start_mask = 0; card->thread_allowed_mask = 0; card->thread_running_mask = 0; return 0;}static intlcs_register_netdev(struct ccwgroup_device *ccwgdev){ struct lcs_card *card; LCS_DBF_TEXT(2, setup, "regnetdv"); card = (struct lcs_card *)ccwgdev->dev.driver_data; if (card->dev->reg_state != NETREG_UNINITIALIZED) return 0; SET_NETDEV_DEV(card->dev, &ccwgdev->dev); return register_netdev(card->dev);}/** * lcs_new_device will be called by setting the group device online. */static intlcs_new_device(struct ccwgroup_device *ccwgdev){ struct lcs_card *card; struct net_device *dev=NULL; enum lcs_dev_states recover_state; int rc; card = (struct lcs_card *)ccwgdev->dev.driver_data; if (!card) return -ENODEV; LCS_DBF_TEXT(2, setup, "newdev"); LCS_DBF_HEX(3, setup, &card, sizeof(void*)); card->read.ccwdev = ccwgdev->cdev[0]; card->write.ccwdev = ccwgdev->cdev[1]; recover_state = card->state; ccw_device_set_online(card->read.ccwdev); ccw_device_set_online(card->write.ccwdev); LCS_DBF_TEXT(3, setup, "lcsnewdv"); lcs_setup_card(card); rc = lcs_detect(card); if (rc) { LCS_DBF_TEXT(2, setup, "dtctfail"); PRINT_WARN("Detection of LCS card failed with return code " "%d (0x%x)\n", rc, rc); lcs_stopcard(card); goto out; } if (card->dev) { LCS_DBF_TEXT(2, setup, "samedev"); LCS_DBF_HEX(3, setup, &card, sizeof(void*)); goto netdev_out; } switch (card->lan_type) {#ifdef CONFIG_NET_ETHERNET case LCS_FRAME_TYPE_ENET: card->lan_type_trans = eth_type_trans; dev = alloc_etherdev(0); break;#endif#ifdef CONFIG_TR case LCS_FRAME_TYPE_TR: card->lan_type_trans = tr_type_trans; dev = alloc_trdev(0); break;#endif#ifdef CONFIG_FDDI case LCS_FRAME_TYPE_FDDI: card->lan_type_trans = fddi_type_trans; dev = alloc_fddidev(0); break;#endif default: LCS_DBF_TEXT(3, setup, "errinit"); PRINT_ERR("LCS: Initialization failed\n"); PRINT_ERR("LCS: No device found!\n"); goto out; } if (!dev) goto out; card->dev = dev; card->dev->priv = card; card->dev->open = lcs_open_device; card->dev->stop = lcs_stop_device; card->dev->hard_start_xmit = lcs_start_xmit; card->dev->get_stats = lcs_getstats; SET_MODULE_OWNER(dev); memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH);#ifdef CONFIG_IP_MULTICAST if (!lcs_check_multicast_support(card)) card->dev->set_multicast_list = lcs_set_multicast_list;#endifnetdev_out: lcs_set_allowed_threads(card,0xffffffff); if (recover_state == DEV_STATE_RECOVER) { lcs_set_multicast_list(card->dev); card->dev->flags |= IFF_UP; netif_carrier_on(card->dev); netif_wake_queue(card->dev); card->state = DEV_STATE_UP; } else { lcs_stopcard(card); } if (lcs_register_netdev(ccwgdev) != 0) goto out; /* Print out supported assists: IPv6 */ PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name, (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ? "with" : "without"); /* Print out supported assist: Multicast */ PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name, (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ? "with" : "without"); return 0;out: ccw_device_set_offline(card->read.ccwdev); ccw_device_set_offline(card->write.ccwdev); return -ENODEV;}/** * lcs_shutdown_device, called when setting the group device offline. */static int__lcs_shutdown_device(struct ccwgroup_device *ccwgdev, int recovery_mode){ struct lcs_card *card; enum lcs_dev_states recover_state; int ret; LCS_DBF_TEXT(3, setup, "shtdndev"); card = (struct lcs_card *)ccwgdev->dev.driver_data; if (!card) return -ENODEV; if (recovery_mode == 0) { lcs_set_allowed_threads(card, 0); if (lcs_wait_for_threads(card, LCS_SET_MC_THREAD)) return -ERESTARTSYS; } LCS_DBF_HEX(3, setup, &card, sizeof(void*)); recover_state = card->state; ret = lcs_stop_device(card->dev); ret = ccw_device_set_offline(card->read.ccwdev); ret = ccw_device_set_offline(card->write.ccwdev); if (recover_state == DEV_STATE_UP) { card->state = DEV_STATE_RECOVER; } if (ret) return ret; return 0;}static intlcs_shutdown_device(struct ccwgroup_device *ccwgdev){ return __lcs_shutdown_device(ccwgdev, 0);}/** * drive lcs recovery after startup and startlan initiated by Lan Gateway */static intlcs_recovery(void *ptr){ struct lcs_card *card; struct ccwgroup_device *gdev; int rc; card = (struct lcs_card *) ptr; daemonize("lcs_recover"); LCS_DBF_TEXT(4, trace, "recover1"); if (!lcs_do_run_thread(card, LCS_RECOVERY_THREAD)) return 0; LCS_DBF_TEXT(4, trace, "recover2"); gdev = card->gdev; PRINT_WARN("Recovery of device %s started...\n", gdev->dev.bus_id); rc = __lcs_shutdown_device(gdev, 1); rc = lcs_new_device(gdev); if (!rc) PRINT_INFO("Device %s successfully recovered!\n", card->dev->name); else PRINT_INFO("Device %s could not be recovered!\n", card->dev->name); lcs_clear_thread_running_bit(card, LCS_RECOVERY_THREAD); return 0;}/** * lcs_remove_device, free buffers and card */static voidlcs_remove_device(struct ccwgroup_device *ccwgdev){ struct lcs_card *card; card = (struct lcs_card *)ccwgdev->dev.driver_data; if (!card) return; PRINT_INFO("Removing lcs group device ....\n"); LCS_DBF_TEXT(3, setup, "remdev"); LCS_DBF_HEX(3, setup, &card, sizeof(void*)); if (ccwgdev->state == CCWGROUP_ONLINE) { lcs_shutdown_device(ccwgdev); } if (card->dev) unregister_netdev(card->dev); sysfs_remove_group(&ccwgdev->dev.kobj, &lcs_attr_group); lcs_cleanup_card(card); lcs_free_card(card); put_device(&ccwgdev->dev);}/** * LCS ccwgroup driver registration */static struct ccwgroup_driver lcs_group_driver = { .owner = THIS_MODULE, .name = "lcs", .max_slaves = 2, .driver_id = 0xD3C3E2, .probe = lcs_probe_device, .remove = lcs_remove_device, .set_online = lcs_new_device, .set_offline = lcs_shutdown_device,};/** * LCS Module/Kernel initialization function */static int__init lcs_init_module(void){ int rc; PRINT_INFO("Loading %s\n",version); rc = lcs_register_debug_facility(); LCS_DBF_TEXT(0, setup, "lcsinit"); if (rc) { PRINT_ERR("Initialization failed\n"); return rc; } rc = register_cu3088_discipline(&lcs_group_driver); if (rc) { PRINT_ERR("Initialization failed\n"); return rc; } return 0;}/** * LCS module cleanup function */static void__exit lcs_cleanup_module(void){ PRINT_INFO("Terminating lcs module.\n"); LCS_DBF_TEXT(0, trace, "cleanup"); unregister_cu3088_discipline(&lcs_group_driver); lcs_unregister_debug_facility();}module_init(lcs_init_module);module_exit(lcs_cleanup_module);MODULE_AUTHOR("Frank Pavlic <fpavlic@de.ibm.com>");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -