├── src ├── dnw │ ├── Makefile │ ├── dnw.c │ └── dnw2.c └── driver │ ├── Makefile │ └── secbulk.c ├── 51-dnw.rules ├── Makefile └── README /src/dnw/Makefile: -------------------------------------------------------------------------------- 1 | all:dnw2 dnw 2 | dnw2 : dnw2.c 3 | gcc -g -o $@ $^ -lusb 4 | dnw : dnw.c 5 | gcc -g -o $@ $^ 6 | 7 | clean : 8 | rm -rf dnw dnw2 *.o 9 | 10 | install : dnw dnw2 11 | cp $^ /usr/bin 12 | -------------------------------------------------------------------------------- /51-dnw.rules: -------------------------------------------------------------------------------- 1 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="5345", ATTRS{idProduct}=="1234", MODE="0666", RUN+="/sbin/modprobe secbulk" 2 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="04e8", ATTRS{idProduct}=="1234", MODE="0666", RUN+="/sbin/modprobe secbulk" 3 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="067b", MODE="0666", RUN+="/sbin/modprobe usbserial" 4 | -------------------------------------------------------------------------------- /src/driver/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := secbulk.o 2 | secbulk-m := secbulk.o 3 | 4 | BASEDIR := /lib/modules/$(shell uname -r) 5 | KERNELDIR ?= $(BASEDIR)/build 6 | PWD :=$(shell pwd) 7 | 8 | .PHONY: all 9 | all: clean modules 10 | 11 | .PHONY:modules 12 | modules: 13 | $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules 14 | 15 | .PHONY:clean 16 | clean: 17 | $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) clean 18 | 19 | .PHONY:install 20 | install: 21 | $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) INSTALL_MOD_DIR=$(RTKDIR) modules_install 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # author: Du, Changbin 2 | 3 | driver_src = `pwd`/src/driver 4 | dnw_src = src/dnw 5 | 6 | all: driver dnw 7 | 8 | driver: 9 | make -C /lib/modules/`uname -r`/build M=$(driver_src) modules 10 | 11 | dnw: 12 | make -C $(dnw_src) 13 | 14 | install: all 15 | make -C $(dnw_src) install 16 | make -C /lib/modules/`uname -r`/build M=$(driver_src) modules_install 17 | cp 51-dnw.rules /etc/udev/rules.d/ 18 | depmod 19 | 20 | clean: 21 | make -C $(dnw_src) clean 22 | make -C /lib/modules/`uname -r`/build M=$(driver_src) clean 23 | 24 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 1、源码说明: 2 | 1.1起因 3 | 由于本人最近要做一个嵌入式的项目,涉及到开发板的调试,按照开发板商提供的文档都 4 | 是要求在winxp下用dnw和xshell来调试,xshell还好说,关键是dnw usb驱动在win7下 5 | 无法安装,而且我工作环境都是linux,在linux下编译调试开发板本就是天经地义的事儿, 6 | 却被这些开发板商教导成在win下用虚拟机装linux系统作为编译环境,在win下用dnw来烧 7 | 写调试开发板,win系统还得是xp的,这不是坑爹吗? 8 | 1.2说明 9 | 本源代码收集自网络,经过整理和加入宏定义,使其适用于OK6410/EZ6410/FS2410和 10 | UT-Exynos4412(我当前使用的)开发板;对源码进行了适当的注释和错误纠正,同时加 11 | 了dnw2源代码(利用libusb而不需内核驱动);同样以GPL协议发布; 12 | 13 | 2、使用说明: 14 | 2.1 编译 15 | 安装libusb 16 | sudo apt-get install libusb-dev 17 | 18 | git clone git@github.com:hechaoyuyu/dnw-linux.git 19 | cd dnw-linux 20 | make 21 | make install 22 | 安装的文件为: 23 | dnw --- 用于传输数据的软件(依赖secbulk.ko),用法:dnw filename 24 | secbulk.ko --- 识别下载用USB的驱动; 25 | dnw.rules --- 自动加载secbulk.ko; 26 | dnw2 --- 基于libusb而不用内核模块的数据传输程序,用法:dnw2 filename 27 | 2.1 使用 28 | 首先用串口线连好PC与开发板(我用的是usb转串口线),并设置好kermit或minicom( 29 | 用dmesg查看串口设备文件),启动开发板进入u-boot,输入dnw <下载地址>,如我要 30 | 下载bootloader,则在开发板上输入dnw 0x40008000,u-boot会提示你连接usb otg 31 | 线,连接好usb线后,u-boot会提示已经连接完毕,可以进行数据传输,则在PC端输入 32 | dnw file_name或dnw2 file_name,我这里是输入sudo dnw2 bootloader_mmc.bin, 33 | 数据传输完毕即可进行烧写操作。 34 | 2.2 注意 35 | 关于dnw中指定的下载地址,请按自己开发板中记录的地址为准,再去改dnw2.c或dnw.c 36 | 中对应的RAM_BASE。连好usb线后,先在PC上用lsusb查看刚连接的usb设备ID号,再去 37 | 改dnw2.c或secbulk.c中VENDOR_ID/PRODUCT_ID或secbulk_table。 38 | 3、后续开发 39 | 如有必要和时间,打算开发一个类似于win下的dnw图形界面版,集kermit/minicom与 40 | dnw下载功能如一体,用pygtk或qt来做界面,如果谁有兴趣,可以与我联系: 41 | hechaoyuyu@gmail.com 。 42 | 43 | 44 | 以下是针对OK6410开发板的使用流程: 45 | 1. build and install 46 | ===================== 47 | $ make 48 | $ sudo make install 49 | 50 | 2. dnw tool usage 51 | ===================== 52 | Connect board to PC and open minicom. Boot board and enter U-Boot command line mode. 53 | Then run command "dnw " in U-Boot. U-Boot may print bellow message: 54 | Insert a OTG cable into the connector! 55 | OTG cable Connected! 56 | Now, Waiting for DNW to transmit data 57 | 58 | Now, you can download your file to board by follow command on PC end: 59 | $ sudo dnw 60 | 61 | Note: If your board isn't FL Ok6410, please set right load-address via "a" option. 62 | Above steps have only download file to board's RAM, so you need flash 63 | it to nand via U-Boot command "nand write". 64 | 65 | If above doesn't work, pls check if you can see bellow message in `dmesg`. 66 | usb 1-1: new full speed USB device using uhci_hcd and address 2 67 | usb 1-1: configuration #1 chosen from 1 choice 68 | secbulk:secbulk probing... 69 | secbulk:bulk out endpoint found! 70 | 71 | =============================================== 72 | some U-Boot commands special for FL Ok6410 73 | (1) download U-Boot 74 | $dnw 50008000 75 | $nand erase 0 100000 76 | $nand write.uboot 50008000 0 100000 77 | #dnw default load address is 0xc0000000 78 | all in one: 79 | $dnw 50008000 && nand erase 0 100000 && nand write.uboot 50008000 0 100000 80 | (2) download kernel 81 | $dnw 50008000 82 | $nand erase 100000 500000 83 | $nand write.e 50008000 100000 500000 84 | all in one: 85 | $dnw 50008000 && nand erase 100000 500000 && nand write.e 50008000 100000 500000 86 | (3) download yaffs2 root file system 87 | $dnw 50008000 88 | $nand erase 600000 #erase mtdblock2 partition 89 | $nand write.yaffs2 50008000 600000 8000000 #instead 8000000 of real image size 90 | all in one: 91 | $dnw 50008000 && nand erase 600000 && nand write.yaffs2 50008000 600000 8000000 92 | (4) download ubifs/cramfs root file system 93 | $dnw 50008000 94 | $nand erase 600000 #erase mtdblock2 partition 95 | $nand write.e 50008000 600000 8000000 #instead 8000000 of real image size 96 | all in one: 97 | $dnw 50008000 && nand erase 600000 && nand write.e 50008000 600000 8000000 98 | (5) download jffs2 root file system 99 | $dnw 50008000 100 | $nand erase 600000 #erase mtdblock2 partition 101 | $nand write.jffs2 50008000 600000 8000000 #instead 8000000 of real image size 102 | all in one: 103 | $dnw 50008000 && nand erase 600000 && nand write.jffs2 50008000 600000 8000000 104 | (6) deal with bad blocks 105 | $nand scrub 106 | (7) set kernel arguments 107 | $setenv bootargs "root=/dev/mtdblock2 rootfstype=yaffs2 console=ttySAC0,115200" 108 | $save 109 | $reset 110 | (8) boot from NFS 111 | $setenv bootargs "root=/dev/nfs nfsroot=192.168.0.231:/FileSystem-Yaffs2 \ 112 | ip=192.168.0.232:192.168.0.231:192.168.0.201:255.255.255.0:8.8.8.8:eth0:off \ 113 | console=ttySAC0,115200" 114 | $save 115 | # "192.168.0.231" is your host ip; "192.168.0.232" is your board's ip; 116 | # "192.168.0.201" is gateway; "255.255.255.0" is mask. 117 | 118 | -------------------------------------------------------------------------------- /src/dnw/dnw.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | const char* dev = "/dev/secbulk0"; 14 | #define BLOCK_SIZE (1*1024*1024) 15 | #define EZ6410_RAM_BASE 0x40008000 16 | //download address 17 | #define RAM_BASE EZ6410_RAM_BASE 18 | 19 | struct download_buffer 20 | { 21 | uint32_t load_addr; /* load address */ 22 | uint32_t size; /* data size */ 23 | uint8_t data[0]; 24 | /* uint16_t checksum; */ 25 | }; 26 | 27 | static int _download_buffer(struct download_buffer *buf) 28 | { 29 | int fd_dev = open(dev, O_WRONLY); 30 | if( -1 == fd_dev) 31 | { 32 | printf("Can not open %s: %s\n", dev, strerror(errno)); 33 | return -1; 34 | } 35 | 36 | printf("Writing data...\n"); 37 | size_t remain_size = buf->size; 38 | size_t block_size = BLOCK_SIZE; 39 | size_t writed = 0; 40 | while(remain_size>0) 41 | { 42 | size_t to_write = remain_size > block_size ? block_size : remain_size; 43 | if( to_write != write(fd_dev, (unsigned char*)buf + writed, to_write)) 44 | { 45 | perror("write failed"); 46 | close(fd_dev); 47 | return -1; 48 | } 49 | remain_size -= to_write; 50 | writed += to_write; 51 | printf("\r%02zu%%\t0x%08zX bytes (%zu K)", 52 | (size_t)((uint64_t)writed*100/(buf->size)), 53 | writed, 54 | writed/1024); 55 | fflush(stdout); 56 | } 57 | printf("\n"); 58 | close(fd_dev); 59 | return 0; 60 | } 61 | 62 | static inline void cal_and_set_checksum(struct download_buffer *buf) 63 | { 64 | uint16_t sum = 0; 65 | int i; 66 | 67 | for(i = 0; i < buf->size; i++) 68 | { 69 | sum += buf->data[i]; 70 | } 71 | *((uint16_t*)(&((uint8_t*)buf)[buf->size - 2])) = sum; 72 | } 73 | 74 | static struct download_buffer* alloc_buffer(size_t data_size) 75 | { 76 | struct download_buffer *buffer = NULL; 77 | size_t total_size = data_size + sizeof(struct download_buffer) + 2; 78 | 79 | buffer = (typeof(buffer))malloc(total_size); 80 | if(NULL == buffer) 81 | return NULL; 82 | buffer->size = total_size; 83 | return buffer; 84 | } 85 | 86 | static void free_buffer(struct download_buffer *buf) 87 | { 88 | free(buf); 89 | } 90 | 91 | static struct download_buffer *load_file(const char *path, unsigned long load_addr) 92 | { 93 | struct stat file_stat; 94 | struct download_buffer *buffer = NULL; 95 | unsigned long total_size; 96 | int fd; 97 | 98 | fd = open(path, O_RDONLY); 99 | if(-1 == fd) 100 | { 101 | printf("Can not open file %s: %s\n", path, strerror(errno)); 102 | return NULL; 103 | } 104 | 105 | if( -1 == fstat(fd, &file_stat) ) 106 | { 107 | perror("Get file size filed!\n"); 108 | goto error; 109 | } 110 | 111 | buffer = alloc_buffer(file_stat.st_size); 112 | if(NULL == buffer) 113 | { 114 | perror("malloc failed!\n"); 115 | goto error; 116 | } 117 | if( file_stat.st_size != read(fd, buffer->data, file_stat.st_size)) 118 | { 119 | perror("Read file failed!\n"); 120 | goto error; 121 | } 122 | 123 | buffer->load_addr = load_addr; 124 | cal_and_set_checksum(buffer); 125 | 126 | return buffer; 127 | 128 | error: 129 | if(fd != -1) 130 | close(fd); 131 | if( NULL != buffer ) 132 | free(buffer); 133 | return NULL; 134 | } 135 | 136 | static int download_file(const char *path, unsigned long load_addr) 137 | { 138 | struct download_buffer *buffer; 139 | struct timeval __start, __end; 140 | long __time_val = 0; 141 | float speed = 0.0; 142 | 143 | buffer = load_file(path, load_addr); 144 | gettimeofday(&__start,NULL); 145 | if (buffer != NULL) 146 | { 147 | if (_download_buffer(buffer) == 0) 148 | { 149 | gettimeofday(&__end,NULL); 150 | __time_val = (long)(__end.tv_usec - __start.tv_usec)/1000 + \ 151 | (long)(__end.tv_sec - __start.tv_sec) * 1000; 152 | speed = (float)buffer->size/__time_val/(1024*1024) * 1000; 153 | printf("speed: %fM/S\n",speed); 154 | free_buffer(buffer); 155 | } 156 | else 157 | { 158 | free_buffer(buffer); 159 | return -1; 160 | } 161 | } 162 | else 163 | return -1; 164 | } 165 | 166 | int main(int argc, char* argv[]) 167 | { 168 | unsigned load_addr = RAM_BASE; 169 | char* path = NULL; 170 | int c; 171 | 172 | while ((c = getopt (argc, argv, "a:h")) != EOF) 173 | switch (c) 174 | { 175 | case 'a': 176 | load_addr = strtol(optarg, NULL, 16); 177 | continue; 178 | case '?': case 'h': default: 179 | usage: 180 | printf("Usage: dwn [-a load_addr] \n"); 181 | printf("Default load address: 0x40008000\n"); 182 | return 1; 183 | } 184 | if (optind < argc) 185 | path = argv[optind]; 186 | else 187 | goto usage; 188 | 189 | printf("load address: 0x%08X\n", load_addr); 190 | if (download_file(path, load_addr) != 0) 191 | { 192 | return -1; 193 | } 194 | 195 | return 0; 196 | } 197 | 198 | -------------------------------------------------------------------------------- /src/dnw/dnw2.c: -------------------------------------------------------------------------------- 1 | /* dnw2 linux main file. This depends on libusb. 2 | * 3 | * License: GPL 4 | * 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | //FS2410 15 | #define FS2410_VENDOR_ID 0x5345 16 | #define FS2410_PRODUCT_ID 0x1234 17 | #define FS2410_RAM_BASE 0x30200000 18 | //EZ6410 19 | #define EZ6410_VENDOR_ID 0x04e8 20 | #define EZ6410_PRODUCT_ID 0x1234 21 | #define EZ6410_RAM_BASE 0x40008000 22 | //download address 23 | #define RAM_BASE EZ6410_RAM_BASE 24 | #define VENDOR_ID EZ6410_VENDOR_ID 25 | #define PRODUCT_ID EZ6410_PRODUCT_ID 26 | 27 | struct usb_dev_handle * open_port() 28 | { 29 | struct usb_bus *busses, *bus; 30 | 31 | usb_init(); 32 | usb_find_busses(); 33 | usb_find_devices(); 34 | 35 | busses = usb_get_busses(); 36 | for (bus = busses; bus; bus = bus->next) 37 | { 38 | struct usb_device *dev; 39 | for (dev = bus->devices; dev; dev = dev->next) 40 | { 41 | //printf("idVendor:0x%x\t,ipProduct:0x%x\n", dev->descriptor.idVendor, dev->descriptor.idProduct); 42 | 43 | if (VENDOR_ID == dev->descriptor.idVendor 44 | && PRODUCT_ID == dev->descriptor.idProduct) 45 | { 46 | printf("Target usb device found!\n"); 47 | struct usb_dev_handle *hdev = usb_open(dev); 48 | if (!hdev) 49 | { 50 | perror("Cannot open device"); 51 | } 52 | else 53 | { 54 | if (0 != usb_claim_interface(hdev, 0)) 55 | { 56 | perror("Cannot claim interface"); 57 | usb_close(hdev); 58 | hdev = NULL; 59 | } 60 | } 61 | return hdev; 62 | } 63 | } 64 | } 65 | 66 | printf("Target usb device not found!\n"); 67 | 68 | return NULL; 69 | } 70 | 71 | static u_int16_t ace_csum(const unsigned char *data, u_int32_t len) 72 | { 73 | u_int16_t csum = 0; 74 | int j; 75 | 76 | for (j = 0; j < len; j ++) 77 | { 78 | csum += data[j]; 79 | } 80 | 81 | return csum; 82 | } 83 | 84 | unsigned char* prepare_write_buf(char *filename, unsigned int *len, unsigned long load_addr) 85 | { 86 | unsigned char *write_buf = NULL; 87 | struct stat fs; 88 | 89 | int fd = open(filename, O_RDONLY); 90 | if (-1 == fd) 91 | { 92 | perror("Cannot open file"); 93 | return NULL; 94 | } 95 | if (-1 == fstat(fd, &fs)) 96 | { 97 | perror("Cannot get file size"); 98 | goto error; 99 | } 100 | write_buf = (unsigned char*) malloc(fs.st_size + 10); 101 | if (NULL == write_buf) 102 | { 103 | perror("malloc failed"); 104 | goto error; 105 | } 106 | 107 | if (fs.st_size != read(fd, write_buf + 8, fs.st_size)) 108 | { 109 | perror("Reading file failed"); 110 | goto error; 111 | } 112 | 113 | printf("Filename : %s\n", filename); 114 | printf("Filesize : %lu bytes\n", fs.st_size); 115 | 116 | *((u_int32_t*) write_buf) = load_addr; //download address 117 | *((u_int32_t*) write_buf + 1) = fs.st_size + 10; //download size; 118 | *len = fs.st_size + 10; 119 | 120 | // calculate checksum value 121 | u_int16_t csum = ace_csum(write_buf+8, fs.st_size); 122 | *(write_buf+fs.st_size+8) = csum & 0xff; 123 | *(write_buf+fs.st_size+9) = (csum >> 8) & 0xff; 124 | return write_buf; 125 | 126 | error: 127 | if (fd != -1) 128 | close(fd); 129 | if (NULL != write_buf) 130 | free(write_buf); 131 | fs.st_size = 0; 132 | return NULL; 133 | 134 | } 135 | 136 | int main(int argc, char *argv[]) 137 | { 138 | unsigned load_addr = RAM_BASE; 139 | char* path = NULL; 140 | int c; 141 | 142 | //处理命令行参数 143 | while ((c = getopt (argc, argv, "a:h")) != EOF) 144 | switch (c) 145 | { 146 | case 'a': 147 | load_addr = strtol(optarg, NULL, 16); 148 | continue; 149 | case '?': case 'h': default: 150 | usage: 151 | printf("Usage: dwn2 [-a load_addr] \n"); 152 | printf("Default load address: 0x40008000\n"); 153 | return 1; 154 | } 155 | if (optind < argc) 156 | path = argv[optind]; 157 | else 158 | goto usage; 159 | printf("load address: 0x%08X\n", load_addr); 160 | 161 | //打开设备文件 162 | struct usb_dev_handle *hdev = open_port(); 163 | if (!hdev) 164 | { 165 | return 1; 166 | } 167 | 168 | //准备写入空间 169 | unsigned int len = 0; 170 | unsigned char* write_buf = prepare_write_buf(path, &len, load_addr); 171 | if (NULL == write_buf) 172 | return 1; 173 | //写入数据 174 | unsigned int remain = len; 175 | unsigned int towrite; 176 | printf("Writing data ...\n"); 177 | while (remain) 178 | { 179 | towrite = remain > 512 ? 512 : remain; 180 | if (towrite != usb_bulk_write(hdev, 0x02, write_buf+(len-remain), towrite, 3000)) 181 | { 182 | perror("usb_bulk_write failed"); 183 | break; 184 | } 185 | remain -= towrite; 186 | printf("\r%d%%\t %d bytes ", (len-remain)*100/len, len-remain); 187 | fflush(stdout); 188 | } 189 | if (0 == remain) 190 | printf("Done!\n"); 191 | return 0; 192 | } 193 | -------------------------------------------------------------------------------- /src/driver/secbulk.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define SECBULK_MAJOR 102 10 | #define SECBULK_MINOR 0 11 | #define DRIVER_NAME "secbulk" 12 | 13 | #define BULKOUT_BUFFER_SIZE (4*1024) 14 | 15 | struct secbulk_dev 16 | { 17 | struct usb_device *udev; 18 | struct mutex io_mutex; 19 | char* bulkout_buffer; 20 | __u8 bulk_out_endpointAddr; 21 | }; 22 | 23 | static struct usb_class_driver secbulk_class; 24 | 25 | static struct usb_device_id secbulk_table[]= 26 | { 27 | { USB_DEVICE(0x5345, 0x1234) }, /* FS2410 */ 28 | { USB_DEVICE(0x04e8, 0x1234) }, /* EZ6410 */ 29 | { } 30 | }; 31 | 32 | static struct usb_driver secbulk_driver; 33 | static void secbulk_disconnect(struct usb_interface *interface) 34 | { 35 | struct secbulk_dev *dev = NULL; 36 | printk(KERN_INFO "secbulk:secbulk disconnected!\n"); 37 | dev = usb_get_intfdata(interface); 38 | if( NULL != dev ) 39 | kfree(dev); 40 | usb_deregister_dev(interface, &secbulk_class); 41 | return; 42 | } 43 | 44 | static ssize_t secbulk_read(struct file *file, char __user *buf, size_t len, loff_t *loff) 45 | { 46 | return -EPERM; 47 | } 48 | 49 | static ssize_t secbulk_write(struct file *file, const char __user *buf, size_t len, loff_t *loff) 50 | { 51 | size_t to_write; 52 | struct secbulk_dev *dev = file->private_data; 53 | int ret; 54 | int actual_length; 55 | size_t total_writed; 56 | 57 | total_writed = 0; 58 | while(len > 0) 59 | { 60 | to_write = min(len, BULKOUT_BUFFER_SIZE); 61 | 62 | if(copy_from_user(dev->bulkout_buffer, buf+total_writed, to_write)) 63 | { 64 | printk(KERN_ERR "secbulk:copy_from_user failed!\n"); 65 | return -EFAULT; 66 | } 67 | 68 | ret = usb_bulk_msg(dev->udev, 69 | usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), 70 | dev->bulkout_buffer, 71 | to_write, 72 | &actual_length, 73 | 3*HZ); 74 | if(ret || actual_length!=to_write) 75 | { 76 | printk(KERN_ERR "secbulk:usb_bulk_msg failed!\n"); 77 | return -EFAULT; 78 | } 79 | len -= to_write; 80 | total_writed += to_write; 81 | } 82 | return total_writed; 83 | } 84 | 85 | static int secbulk_open(struct inode *node, struct file *file) 86 | { 87 | struct usb_interface *interface; 88 | struct secbulk_dev *dev; 89 | 90 | interface = usb_find_interface(&secbulk_driver, iminor(node)); 91 | if(!interface) 92 | return -ENODEV; 93 | 94 | dev = usb_get_intfdata(interface); 95 | dev->bulkout_buffer = kzalloc(BULKOUT_BUFFER_SIZE, GFP_KERNEL); 96 | if(!(dev->bulkout_buffer)) 97 | return -ENOMEM; 98 | if(!mutex_trylock(&dev->io_mutex)) 99 | return -EBUSY; 100 | file->private_data = dev; 101 | 102 | return 0; 103 | } 104 | 105 | static int secbulk_release(struct inode *node, struct file *file) 106 | { 107 | struct secbulk_dev *dev; 108 | 109 | dev = (struct secbulk_dev*)(file->private_data); 110 | kfree(dev->bulkout_buffer); 111 | mutex_unlock(&dev->io_mutex); 112 | return 0; 113 | } 114 | 115 | static struct file_operations secbulk_fops = 116 | { 117 | .owner = THIS_MODULE, 118 | .read = secbulk_read, 119 | .write = secbulk_write, 120 | .open = secbulk_open, 121 | .release= secbulk_release, 122 | }; 123 | 124 | static struct usb_class_driver secbulk_class = 125 | { 126 | .name = "secbulk%d", 127 | .fops = &secbulk_fops, 128 | .minor_base= 100, 129 | }; 130 | 131 | static int secbulk_probe(struct usb_interface *interface, const struct usb_device_id *id) 132 | { 133 | int ret; 134 | struct secbulk_dev *dev; 135 | struct usb_host_interface *iface_desc; 136 | struct usb_endpoint_descriptor *endpoint; 137 | int i; 138 | 139 | printk(KERN_INFO "secbulk:secbulk probing...\n"); 140 | 141 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); 142 | if(!dev) 143 | { 144 | ret = -ENOMEM; 145 | goto error; 146 | } 147 | 148 | iface_desc = interface->cur_altsetting; 149 | for(i=0; i < iface_desc->desc.bNumEndpoints; i++) 150 | { 151 | endpoint = &(iface_desc->endpoint[i].desc); 152 | if(!dev->bulk_out_endpointAddr && usb_endpoint_is_bulk_out(endpoint)) 153 | { 154 | printk(KERN_INFO "secbulk:bulk out endpoint found!\n"); 155 | dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; 156 | break; 157 | } 158 | } 159 | 160 | if(!(dev->bulk_out_endpointAddr)) 161 | { 162 | ret = -EBUSY; 163 | goto error; 164 | } 165 | 166 | ret = usb_register_dev(interface, &secbulk_class); 167 | if(ret) 168 | { 169 | printk(KERN_ERR "secbulk: usb_register_dev failed!\n"); 170 | return ret; 171 | } 172 | dev->udev = usb_get_dev(interface_to_usbdev(interface)); 173 | 174 | usb_set_intfdata(interface, dev); 175 | 176 | mutex_init(&dev->io_mutex); 177 | return 0; 178 | error: 179 | if(!dev) 180 | kfree(dev); 181 | return ret; 182 | } 183 | 184 | static struct usb_driver secbulk_driver= 185 | { 186 | .name= "secbulk", 187 | .probe= secbulk_probe, 188 | .disconnect= secbulk_disconnect, 189 | .id_table= secbulk_table, 190 | .supports_autosuspend=0, 191 | }; 192 | 193 | static int __init secbulk_init(void) 194 | { 195 | int result; 196 | printk(KERN_INFO "secbulk:secbulk loaded\n"); 197 | result = usb_register(&secbulk_driver); 198 | if(result) 199 | { 200 | printk(KERN_ERR "secbulk:usb_register failed: %d", result); 201 | return result; 202 | } 203 | return 0; 204 | } 205 | 206 | static void __exit secbulk_exit(void) 207 | { 208 | usb_deregister(&secbulk_driver); 209 | printk(KERN_INFO "secbulk:secbulk unloaded\n"); 210 | } 211 | 212 | module_init(secbulk_init); 213 | module_exit(secbulk_exit); 214 | MODULE_LICENSE("GPL"); 215 | 216 | --------------------------------------------------------------------------------