📄 ueagle-atm.c
字号:
* Stop the modem : kill kernel thread and free data */static void uea_stop(struct uea_softc *sc){ int ret; uea_enters(INS_TO_USBDEV(sc)); ret = kthread_stop(sc->kthread); uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret); /* stop any pending boot process */ flush_scheduled_work(); uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL); usb_kill_urb(sc->urb_int); kfree(sc->urb_int->transfer_buffer); usb_free_urb(sc->urb_int); if (sc->dsp_firm) release_firmware(sc->dsp_firm); uea_leaves(INS_TO_USBDEV(sc));}/* syfs interface */static struct uea_softc *dev_to_uea(struct device *dev){ struct usb_interface *intf; struct usbatm_data *usbatm; intf = to_usb_interface(dev); if (!intf) return NULL; usbatm = usb_get_intfdata(intf); if (!usbatm) return NULL; return usbatm->driver_data;}static ssize_t read_status(struct device *dev, struct device_attribute *attr, char *buf){ int ret = -ENODEV; struct uea_softc *sc; mutex_lock(&uea_mutex); sc = dev_to_uea(dev); if (!sc) goto out; ret = snprintf(buf, 10, "%08x\n", sc->stats.phy.state);out: mutex_unlock(&uea_mutex); return ret;}static ssize_t reboot(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ int ret = -ENODEV; struct uea_softc *sc; mutex_lock(&uea_mutex); sc = dev_to_uea(dev); if (!sc) goto out; sc->reset = 1; ret = count;out: mutex_unlock(&uea_mutex); return ret;}static DEVICE_ATTR(stat_status, S_IWUGO | S_IRUGO, read_status, reboot);static ssize_t read_human_status(struct device *dev, struct device_attribute *attr, char *buf){ int ret = -ENODEV; struct uea_softc *sc; mutex_lock(&uea_mutex); sc = dev_to_uea(dev); if (!sc) goto out; switch (GET_STATUS(sc->stats.phy.state)) { case 0: ret = sprintf(buf, "Modem is booting\n"); break; case 1: ret = sprintf(buf, "Modem is initializing\n"); break; case 2: ret = sprintf(buf, "Modem is operational\n"); break; default: ret = sprintf(buf, "Modem synchronization failed\n"); break; }out: mutex_unlock(&uea_mutex); return ret;}static DEVICE_ATTR(stat_human_status, S_IWUGO | S_IRUGO, read_human_status, NULL);static ssize_t read_delin(struct device *dev, struct device_attribute *attr, char *buf){ int ret = -ENODEV; struct uea_softc *sc; mutex_lock(&uea_mutex); sc = dev_to_uea(dev); if (!sc) goto out; if (sc->stats.phy.flags & 0x0C00) ret = sprintf(buf, "ERROR\n"); else if (sc->stats.phy.flags & 0x0030) ret = sprintf(buf, "LOSS\n"); else ret = sprintf(buf, "GOOD\n");out: mutex_unlock(&uea_mutex); return ret;}static DEVICE_ATTR(stat_delin, S_IWUGO | S_IRUGO, read_delin, NULL);#define UEA_ATTR(name, reset) \ \static ssize_t read_##name(struct device *dev, \ struct device_attribute *attr, char *buf) \{ \ int ret = -ENODEV; \ struct uea_softc *sc; \ \ mutex_lock(&uea_mutex); \ sc = dev_to_uea(dev); \ if (!sc) \ goto out; \ ret = snprintf(buf, 10, "%08x\n", sc->stats.phy.name); \ if (reset) \ sc->stats.phy.name = 0; \out: \ mutex_unlock(&uea_mutex); \ return ret; \} \ \static DEVICE_ATTR(stat_##name, S_IRUGO, read_##name, NULL)UEA_ATTR(mflags, 1);UEA_ATTR(vidcpe, 0);UEA_ATTR(usrate, 0);UEA_ATTR(dsrate, 0);UEA_ATTR(usattenuation, 0);UEA_ATTR(dsattenuation, 0);UEA_ATTR(usmargin, 0);UEA_ATTR(dsmargin, 0);UEA_ATTR(txflow, 0);UEA_ATTR(rxflow, 0);UEA_ATTR(uscorr, 0);UEA_ATTR(dscorr, 0);UEA_ATTR(usunc, 0);UEA_ATTR(dsunc, 0);/* Retrieve the device End System Identifier (MAC) */#define htoi(x) (isdigit(x) ? x-'0' : toupper(x)-'A'+10)static int uea_getesi(struct uea_softc *sc, u_char * esi){ unsigned char mac_str[2 * ETH_ALEN + 1]; int i; if (usb_string (sc->usb_dev, sc->usb_dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) != 2 * ETH_ALEN) return 1; for (i = 0; i < ETH_ALEN; i++) esi[i] = htoi(mac_str[2 * i]) * 16 + htoi(mac_str[2 * i + 1]); return 0;}/* ATM stuff */static int uea_atm_open(struct usbatm_data *usbatm, struct atm_dev *atm_dev){ struct uea_softc *sc = usbatm->driver_data; return uea_getesi(sc, atm_dev->esi);}static int uea_heavy(struct usbatm_data *usbatm, struct usb_interface *intf){ struct uea_softc *sc = usbatm->driver_data; wait_event(sc->sync_q, IS_OPERATIONAL(sc)); return 0;}static int claim_interface(struct usb_device *usb_dev, struct usbatm_data *usbatm, int ifnum){ int ret; struct usb_interface *intf = usb_ifnum_to_if(usb_dev, ifnum); if (!intf) { uea_err(usb_dev, "interface %d not found\n", ifnum); return -ENODEV; } ret = usb_driver_claim_interface(&uea_driver, intf, usbatm); if (ret != 0) uea_err(usb_dev, "can't claim interface %d, error %d\n", ifnum, ret); return ret;}static void create_fs_entries(struct uea_softc *sc, struct usb_interface *intf){ /* sysfs interface */ device_create_file(&intf->dev, &dev_attr_stat_status); device_create_file(&intf->dev, &dev_attr_stat_mflags); device_create_file(&intf->dev, &dev_attr_stat_human_status); device_create_file(&intf->dev, &dev_attr_stat_delin); device_create_file(&intf->dev, &dev_attr_stat_vidcpe); device_create_file(&intf->dev, &dev_attr_stat_usrate); device_create_file(&intf->dev, &dev_attr_stat_dsrate); device_create_file(&intf->dev, &dev_attr_stat_usattenuation); device_create_file(&intf->dev, &dev_attr_stat_dsattenuation); device_create_file(&intf->dev, &dev_attr_stat_usmargin); device_create_file(&intf->dev, &dev_attr_stat_dsmargin); device_create_file(&intf->dev, &dev_attr_stat_txflow); device_create_file(&intf->dev, &dev_attr_stat_rxflow); device_create_file(&intf->dev, &dev_attr_stat_uscorr); device_create_file(&intf->dev, &dev_attr_stat_dscorr); device_create_file(&intf->dev, &dev_attr_stat_usunc); device_create_file(&intf->dev, &dev_attr_stat_dsunc);}static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, const struct usb_device_id *id){ struct usb_device *usb = interface_to_usbdev(intf); struct uea_softc *sc; int ret, ifnum = intf->altsetting->desc.bInterfaceNumber; uea_enters(usb); /* interface 0 is for firmware/monitoring */ if (ifnum != UEA_INTR_IFACE_NO) return -ENODEV; usbatm->flags = (sync_wait[modem_index] ? 0 : UDSL_SKIP_HEAVY_INIT); /* interface 1 is for outbound traffic */ ret = claim_interface(usb, usbatm, UEA_US_IFACE_NO); if (ret < 0) return ret; /* ADI930 has only 2 interfaces and inbound traffic is on interface 1 */ if (UEA_CHIP_VERSION(id) != ADI930) { /* interface 2 is for inbound traffic */ ret = claim_interface(usb, usbatm, UEA_DS_IFACE_NO); if (ret < 0) return ret; } sc = kzalloc(sizeof(struct uea_softc), GFP_KERNEL); if (!sc) { uea_err(usb, "uea_init: not enough memory !\n"); return -ENOMEM; } sc->usb_dev = usb; usbatm->driver_data = sc; sc->usbatm = usbatm; sc->modem_index = (modem_index < NB_MODEM) ? modem_index++ : 0; sc->driver_info = id->driver_info; /* ADI930 don't support iso */ if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) { int i; /* try set fastest alternate for inbound traffic interface */ for (i = FASTEST_ISO_INTF; i > 0; i--) if (usb_set_interface(usb, UEA_DS_IFACE_NO, i) == 0) break; if (i > 0) { uea_dbg(usb, "set alternate %d for 2 interface\n", i); uea_info(usb, "using iso mode\n"); usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ; } else { uea_err(usb, "setting any alternate failed for " "2 interface, using bulk mode\n"); } } ret = uea_boot(sc); if (ret < 0) { kfree(sc); return ret; } create_fs_entries(sc, intf); return 0;}static void destroy_fs_entries(struct uea_softc *sc, struct usb_interface *intf){ /* sysfs interface */ device_remove_file(&intf->dev, &dev_attr_stat_status); device_remove_file(&intf->dev, &dev_attr_stat_mflags); device_remove_file(&intf->dev, &dev_attr_stat_human_status); device_remove_file(&intf->dev, &dev_attr_stat_delin); device_remove_file(&intf->dev, &dev_attr_stat_vidcpe); device_remove_file(&intf->dev, &dev_attr_stat_usrate); device_remove_file(&intf->dev, &dev_attr_stat_dsrate); device_remove_file(&intf->dev, &dev_attr_stat_usattenuation); device_remove_file(&intf->dev, &dev_attr_stat_dsattenuation); device_remove_file(&intf->dev, &dev_attr_stat_usmargin); device_remove_file(&intf->dev, &dev_attr_stat_dsmargin); device_remove_file(&intf->dev, &dev_attr_stat_txflow); device_remove_file(&intf->dev, &dev_attr_stat_rxflow); device_remove_file(&intf->dev, &dev_attr_stat_uscorr); device_remove_file(&intf->dev, &dev_attr_stat_dscorr); device_remove_file(&intf->dev, &dev_attr_stat_usunc); device_remove_file(&intf->dev, &dev_attr_stat_dsunc);}static void uea_unbind(struct usbatm_data *usbatm, struct usb_interface *intf){ struct uea_softc *sc = usbatm->driver_data; destroy_fs_entries(sc, intf); uea_stop(sc); kfree(sc);}static struct usbatm_driver uea_usbatm_driver = { .driver_name = "ueagle-atm", .bind = uea_bind, .atm_start = uea_atm_open, .unbind = uea_unbind, .heavy_init = uea_heavy, .bulk_in = UEA_BULK_DATA_PIPE, .bulk_out = UEA_BULK_DATA_PIPE, .isoc_in = UEA_ISO_DATA_PIPE,};static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id){ struct usb_device *usb = interface_to_usbdev(intf); uea_enters(usb); uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s\n", le16_to_cpu(usb->descriptor.idVendor), le16_to_cpu(usb->descriptor.idProduct), chip_name[UEA_CHIP_VERSION(id)]); usb_reset_device(usb); if (UEA_IS_PREFIRM(id)) return uea_load_firmware(usb, UEA_CHIP_VERSION(id)); return usbatm_usb_probe(intf, id, &uea_usbatm_driver);}static void uea_disconnect(struct usb_interface *intf){ struct usb_device *usb = interface_to_usbdev(intf); int ifnum = intf->altsetting->desc.bInterfaceNumber; uea_enters(usb); /* ADI930 has 2 interfaces and eagle 3 interfaces. * Pre-firmware device has one interface */ if (usb->config->desc.bNumInterfaces != 1 && ifnum == 0) { mutex_lock(&uea_mutex); usbatm_usb_disconnect(intf); mutex_unlock(&uea_mutex); uea_info(usb, "ADSL device removed\n"); } uea_leaves(usb);}/* * List of supported VID/PID */static const struct usb_device_id uea_ids[] = { {USB_DEVICE(ELSA_VID, ELSA_PID_PREFIRM), .driver_info = ADI930 | PREFIRM}, {USB_DEVICE(ELSA_VID, ELSA_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM}, {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM}, {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM}, {USB_DEVICE(USR_VID, MILLER_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, {USB_DEVICE(USR_VID, MILLER_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM}, {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM}, {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM}, {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM}, {}};/* * USB driver descriptor */static struct usb_driver uea_driver = { .name = "ueagle-atm", .id_table = uea_ids, .probe = uea_probe, .disconnect = uea_disconnect,};MODULE_DEVICE_TABLE(usb, uea_ids);/** * uea_init - Initialize the module. * Register to USB subsystem */static int __init uea_init(void){ printk(KERN_INFO "[ueagle-atm] driver " EAGLEUSBVERSION " loaded\n"); usb_register(&uea_driver); return 0;}module_init(uea_init);/** * uea_exit - Destroy module * Deregister with USB subsystem */static void __exit uea_exit(void){ /* * This calls automatically the uea_disconnect method if necessary: */ usb_deregister(&uea_driver); printk(KERN_INFO "[ueagle-atm] driver unloaded\n");}module_exit(uea_exit);MODULE_AUTHOR("Damien Bergamini/Matthieu Castet/Stanislaw W. Gruszka");MODULE_DESCRIPTION("ADI 930/Eagle USB ADSL Modem driver");MODULE_LICENSE("Dual BSD/GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -