| TODO: |
| - Rx block size is limited to < 2048, hardware bug? |
| - Group size is limited to < page size, kernel alloc/mmap API issues |
| - test whether Tx is transmitting data from provided buffers |
| - handle device unplug case |
| - handle temperature above threshold |
| - use bus address instead of physical address for DMA |
| - support for snapshot mode |
| - audit userspace interfaces |
| - get reserved major/minor if needed |
| |
| Sample Code: |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/mman.h> |
| #include <sys/ioctl.h> |
| #include <poll.h> |
| #include <stdio.h> |
| #include <error.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <stdint.h> |
| |
| #include <sysfs/libsysfs.h> |
| |
| #include <poch.h> |
| |
| struct pconsume { |
| uint32_t * offsets; |
| uint32_t nfetch; |
| uint32_t nflush; |
| }; |
| |
| uint32_t offsets[10]; |
| |
| void process_group(unsigned char *buf, uint32_t size) |
| { |
| uint16_t *buf16 = (uint16_t *)buf; |
| |
| printf("RX: %p %u %04x %04x %04x %04x %04x %04x\n", buf, size, |
| buf16[0], buf16[1], buf16[2], buf16[3], buf16[4], buf16[5]); |
| } |
| |
| int main() |
| { |
| struct sysfs_attribute *attr; |
| char *path; |
| int ret; |
| unsigned long mmap_size; |
| int fd; |
| unsigned char *cbuf; |
| |
| uint32_t nflush; |
| struct pollfd poll_fds; |
| int count = 0; |
| int i; |
| |
| path = "/sys/class/pocketchange/poch0/ch0/block_size"; |
| attr = sysfs_open_attribute(path); |
| ret = sysfs_write_attribute(attr, "256", strlen("256")); |
| if (ret == -1) |
| error(1, errno, "error writing attribute %s", path); |
| sysfs_close_attribute(attr); |
| |
| path = "/sys/class/pocketchange/poch0/ch0/group_size"; |
| attr = sysfs_open_attribute(path); |
| ret = sysfs_write_attribute(attr, "4096", strlen("4096")); |
| if (ret == -1) |
| error(1, errno, "error writing attribute %s", path); |
| sysfs_close_attribute(attr); |
| |
| path = "/sys/class/pocketchange/poch0/ch0/group_count"; |
| attr = sysfs_open_attribute(path); |
| ret = sysfs_write_attribute(attr, "64", strlen("64")); |
| if (ret == -1) |
| error(1, errno, "error writing attribute %s", path); |
| sysfs_close_attribute(attr); |
| |
| fd = open("/dev/ch0", O_RDWR); |
| if (fd == -1) |
| error(1, errno, "error opening device node"); |
| |
| path = "/sys/class/pocketchange/poch0/ch0/mmap_size"; |
| attr = sysfs_open_attribute(path); |
| ret = sysfs_read_attribute(attr); |
| if (ret == -1) |
| error(1, errno, "error reading attribute %s", path); |
| printf("%s", attr->value); |
| sscanf(attr->value, "%lu", &mmap_size); |
| sysfs_close_attribute(attr); |
| |
| cbuf = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, |
| MAP_PRIVATE, fd, 0); |
| if (cbuf == MAP_FAILED) |
| error(1, errno, "error mapping DMA buffers"); |
| |
| ret = ioctl(fd, POCH_IOC_TRANSFER_START, 0); |
| if (ret == -1) |
| error(1, errno, "error starting transfer"); |
| |
| nflush = 0; |
| while (1) { |
| struct pconsume consume; |
| |
| consume.offsets = offsets; |
| consume.nfetch = 10; |
| consume.nflush = nflush; |
| |
| ret = ioctl(fd, POCH_IOC_CONSUME, &consume); |
| if (ret == -1) |
| error(1, errno, "error consuming groups"); |
| |
| nflush = consume.nfetch; |
| |
| for (i = 0; i < nflush; i++) { |
| process_group(cbuf + consume.offsets[i], 4096); |
| |
| count++; |
| if (count == 1000) |
| break; |
| } |
| |
| if (count == 1000) |
| break; |
| } |
| |
| ret = ioctl(fd, POCH_IOC_TRANSFER_STOP, 0); |
| if (ret == -1) |
| error(1, errno, "error starting transfer"); |
| |
| return 0; |
| } |
| |
| Please send patches to Greg Kroah-Hartman <greg@kroah.com> and |
| Vijay Kumar <vijaykumar@bravegnu.org> and Jaya Kumar <jayakumar.lkml@gmail.com> |