📄 ueagle-atm.c
字号:
struct intr_pkt *intr; uea_enters(INS_TO_USBDEV(sc)); if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { size = E4_INTR_PKT_SIZE; sc->dispatch_cmv = uea_dispatch_cmv_e4; sc->schedule_load_page = uea_schedule_load_page_e4; sc->stat = uea_stat_e4; sc->send_cmvs = uea_send_cmvs_e4; INIT_WORK(&sc->task, uea_load_page_e4); } else { size = E1_INTR_PKT_SIZE; sc->dispatch_cmv = uea_dispatch_cmv_e1; sc->schedule_load_page = uea_schedule_load_page_e1; sc->stat = uea_stat_e1; sc->send_cmvs = uea_send_cmvs_e1; INIT_WORK(&sc->task, uea_load_page_e1); } init_waitqueue_head(&sc->sync_q); sc->work_q = create_workqueue("ueagle-dsp"); if (!sc->work_q) { uea_err(INS_TO_USBDEV(sc), "cannot allocate workqueue\n"); uea_leaves(INS_TO_USBDEV(sc)); return -ENOMEM; } if (UEA_CHIP_VERSION(sc) == ADI930) load_XILINX_firmware(sc); intr = kmalloc(size, GFP_KERNEL); if (!intr) { uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt package\n"); goto err0; } sc->urb_int = usb_alloc_urb(0, GFP_KERNEL); if (!sc->urb_int) { uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n"); goto err1; } usb_fill_int_urb(sc->urb_int, sc->usb_dev, usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE), intr, size, uea_intr, sc, sc->usb_dev->actconfig->interface[0]->altsetting[0]. endpoint[0].desc.bInterval); ret = usb_submit_urb(sc->urb_int, GFP_KERNEL); if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "urb submition failed with error %d\n", ret); goto err1; } sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm"); if (sc->kthread == ERR_PTR(-ENOMEM)) { uea_err(INS_TO_USBDEV(sc), "failed to create thread\n"); goto err2; } uea_leaves(INS_TO_USBDEV(sc)); return 0;err2: usb_kill_urb(sc->urb_int);err1: usb_free_urb(sc->urb_int); sc->urb_int = NULL; kfree(intr);err0: destroy_workqueue(sc->work_q); uea_leaves(INS_TO_USBDEV(sc)); return -ENOMEM;}/* * 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); 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); /* stop any pending boot process, when no one can schedule work */ destroy_workqueue(sc->work_q); 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; int modem_state; struct uea_softc *sc; mutex_lock(&uea_mutex); sc = dev_to_uea(dev); if (!sc) goto out; if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { switch (sc->stats.phy.state) { case 0x0: /* not yet synchronized */ case 0x1: case 0x3: case 0x4: modem_state = 0; break; case 0x5: /* initialization */ case 0x6: case 0x9: case 0xa: modem_state = 1; break; case 0x7: /* operational */ modem_state = 2; break; case 0x2: /* fail ... */ modem_state = 3; break; default: /* unknown */ modem_state = 4; break; } } else modem_state = GET_STATUS(sc->stats.phy.state); switch (modem_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; case 3: ret = sprintf(buf, "Modem synchronization failed\n"); break; default: ret = sprintf(buf, "Modem state is unknown\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; char *delin = "GOOD"; mutex_lock(&uea_mutex); sc = dev_to_uea(dev); if (!sc) goto out; if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { if (sc->stats.phy.flags & 0x4000) delin = "RESET"; else if (sc->stats.phy.flags & 0x0001) delin = "LOSS"; } else { if (sc->stats.phy.flags & 0x0C00) delin = "ERROR"; else if (sc->stats.phy.flags & 0x0030) delin = "LOSS"; } ret = sprintf(buf, "%s\n", delin);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);UEA_ATTR(firmid, 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_interruptible(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 struct attribute *attrs[] = { &dev_attr_stat_status.attr, &dev_attr_stat_mflags.attr, &dev_attr_stat_human_status.attr, &dev_attr_stat_delin.attr, &dev_attr_stat_vidcpe.attr, &dev_attr_stat_usrate.attr, &dev_attr_stat_dsrate.attr, &dev_attr_stat_usattenuation.attr, &dev_attr_stat_dsattenuation.attr, &dev_attr_stat_usmargin.attr, &dev_attr_stat_dsmargin.attr, &dev_attr_stat_txflow.attr, &dev_attr_stat_rxflow.attr, &dev_attr_stat_uscorr.attr, &dev_attr_stat_dscorr.attr, &dev_attr_stat_usunc.attr, &dev_attr_stat_dsunc.attr, &dev_attr_stat_firmid.attr, NULL,};static struct attribute_group attr_grp = { .attrs = attrs,};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; unsigned int alt; 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; /* first try to use module parameter */ if (annex[sc->modem_index] == 1) sc->annex = ANNEXA; else if (annex[sc->modem_index] == 2) sc->annex = ANNEXB; /* try to autodetect annex */ else if (sc->driver_info & AUTO_ANNEX_A) sc->annex = ANNEXA; else if (sc->driver_info & AUTO_ANNEX_B) sc->annex = ANNEXB; else sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA; alt = altsetting[sc->modem_index]; /* ADI930 don't support iso */ if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) { if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) { uea_dbg(usb, "set alternate %u for 2 interface\n", alt); uea_info(usb, "using iso mode\n"); usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ; } else { uea_err(usb, "setting alternate %u failed for " "2 interface, using bulk mode\n", alt); } } ret = sysfs_create_group(&intf->dev.kobj, &attr_grp); if (ret < 0) goto error; ret = uea_boot(sc); if (ret < 0) goto error_rm_grp; return 0;error_rm_grp: sysfs_remove_group(&intf->dev.kobj, &attr_grp);error: kfree(sc); return ret;}static void uea_unbind(struct usbatm_data *usbatm, struct usb_interface *intf){ struct uea_softc *sc = usbatm->driver_data; sysfs_remove_group(&intf->dev.kobj, &attr_grp); 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) Rev (%#X): %s\n", le16_to_cpu(usb->descriptor.idVendor), le16_to_cpu(usb->descriptor.idProduct), le16_to_cpu(usb->descriptor.bcdDevice), 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(ANALOG_VID, ADI930_PID_PREFIRM), .driver_info = ADI930 | PREFIRM}, {USB_DEVICE(ANALOG_VID, ADI930_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM}, {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM}, {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM}, {USB_D
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -