📄 undi_nii.c
字号:
uint16_t media_header_len; undi_frame_type type; uint8_t reserved[7];} PACKED;struct fptr { void *func; void *gp;};extern char __gp[];/* Variables */static unsigned undi_ifnum;static void *undi_entry_point;static struct cdb cdb;static char buffer[1024*1024];/* SW UNDI callbacks */static void undi_udelay(uint64_t microseconds){#if 0 printf("undi_udelay(%lx)\n", microseconds);#endif if (microseconds < 10) { microseconds = 10; } if (microseconds > 1000) { mdelay(microseconds/1000); microseconds%=1000; } udelay(microseconds);}static struct fptr fptr_undi_udelay = { .func = &undi_udelay, .gp = &__gp,};static void undi_block(uint32_t enable __unused){#if 0 printf("undi_block(%x)\n", enable);#endif return;}static struct fptr fptr_undi_block = { .func = &undi_block, .gp = &__gp,};static void undi_virt2phys(uint64_t virtual, uint64_t *ptr){#if 0 printf("undi_virt2phys(%lx, %lx)\n", virtual, ptr);#endif *ptr = virt_to_phys((void *)virtual);}static struct fptr fptr_undi_virt2phys = { .func = &undi_virt2phys, .gp = &__gp,};#define UNDI_IO_READ 0#define UNDI_IO_WRITE 1#define UNDI_MEM_READ 2#define UNDI_MEM_WRITE 3static void undi_mem_io(uint8_t read_write, uint8_t len, uint64_t port, uint64_t buf_addr){ printf("undi_mem_io(%hhx, %hhx, %lx, %lx)\n", read_write, len, port, buf_addr);#if 0 if ((read_write == UNDI_IO_READ) && (len == 1)) { uint8_t *buf = (void *)buf_addr; *buf = inb(port); } else if ((read_write == UNDI_IO_READ) && (len == 2)) { uint16_t *buf = (void *)buf_addr; *buf = inw(port); } else if ((read_write == UNDI_IO_READ) && (len == 4)) { uint32_t *buf = (void *)buf_addr; *buf = inl(port); } else if ((read_write == UNDI_IO_READ) && (len == 8)) { uint64_t *buf = (void *)buf_addr; *buf = inq(port); } else if ((read_write == UNDI_IO_WRITE) && (len == 1)) { uint8_t *buf = (void *)buf_addr; outb(*buf, port); } else if ((read_write == UNDI_IO_WRITE) && (len == 2)) { uint16_t *buf = (void *)buf_addr; outw(*buf, port); } else if ((read_write == UNDI_IO_WRITE) && (len == 4)) { uint32_t *buf = (void *)buf_addr; outl(*buf, port); } else if ((read_write == UNDI_IO_WRITE) && (len == 8)) { uint64_t *buf = (void *)buf_addr; outq(*buf, port); } else if ((read_write == UNDI_MEM_READ) && (len == 1)) { uint8_t *buf = (void *)buf_addr; *buf = readb(port); } else if ((read_write == UNDI_MEM_READ) && (len == 2)) { uint16_t *buf = (void *)buf_addr; *buf = readw(port); } else if ((read_write == UNDI_MEM_READ) && (len == 4)) { uint32_t *buf = (void *)buf_addr; *buf = readl(port); } else if ((read_write == UNDI_MEM_READ) && (len == 8)) { uint64_t *buf = (void *)buf_addr; *buf = readq(port); } else if ((read_write == UNDI_MEM_WRITE) && (len == 1)) { uint8_t *buf = (void *)buf_addr; writeb(*buf, port); } else if ((read_write == UNDI_MEM_WRITE) && (len == 2)) { uint16_t *buf = (void *)buf_addr; writew(*buf, port); } else if ((read_write == UNDI_MEM_WRITE) && (len == 4)) { uint32_t *buf = (void *)buf_addr; writel(*buf, port); } else if ((read_write == UNDI_MEM_WRITE) && (len == 8)) { uint64_t *buf = (void *)buf_addr; writeq(*buf, port); }#endif}static struct fptr fptr_undi_mem_io = { .func = &undi_mem_io, .gp = &__gp,};/* static void undi_memio(this, width, address, count, buffer);??? *//* Wrappers to call the undi functions */static int undi_call(struct cdb *cdb){ int result = 1; cdb->stat_code = CDB_STATCODE_INITIALIZE; cdb->stat_flags = CDB_STATFLAGS_INITIALIZE; cdb->ifnum = undi_ifnum; cdb->control = CDB_CONTROL_LAST_CDB_IN_LIST; __call(undi_entry_point, cdb); /* Wait until the command executes... */ while((cdb->stat_flags & CDB_STATFLAGS_STATUS_MASK) == 0) ; if ((cdb->stat_flags & CDB_STATFLAGS_STATUS_MASK) != CDB_STATFLAGS_COMMAND_COMPLETE) result = 0; if (cdb->stat_code != CDB_STATCODE_SUCCESS) result = 0; return result;}static int get_state(struct cdb *cdb){ memset(cdb, 0, sizeof(*cdb)); cdb->op_code = CDB_OP_GET_STATE; cdb->op_flags = CDB_OPFLAGS_NOT_USED; return undi_call(cdb);}static int start(struct cdb *cdb){ static struct cpb_start cpb; memset(&cpb, 0, sizeof(cpb)); cpb.delay = &fptr_undi_udelay; cpb.block = &fptr_undi_block; cpb.virt2phys = &fptr_undi_virt2phys; cpb.mem_io = &fptr_undi_mem_io; memset(cdb, 0, sizeof(*cdb)); cdb->op_code = CDB_OP_START; cdb->op_flags = CDB_OPFLAGS_NOT_USED; cdb->cpb_size = sizeof(cpb); cdb->cpb_addr = virt_to_phys(&cpb); return undi_call(cdb);}static int stop(struct cdb *cdb){ memset(cdb, 0, sizeof(*cdb)); cdb->op_code = CDB_OP_STOP; cdb->op_flags = CDB_OPFLAGS_NOT_USED; return undi_call(cdb);}static int get_init_info(struct cdb *cdb, struct db_init_info *info){ memset(info, 0, sizeof(*info)); memset(cdb, 0, sizeof(*cdb)); cdb->op_code = CDB_OP_GET_INIT_INFO; cdb->op_flags = CDB_OPFLAGS_NOT_USED; cdb->db_size = sizeof(*info); cdb->db_addr = virt_to_phys(info); return undi_call(cdb);}#if 0/* get_config_info crashes broadcoms pxe driver */static int get_config_info(struct cdb *cdb, struct db_config_info *info){ memset(info, 0, sizeof(*info)); memset(cdb, 0, sizeof(*cdb)); cdb->op_code = CDB_OP_GET_CONFIG_INFO; cdb->op_flags = CDB_OPFLAGS_NOT_USED; cdb->db_size = sizeof(*info); cdb->db_addr = virt_to_phys(info); return undi_call(cdb);}#endifstatic int initialize(struct cdb *cdb, int media_detect, struct cpb_initialize *cpb, struct db_initialize *db){ memset(db, 0, sizeof(*db)); memset(cdb, 0, sizeof(*cdb)); cdb->op_code = CDB_OP_INITIALIZE; cdb->op_flags = media_detect? CDB_OPFLAGS_INIT_DETECT_CABLE:CDB_OPFLAGS_INIT_DO_NOT_DETECT_CABLE; cdb->cpb_size = sizeof(*cpb); cdb->cpb_addr = virt_to_phys(cpb); cdb->db_size = sizeof(*db); cdb->db_addr = virt_to_phys(db); return undi_call(cdb);}static int shutdown(struct cdb *cdb){ memset(cdb, 0, sizeof(*cdb)); cdb->op_code = CDB_OP_SHUTDOWN; cdb->op_flags = CDB_OPFLAGS_NOT_USED; return undi_call(cdb);}static int station_address_read(struct cdb *cdb, struct db_station_address *db){ memset(db, 0, sizeof(*db)); memset(cdb, 0, sizeof(*cdb)); cdb->op_code = CDB_OP_STATION_ADDRESS; cdb->op_flags = CDB_OPFLAGS_STATION_ADDRESS_READ; cdb->db_size = sizeof(*db); cdb->db_addr = virt_to_phys(db); return undi_call(cdb);}static int receive_filters(struct cdb *cdb, unsigned opflags){ /* I currently do not support setting * or returning the multicast filter list. * So do not even attempt to pass them. */ memset(cdb, 0, sizeof(*cdb)); cdb->op_code = CDB_OP_RECEIVE_FILTERS; cdb->op_flags = opflags; return undi_call(cdb);}static int get_transmitted_status(struct cdb *cdb, struct db_get_status *db){ memset(db, 0, sizeof(*db)); memset(cdb, 0, sizeof(*cdb)); cdb->op_code = CDB_OP_GET_STATUS; cdb->op_flags = CDB_OPFLAGS_GET_TRANSMITTED_BUFFERS; cdb->db_size = sizeof(*db); cdb->db_addr = virt_to_phys(db); return undi_call(cdb);}static int transmit(struct cdb *cdb, struct cpb_transmit *cpb){ memset(cdb, 0, sizeof(*cdb)); cdb->op_code = CDB_OP_TRANSMIT; cdb->op_flags = CDB_OPFLAGS_TRANSMIT_WHOLE | CDB_OPFLAGS_TRANSMIT_DONT_BLOCK; cdb->cpb_size = sizeof(*cpb); cdb->cpb_addr = virt_to_phys(cpb); return undi_call(cdb);}static int receive(struct cdb *cdb, struct cpb_receive *cpb, struct db_receive *db){ memset(db, 0, sizeof(*db)); memset(cdb, 0, sizeof(*cdb)); cdb->op_code = CDB_OP_RECEIVE; cdb->op_flags = CDB_OPFLAGS_NOT_USED; cdb->cpb_size = sizeof(*cpb); cdb->cpb_addr = virt_to_phys(cpb); cdb->db_size = sizeof(*db); cdb->db_addr = virt_to_phys(db); return undi_call(cdb);}/* The work horse functions */static int nic_poll(struct nic *nic ){ int result; struct cpb_receive cpb; struct db_receive db; memset(&cpb, 0, sizeof(cpb)); cpb.buffer_addr = virt_to_phys(nic->packet); cpb.buffer_len = ETH_FRAME_LEN; result = receive(&cdb, &cpb, &db); if (result) { nic->packetlen = db.frame_len; return 1; } else if (cdb.stat_code != CDB_STATCODE_NO_DATA) { printf("Receive failed: %lx\n", cdb.stat_code); } return 0; /* initially as this is called to flush the input */}static void nic_transmit(struct nic *nic, const char *dest, unsigned int type, unsigned int size, const char *data){ int result; static struct { uint8_t dst_addr[ETH_ALEN]; uint8_t src_addr[ETH_ALEN]; uint16_t type; uint8_t data[ETH_MAX_MTU]; } packet; struct cpb_transmit cpb; struct db_get_status db; int done; /* Build the packet to transmit in my buffer */ memcpy(&packet.dst_addr, dest, ETH_ALEN); memcpy(&packet.src_addr, nic->node_addr, ETH_ALEN); packet.type = htons(type); memcpy(&packet.data, data, size); /* send the packet to destination */ cpb.frame_addr = virt_to_phys(&packet); cpb.data_len = ETH_HLEN + size; cpb.media_header_len = ETH_HLEN; result = transmit(&cdb, &cpb); if (!result) { printf("transmit failed: %lx\n", cdb.stat_code); return; } /* Wait until the packet is actually transmitted, * indicating it is safe to reuse my trasmit buffer. */ done = 0; while(!done) { int i; result = get_transmitted_status(&cdb, &db); for(i = 0; i < UNDI_MAX_XMIT_BUFFERS; i++) { if (db.tx_buffer[i] == virt_to_phys(&packet)) { done = 1; } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -