📄 ftdi-elan.c
字号:
return result;}static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi){ mutex_lock(&ftdi->u132_lock); while (ftdi->respond_next > ftdi->respond_head) { struct u132_respond *respond = &ftdi->respond[RESPOND_MASK & ftdi->respond_head++]; *respond->result = -ESHUTDOWN; *respond->value = 0; complete(&respond->wait_completion); } mutex_unlock(&ftdi->u132_lock);}static void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi){ int ed_number = 4; mutex_lock(&ftdi->u132_lock); while (ed_number-- > 0) { struct u132_target *target = &ftdi->target[ed_number]; if (target->active == 1) { target->condition_code = TD_DEVNOTRESP; mutex_unlock(&ftdi->u132_lock); ftdi_elan_do_callback(ftdi, target, NULL, 0); mutex_lock(&ftdi->u132_lock); } } ftdi->recieved = 0; ftdi->expected = 4; ftdi->ed_found = 0; mutex_unlock(&ftdi->u132_lock);}static void ftdi_elan_flush_targets(struct usb_ftdi *ftdi){ int ed_number = 4; mutex_lock(&ftdi->u132_lock); while (ed_number-- > 0) { struct u132_target *target = &ftdi->target[ed_number]; target->abandoning = 1; wait_1:if (target->active == 1) { int command_size = ftdi->command_next - ftdi->command_head; if (command_size < COMMAND_SIZE) { struct u132_command *command = &ftdi->command[ COMMAND_MASK & ftdi->command_next]; command->header = 0x80 | (ed_number << 5) | 0x4; command->length = 0x00; command->address = 0x00; command->width = 0x00; command->follows = 0; command->value = 0; command->buffer = &command->value; ftdi->command_next += 1; ftdi_elan_kick_command_queue(ftdi); } else { mutex_unlock(&ftdi->u132_lock); msleep(100); mutex_lock(&ftdi->u132_lock); goto wait_1; } } wait_2:if (target->active == 1) { int command_size = ftdi->command_next - ftdi->command_head; if (command_size < COMMAND_SIZE) { struct u132_command *command = &ftdi->command[ COMMAND_MASK & ftdi->command_next]; command->header = 0x90 | (ed_number << 5); command->length = 0x00; command->address = 0x00; command->width = 0x00; command->follows = 0; command->value = 0; command->buffer = &command->value; ftdi->command_next += 1; ftdi_elan_kick_command_queue(ftdi); } else { mutex_unlock(&ftdi->u132_lock); msleep(100); mutex_lock(&ftdi->u132_lock); goto wait_2; } } } ftdi->recieved = 0; ftdi->expected = 4; ftdi->ed_found = 0; mutex_unlock(&ftdi->u132_lock);}static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi){ int ed_number = 4; mutex_lock(&ftdi->u132_lock); while (ed_number-- > 0) { struct u132_target *target = &ftdi->target[ed_number]; target->abandoning = 1; wait:if (target->active == 1) { int command_size = ftdi->command_next - ftdi->command_head; if (command_size < COMMAND_SIZE) { struct u132_command *command = &ftdi->command[ COMMAND_MASK & ftdi->command_next]; command->header = 0x80 | (ed_number << 5) | 0x4; command->length = 0x00; command->address = 0x00; command->width = 0x00; command->follows = 0; command->value = 0; command->buffer = &command->value; ftdi->command_next += 1; ftdi_elan_kick_command_queue(ftdi); } else { mutex_unlock(&ftdi->u132_lock); msleep(100); mutex_lock(&ftdi->u132_lock); goto wait; } } } ftdi->recieved = 0; ftdi->expected = 4; ftdi->ed_found = 0; mutex_unlock(&ftdi->u132_lock);}static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi){ ftdi_command_queue_work(ftdi, 0); return;}static void ftdi_elan_command_work(struct work_struct *work){ struct usb_ftdi *ftdi = container_of(work, struct usb_ftdi, command_work.work); if (ftdi->disconnected > 0) { ftdi_elan_put_kref(ftdi); return; } else { int retval = ftdi_elan_command_engine(ftdi); if (retval == -ESHUTDOWN) { ftdi->disconnected += 1; } else if (retval == -ENODEV) { ftdi->disconnected += 1; } else if (retval) dev_err(&ftdi->udev->dev, "command error %d\n", retval); ftdi_command_requeue_work(ftdi, msecs_to_jiffies(10)); return; }}static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi){ ftdi_respond_queue_work(ftdi, 0); return;}static void ftdi_elan_respond_work(struct work_struct *work){ struct usb_ftdi *ftdi = container_of(work, struct usb_ftdi, respond_work.work); if (ftdi->disconnected > 0) { ftdi_elan_put_kref(ftdi); return; } else { int retval = ftdi_elan_respond_engine(ftdi); if (retval == 0) { } else if (retval == -ESHUTDOWN) { ftdi->disconnected += 1; } else if (retval == -ENODEV) { ftdi->disconnected += 1; } else if (retval == -EILSEQ) { ftdi->disconnected += 1; } else { ftdi->disconnected += 1; dev_err(&ftdi->udev->dev, "respond error %d\n", retval); } if (ftdi->disconnected > 0) { ftdi_elan_abandon_completions(ftdi); ftdi_elan_abandon_targets(ftdi); } ftdi_response_requeue_work(ftdi, msecs_to_jiffies(10)); return; }}/** the sw_lock is initially held and will be freed* after the FTDI has been synchronized**/static void ftdi_elan_status_work(struct work_struct *work){ struct usb_ftdi *ftdi = container_of(work, struct usb_ftdi, status_work.work); int work_delay_in_msec = 0; if (ftdi->disconnected > 0) { ftdi_elan_put_kref(ftdi); return; } else if (ftdi->synchronized == 0) { down(&ftdi->sw_lock); if (ftdi_elan_synchronize(ftdi) == 0) { ftdi->synchronized = 1; ftdi_command_queue_work(ftdi, 1); ftdi_respond_queue_work(ftdi, 1); up(&ftdi->sw_lock); work_delay_in_msec = 100; } else { dev_err(&ftdi->udev->dev, "synchronize failed\n"); up(&ftdi->sw_lock); work_delay_in_msec = 10 *1000; } } else if (ftdi->stuck_status > 0) { if (ftdi_elan_stuck_waiting(ftdi) == 0) { ftdi->stuck_status = 0; ftdi->synchronized = 0; } else if ((ftdi->stuck_status++ % 60) == 1) { dev_err(&ftdi->udev->dev, "WRONG type of card inserted " "- please remove\n"); } else dev_err(&ftdi->udev->dev, "WRONG type of card inserted " "- checked %d times\n", ftdi->stuck_status); work_delay_in_msec = 100; } else if (ftdi->enumerated == 0) { if (ftdi_elan_enumeratePCI(ftdi) == 0) { ftdi->enumerated = 1; work_delay_in_msec = 250; } else work_delay_in_msec = 1000; } else if (ftdi->initialized == 0) { if (ftdi_elan_setupOHCI(ftdi) == 0) { ftdi->initialized = 1; work_delay_in_msec = 500; } else { dev_err(&ftdi->udev->dev, "initialized failed - trying " "again in 10 seconds\n"); work_delay_in_msec = 1 *1000; } } else if (ftdi->registered == 0) { work_delay_in_msec = 10; if (ftdi_elan_hcd_init(ftdi) == 0) { ftdi->registered = 1; } else dev_err(&ftdi->udev->dev, "register failed\n"); work_delay_in_msec = 250; } else { if (ftdi_elan_checkingPCI(ftdi) == 0) { work_delay_in_msec = 250; } else if (ftdi->controlreg & 0x00400000) { if (ftdi->gone_away > 0) { dev_err(&ftdi->udev->dev, "PCI device eject con" "firmed platform_dev.dev.parent=%p plat" "form_dev.dev=%p\n", ftdi->platform_dev.dev.parent, &ftdi->platform_dev.dev); platform_device_unregister(&ftdi->platform_dev); ftdi->platform_dev.dev.parent = NULL; ftdi->registered = 0; ftdi->enumerated = 0; ftdi->card_ejected = 0; ftdi->initialized = 0; ftdi->gone_away = 0; } else ftdi_elan_flush_targets(ftdi); work_delay_in_msec = 250; } else { dev_err(&ftdi->udev->dev, "PCI device has disappeared\n" ); ftdi_elan_cancel_targets(ftdi); work_delay_in_msec = 500; ftdi->enumerated = 0; ftdi->initialized = 0; } } if (ftdi->disconnected > 0) { ftdi_elan_put_kref(ftdi); return; } else { ftdi_status_requeue_work(ftdi, msecs_to_jiffies(work_delay_in_msec)); return; }}/** file_operations for the jtag interface** the usage count for the device is incremented on open()* and decremented on release()*/static int ftdi_elan_open(struct inode *inode, struct file *file){ int subminor = iminor(inode); struct usb_interface *interface = usb_find_interface(&ftdi_elan_driver, subminor); if (!interface) { printk(KERN_ERR "can't find device for minor %d\n", subminor); return -ENODEV; } else { struct usb_ftdi *ftdi = usb_get_intfdata(interface); if (!ftdi) { return -ENODEV; } else { if (down_interruptible(&ftdi->sw_lock)) { return -EINTR; } else { ftdi_elan_get_kref(ftdi); file->private_data = ftdi; return 0; } } }}static int ftdi_elan_release(struct inode *inode, struct file *file){ struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data; if (ftdi == NULL) return -ENODEV; up(&ftdi->sw_lock); /* decrement the count on our device */ ftdi_elan_put_kref(ftdi);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -