📄 ftdi-elan.c
字号:
return 0;}#define FTDI_ELAN_IOC_MAGIC 0xA1#define FTDI_ELAN_IOCDEBUG _IOC(_IOC_WRITE, FTDI_ELAN_IOC_MAGIC, 1, 132)static int ftdi_elan_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ switch (cmd) { case FTDI_ELAN_IOCDEBUG:{ char line[132]; int size = strncpy_from_user(line, (const char __user *)arg, sizeof(line)); if (size < 0) { return -EINVAL; } else { printk(KERN_ERR "TODO: ioctl %s\n", line); return 0; } } default: return -EFAULT; }}/*** blocking bulk reads are used to get data from the device**/static ssize_t ftdi_elan_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos){ char data[30 *3 + 4]; char *d = data; int m = (sizeof(data) - 1) / 3; int bytes_read = 0; int retry_on_empty = 10; int retry_on_timeout = 5; struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data; if (ftdi->disconnected > 0) { return -ENODEV; } data[0] = 0; have:if (ftdi->bulk_in_left > 0) { if (count-- > 0) { char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer; ftdi->bulk_in_left -= 1; if (bytes_read < m) { d += sprintf(d, " %02X", 0x000000FF & *p); } else if (bytes_read > m) { } else d += sprintf(d, " .."); if (copy_to_user(buffer++, p, 1)) { return -EFAULT; } else { bytes_read += 1; goto have; } } else return bytes_read; } more:if (count > 0) { int packet_bytes = 0; int retval = usb_bulk_msg(ftdi->udev, usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), ftdi->bulk_in_buffer, ftdi->bulk_in_size, &packet_bytes, msecs_to_jiffies(50)); if (packet_bytes > 2) { ftdi->bulk_in_left = packet_bytes - 2; ftdi->bulk_in_last = 1; goto have; } else if (retval == -ETIMEDOUT) { if (retry_on_timeout-- > 0) { goto more; } else if (bytes_read > 0) { return bytes_read; } else return retval; } else if (retval == 0) { if (retry_on_empty-- > 0) { goto more; } else return bytes_read; } else return retval; } else return bytes_read;}static void ftdi_elan_write_bulk_callback(struct urb *urb){ struct usb_ftdi *ftdi = (struct usb_ftdi *)urb->context; int status = urb->status; if (status && !(status == -ENOENT || status == -ECONNRESET || status == -ESHUTDOWN)) { dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %" "d\n", urb, status); } usb_buffer_free(urb->dev, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma);}static int fill_buffer_with_all_queued_commands(struct usb_ftdi *ftdi, char *buf, int command_size, int total_size){ int ed_commands = 0; int b = 0; int I = command_size; int i = ftdi->command_head; while (I-- > 0) { struct u132_command *command = &ftdi->command[COMMAND_MASK & i++]; int F = command->follows; u8 *f = command->buffer; if (command->header & 0x80) { ed_commands |= 1 << (0x3 & (command->header >> 5)); } buf[b++] = command->header; buf[b++] = (command->length >> 0) & 0x00FF; buf[b++] = (command->length >> 8) & 0x00FF; buf[b++] = command->address; buf[b++] = command->width; while (F-- > 0) { buf[b++] = *f++; } } return ed_commands;}static int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size){ int total_size = 0; int I = command_size; int i = ftdi->command_head; while (I-- > 0) { struct u132_command *command = &ftdi->command[COMMAND_MASK & i++]; total_size += 5 + command->follows; } return total_size;}static int ftdi_elan_command_engine(struct usb_ftdi *ftdi){ int retval; char *buf; int ed_commands; int total_size; struct urb *urb; int command_size = ftdi->command_next - ftdi->command_head; if (command_size == 0) return 0; total_size = ftdi_elan_total_command_size(ftdi, command_size); urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { dev_err(&ftdi->udev->dev, "could not get a urb to write %d comm" "ands totaling %d bytes to the Uxxx\n", command_size, total_size); return -ENOMEM; } buf = usb_buffer_alloc(ftdi->udev, total_size, GFP_KERNEL, &urb->transfer_dma); if (!buf) { dev_err(&ftdi->udev->dev, "could not get a buffer to write %d c" "ommands totaling %d bytes to the Uxxx\n", command_size, total_size); usb_free_urb(urb); return -ENOMEM; } ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf, command_size, total_size); usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, ftdi->bulk_out_endpointAddr), buf, total_size, ftdi_elan_write_bulk_callback, ftdi); urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; if (ed_commands) { char diag[40 *3 + 4]; char *d = diag; int m = total_size; u8 *c = buf; int s = (sizeof(diag) - 1) / 3; diag[0] = 0; while (s-- > 0 && m-- > 0) { if (s > 0 || m == 0) { d += sprintf(d, " %02X", *c++); } else d += sprintf(d, " .."); } } retval = usb_submit_urb(urb, GFP_KERNEL); if (retval) { dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write " "%d commands totaling %d bytes to the Uxxx\n", retval, urb, command_size, total_size); usb_buffer_free(ftdi->udev, total_size, buf, urb->transfer_dma); usb_free_urb(urb); return retval; } usb_free_urb(urb); /* release our reference to this urb, the USB core will eventually free it entirely */ ftdi->command_head += command_size; ftdi_elan_kick_respond_queue(ftdi); return 0;}static void ftdi_elan_do_callback(struct usb_ftdi *ftdi, struct u132_target *target, u8 *buffer, int length){ struct urb *urb = target->urb; int halted = target->halted; int skipped = target->skipped; int actual = target->actual; int non_null = target->non_null; int toggle_bits = target->toggle_bits; int error_count = target->error_count; int condition_code = target->condition_code; int repeat_number = target->repeat_number; void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int, int, int, int, int) = target->callback; target->active -= 1; target->callback = NULL; (*callback) (target->endp, urb, buffer, length, toggle_bits, error_count, condition_code, repeat_number, halted, skipped, actual, non_null);}static char *have_ed_set_response(struct usb_ftdi *ftdi, struct u132_target *target, u16 ed_length, int ed_number, int ed_type, char *b){ int payload = (ed_length >> 0) & 0x07FF; mutex_lock(&ftdi->u132_lock); target->actual = 0; target->non_null = (ed_length >> 15) & 0x0001; target->repeat_number = (ed_length >> 11) & 0x000F; if (ed_type == 0x02) { if (payload == 0 || target->abandoning > 0) { target->abandoning = 0; mutex_unlock(&ftdi->u132_lock); ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, payload); ftdi->recieved = 0; ftdi->expected = 4; ftdi->ed_found = 0; return ftdi->response; } else { ftdi->expected = 4 + payload; ftdi->ed_found = 1; mutex_unlock(&ftdi->u132_lock); return b; } } else if (ed_type == 0x03) { if (payload == 0 || target->abandoning > 0) { target->abandoning = 0; mutex_unlock(&ftdi->u132_lock); ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, payload); ftdi->recieved = 0; ftdi->expected = 4; ftdi->ed_found = 0; return ftdi->response; } else { ftdi->expected = 4 + payload; ftdi->ed_found = 1; mutex_unlock(&ftdi->u132_lock); return b; } } else if (ed_type == 0x01) { target->abandoning = 0; mutex_unlock(&ftdi->u132_lock); ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, payload); ftdi->recieved = 0; ftdi->expected = 4; ftdi->ed_found = 0; return ftdi->response; } else { target->abandoning = 0; mutex_unlock(&ftdi->u132_lock); ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, payload); ftdi->recieved = 0; ftdi->expected = 4; ftdi->ed_found = 0; return ftdi->response; }}static char *have_ed_get_response(struct usb_ftdi *ftdi, struct u132_target *target, u16 ed_length, int ed_number, int ed_type, char *b){ mutex_lock(&ftdi->u132_lock); target->condition_code = TD_DEVNOTRESP; target->actual = (ed_length >> 0) & 0x01FF; target->non_null = (ed_length >> 15) & 0x0001; target->repeat_number = (ed_length >> 11) & 0x000F; mutex_unlock(&ftdi->u132_lock); if (target->active) ftdi_elan_do_callback(ftdi, target, NULL, 0); target->abandoning = 0; ftdi->recieved = 0; ftdi->expected = 4; ftdi->ed_found = 0; return ftdi->response;}/** The engine tries to empty the FTDI fifo** all responses found in the fifo data are dispatched thus* the response buffer can only ever hold a maximum sized* response from the Uxxx.**/static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi){ u8 *b = ftdi->response + ftdi->recieved; int bytes_read = 0; int retry_on_empty = 1; int retry_on_timeout = 3; int empty_packets = 0; read:{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -