?? hso.c
字號:
return; /* linux kernels 2.6.24 on do the check if (!urb->ep) return; * in usb_kill_urb & usb_submit_urb we cant do this because urb->ep doesn't exist * prior to 2.6.23 so we need the -EINPROGRESS check. */ if (urb->status != -EINPROGRESS) return; usb_unlink_urb(urb);}static void safe_usb_kill_urb(struct urb *urb){ if (!urb) return; if (urb->status != -EINPROGRESS) return; usb_kill_urb(urb);}#endif#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12))static int hso_kref_put(struct kref *kref, void (*release)(struct kref *kref)){ kref_put(kref, release); if (atomic_read(&kref->refcount)==0) return 1; return 0;}#else#define hso_kref_put kref_put#endif#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14))#define kzalloc(size,flags) kcalloc(size,1,flags)#endif/* Debugging functions */#ifdef CONFIG_HSO_DEBUG#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22))#define DUMP_PREFIX_NONE 0static void print_hex_dump_bytes(const char *prefix_str, int prefix_type, const void *buf, size_t len){ size_t offset; int i; unsigned char linebuf[200]; int linebuf_offset; for(offset = 0; offset < len; offset += 16) { linebuf_offset = sprintf(&linebuf[0],"%s ", prefix_str); for(i = 0; i < 16 && offset + i < len; i++) linebuf_offset += sprintf(&linebuf[linebuf_offset], "%02x ",((u8*)buf)[offset+i]); linebuf_offset += sprintf(&linebuf[linebuf_offset],"\n"); printk(KERN_DEBUG"%s",linebuf); }}#endifstatic void dbg_dump(int line_count, const char *func_name, unsigned char *buf, unsigned int len){ static char name[255]; sprintf(name, "hso[%d:%s]", line_count, func_name); print_hex_dump_bytes(name, DUMP_PREFIX_NONE, buf, len);}#define DUMP(buf_, len_) \ dbg_dump(__LINE__, __func__, buf_, len_)#define DUMP1(buf_, len_) \ do { \ if (0x01 & debug) \ DUMP(buf_, len_); \ } while (0)#else#define DUMP(buf_, len_)#define DUMP1(buf_, len_)#endif/* module parameters */static int debug;static int tty_major;static int disable_net;/* driver info */static const char driver_name[] = "hso";static const char tty_filename[] = "ttyHS";static const char *version = __FILE__ ": " DRIVER_VERSION " " MOD_AUTHOR;/* the usb driver itself (registered in hso_init) */static struct usb_driver hso_driver;/* serial structures */static struct tty_driver *tty_drv;static struct hso_device *serial_table[HSO_SERIAL_TTY_MINORS];static struct hso_device *network_table[HSO_MAX_NET_DEVICES];static spinlock_t serial_table_lock;static struct TERMIOS *hso_serial_termios[HSO_SERIAL_TTY_MINORS];static struct TERMIOS *hso_serial_termios_locked[HSO_SERIAL_TTY_MINORS];/* hso_mutex_table has to be declared statically as hso_device * is freed in hso_serial_open & hso_serial_close while * the mutex is still in use. */#define HSO_NUM_MUTEXES (HSO_SERIAL_TTY_MINORS+HSO_MAX_NET_DEVICES)static struct hso_mutex_t hso_mutex_table[HSO_NUM_MUTEXES];static spinlock_t hso_mutex_lock;static const s32 default_port_spec[] = { HSO_INTF_MUX | HSO_PORT_NETWORK, HSO_INTF_BULK | HSO_PORT_DIAG, HSO_INTF_BULK | HSO_PORT_MODEM, 0};static const s32 icon321_port_spec[] = { HSO_INTF_MUX | HSO_PORT_NETWORK, HSO_INTF_BULK | HSO_PORT_DIAG2, HSO_INTF_BULK | HSO_PORT_MODEM, HSO_INTF_BULK | HSO_PORT_DIAG, 0};#define default_port_device(vendor, product) \ USB_DEVICE(vendor, product), \ .driver_info = (kernel_ulong_t)default_port_spec#define icon321_port_device(vendor, product) \ USB_DEVICE(vendor, product), \ .driver_info = (kernel_ulong_t)icon321_port_spec/* list of devices we support */static const struct usb_device_id hso_ids[] = { {default_port_device(0x0af0, 0x6711)}, {default_port_device(0x0af0, 0x6731)}, {default_port_device(0x0af0, 0x6751)}, {default_port_device(0x0af0, 0x6771)}, {default_port_device(0x0af0, 0x6791)}, {default_port_device(0x0af0, 0x6811)}, {default_port_device(0x0af0, 0x6911)}, {default_port_device(0x0af0, 0x6951)}, {default_port_device(0x0af0, 0x6971)}, {default_port_device(0x0af0, 0x7011)}, {default_port_device(0x0af0, 0x7031)}, {default_port_device(0x0af0, 0x7051)}, {default_port_device(0x0af0, 0x7071)}, {default_port_device(0x0af0, 0x7111)}, {default_port_device(0x0af0, 0x7211)}, {default_port_device(0x0af0, 0x7251)}, {default_port_device(0x0af0, 0x7271)}, {default_port_device(0x0af0, 0x7311)}, {default_port_device(0x0af0, 0xc031)}, /* Icon-Edge */ {icon321_port_device(0x0af0, 0xd013)}, /* Module HSxPA */ {icon321_port_device(0x0af0, 0xd031)}, /* Icon-321 */ {icon321_port_device(0x0af0, 0xd033)}, /* Icon-322 */ {USB_DEVICE(0x0af0, 0x7301)}, /* GE40x */ {USB_DEVICE(0x0af0, 0x7361)}, /* GE40x */ {USB_DEVICE(0x0af0, 0x7381)}, /* GE40x */ {USB_DEVICE(0x0af0, 0x7401)}, /* GI 0401 */ {USB_DEVICE(0x0af0, 0x7501)}, /* GTM 382 */ {USB_DEVICE(0x0af0, 0x7601)}, /* GE40x */ {USB_DEVICE(0x0af0, 0x7701)}, {USB_DEVICE(0x0af0, 0x7801)}, {USB_DEVICE(0x0af0, 0x7901)}, {USB_DEVICE(0x0af0, 0x8200)}, {USB_DEVICE(0x0af0, 0x8201)}, {USB_DEVICE(0x0af0, 0xd035)}, {USB_DEVICE(0x0af0, 0xd055)}, {USB_DEVICE(0x0af0, 0xd155)}, {USB_DEVICE(0x0af0, 0xd255)}, {USB_DEVICE(0x0af0, 0xd057)}, {USB_DEVICE(0x0af0, 0xd157)}, {USB_DEVICE(0x0af0, 0xd257)}, {USB_DEVICE(0x0af0, 0xd357)}, {}};MODULE_DEVICE_TABLE(usb, hso_ids);#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19))/* Sysfs attribute */static ssize_t hso_sysfs_show_porttype(struct device *dev, struct device_attribute *attr, char *buf){ struct hso_device *hso_dev = dev->driver_data; char *port_name; if (!hso_dev) return 0; switch (hso_dev->port_spec & HSO_PORT_MASK) { case HSO_PORT_CONTROL: port_name = "Control"; break; case HSO_PORT_APP: port_name = "Application"; break; case HSO_PORT_APP2: port_name = "Application2"; break; case HSO_PORT_GPS: port_name = "GPS"; break; case HSO_PORT_GPS_CONTROL: port_name = "GPS Control"; break; case HSO_PORT_PCSC: port_name = "PCSC"; break; case HSO_PORT_DIAG: port_name = "Diagnostic"; break; case HSO_PORT_DIAG2: port_name = "Diagnostic2"; break; case HSO_PORT_MODEM: port_name = "Modem"; break; case HSO_PORT_NETWORK: port_name = "Network"; break; default: port_name = "Unknown"; break; } return sprintf(buf, "%s\n", port_name);}static DEVICE_ATTR(hsotype, S_IRUGO, hso_sysfs_show_porttype, NULL);#endifstatic int hso_urb_to_index(struct hso_serial *serial, struct urb *urb){ int idx; for (idx = 0; idx < serial->num_rx_urbs; idx++) if (serial->rx_urb[idx] == urb) return idx; dev_err(serial->parent->dev, "hso_urb_to_index failed\n"); return -1;}/* converts mux value to a port spec value */static u32 hso_mux_to_port(int mux){ u32 result; switch (mux) { case 0x1: result = HSO_PORT_CONTROL; break; case 0x2: result = HSO_PORT_APP; break; case 0x4: result = HSO_PORT_PCSC; break; case 0x8: result = HSO_PORT_GPS; break; case 0x10: result = HSO_PORT_APP2; break; default: result = HSO_PORT_NO_PORT; } return result;}/* converts port spec value to a mux value */static u32 hso_port_to_mux(int port){ u32 result; switch (port & HSO_PORT_MASK) { case HSO_PORT_CONTROL: result = 0x0; break; case HSO_PORT_APP: result = 0x1; break; case HSO_PORT_PCSC: result = 0x2; break; case HSO_PORT_GPS: result = 0x3; break; case HSO_PORT_APP2: result = 0x4; break; default: result = 0x0; } return result;}static struct hso_serial *get_serial_by_shared_int_and_type( struct hso_shared_int *shared_int, int mux){ int i, port; port = hso_mux_to_port(mux); for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { if (serial_table[i] && (dev2ser(serial_table[i])->shared_int == shared_int) && ((serial_table[i]->port_spec & HSO_PORT_MASK) == port)) { return dev2ser(serial_table[i]); } } return NULL;}static struct hso_serial *get_serial_by_index(unsigned index){ struct hso_serial *serial = NULL; unsigned long flags; spin_lock_irqsave(&serial_table_lock, flags); if (serial_table[index]) serial = dev2ser(serial_table[index]); spin_unlock_irqrestore(&serial_table_lock, flags); return serial;}static int get_free_serial_index(void){ int index; unsigned long flags; spin_lock_irqsave(&serial_table_lock, flags); for (index = 0; index < HSO_SERIAL_TTY_MINORS; index++) { if (serial_table[index] == NULL) { spin_unlock_irqrestore(&serial_table_lock, flags); return index; } } spin_unlock_irqrestore(&serial_table_lock, flags); printk(KERN_ERR "%s: no free serial devices in table\n", __func__); return -1;}static void set_serial_by_index(unsigned index, struct hso_serial *serial){ unsigned long flags; spin_lock_irqsave(&serial_table_lock, flags); if (serial) serial_table[index] = serial->parent; else serial_table[index] = NULL; spin_unlock_irqrestore(&serial_table_lock, flags);}static struct hso_mutex_t *hso_get_free_mutex(void){ int index; struct hso_mutex_t *curr_hso_mutex; spin_lock(&hso_mutex_lock); for (index = 0; index < HSO_NUM_MUTEXES; index++) { curr_hso_mutex = &hso_mutex_table[index]; if (!curr_hso_mutex->allocated) { curr_hso_mutex->allocated = 1; spin_unlock(&hso_mutex_lock); return curr_hso_mutex; } } printk(KERN_ERR "BUG %s: no free hso_mutexs devices in table\n", __func__); spin_unlock(&hso_mutex_lock); return NULL;}static void hso_free_mutex(struct hso_mutex_t *mutex){ spin_lock(&hso_mutex_lock); mutex->allocated = 0; spin_unlock(&hso_mutex_lock);}/* log a meaningful explanation of an USB status */static void log_usb_status(int status, const char *function){ char *explanation; switch (status) { case -ENODEV: explanation = "no device"; break; case -ENOENT: explanation = "endpoint not enabled"; break; case -EPIPE: explanation = "endpoint stalled"; break; case -ENOSPC: explanation = "not enough bandwidth"; break; case -ESHUTDOWN: explanation = "device disabled"; break; case -EHOSTUNREACH: explanation = "device suspended"; break; case -EINVAL: case -EAGAIN: case -EFBIG: case -EMSGSIZE: explanation = "internal error"; break; default: explanation = "unknown status"; break; } D1("%s: received USB status - %s (%d)", function, explanation, status);}/* Network interface functions *//* called when net interface is brought up by ifconfig */static int hso_net_open(struct net_device *net){ struct hso_net *odev = netdev_priv(net); unsigned long flags = 0; if (!odev) { netdev_err(net, "No net device !\n"); return -ENODEV; } odev->skb_tx_buf = NULL; /* setup environment */ spin_lock_irqsave(&odev->net_lock, flags); odev->rx_parse_state = WAIT_IP; odev->rx_buf_size = 0; odev->rx_buf_missing = sizeof(struct iphdr); spin_unlock_irqrestore(&odev->net_lock, flags); /* We are up and running. */ set_bit(HSO_NET_RUNNING, &odev->flags); hso_start_net_device(odev->parent); /* Tell the kernel we are ready to start receiving from it */ netif_start_queue(net); return 0;}/* called when interface is brought down by ifconfig */static int hso_net_close(struct net_device *net){ struct hso_net *odev = netdev_priv(net); /* we don't need the queue anymore */ netif_stop_queue(net); /* no longer running */ clear_bit(HSO_NET_RUNNING, &odev->flags); hso_stop_net_device(odev->parent); /* done */ return 0;}/* USB tells is xmit done, we should start the netqueue again */static void write_bulk_callback(CALLBACK_ARGS){ struct hso_net *odev = urb->context; int status = urb->status; /* Sanity check */ if (!odev || !test_bit(HSO_NET_RUNNING, &odev->flags)) { dev_err(&urb->dev->dev, "%s: device not running\n", __func__); return; } /* Do we still have a valid kernel network device? */ if (!netif_device_present(odev->net)) { dev_err(&urb->dev->dev, "%s: net device not present\n", __func__);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -