⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbatm.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
				       u8 *target, unsigned int avail_space){	struct usbatm_control *ctrl = UDSL_SKB(skb);	struct atm_vcc *vcc = ctrl->atm.vcc;	unsigned int bytes_written;	unsigned int stride = instance->tx_channel.stride;	vdbg("%s: skb->len=%d, avail_space=%u", __func__, skb->len, avail_space);	UDSL_ASSERT(!(avail_space % stride));	for (bytes_written = 0; bytes_written < avail_space && ctrl->len;	     bytes_written += stride, target += stride) {		unsigned int data_len = min_t(unsigned int, skb->len, ATM_CELL_PAYLOAD);		unsigned int left = ATM_CELL_PAYLOAD - data_len;		u8 *ptr = target;		ptr[0] = vcc->vpi >> 4;		ptr[1] = (vcc->vpi << 4) | (vcc->vci >> 12);		ptr[2] = vcc->vci >> 4;		ptr[3] = vcc->vci << 4;		ptr[4] = 0xec;		ptr += ATM_CELL_HEADER;		memcpy(ptr, skb->data, data_len);		ptr += data_len;		__skb_pull(skb, data_len);		if(!left)			continue;		memset(ptr, 0, left);		if (left >= ATM_AAL5_TRAILER) {	/* trailer will go in this cell */			u8 *trailer = target + ATM_CELL_SIZE - ATM_AAL5_TRAILER;			/* trailer[0] = 0;		UU = 0 */			/* trailer[1] = 0;		CPI = 0 */			trailer[2] = ctrl->len >> 8;			trailer[3] = ctrl->len;			ctrl->crc = ~ crc32_be(ctrl->crc, ptr, left - 4);			trailer[4] = ctrl->crc >> 24;			trailer[5] = ctrl->crc >> 16;			trailer[6] = ctrl->crc >> 8;			trailer[7] = ctrl->crc;			target[3] |= 0x2;	/* adjust PTI */			ctrl->len = 0;		/* tag this skb finished */		}		else			ctrl->crc = crc32_be(ctrl->crc, ptr, left);	}	return bytes_written;}/****************  receive  ****************/static void usbatm_rx_process(unsigned long data){	struct usbatm_data *instance = (struct usbatm_data *)data;	struct urb *urb;	while ((urb = usbatm_pop_urb(&instance->rx_channel))) {		vdbg("%s: processing urb 0x%p", __func__, urb);		if (usb_pipeisoc(urb->pipe)) {			unsigned char *merge_start = NULL;			unsigned int merge_length = 0;			const unsigned int packet_size = instance->rx_channel.packet_size;			int i;			for (i = 0; i < urb->number_of_packets; i++) {				if (!urb->iso_frame_desc[i].status) {					unsigned int actual_length = urb->iso_frame_desc[i].actual_length;					UDSL_ASSERT(actual_length <= packet_size);					if (!merge_length)						merge_start = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;					merge_length += actual_length;					if (merge_length && (actual_length < packet_size)) {						usbatm_extract_cells(instance, merge_start, merge_length);						merge_length = 0;					}				} else {					atm_rldbg(instance, "%s: status %d in frame %d!\n", __func__, urb->status, i);					if (merge_length)						usbatm_extract_cells(instance, merge_start, merge_length);					merge_length = 0;					instance->buf_usage = 0;				}			}			if (merge_length)				usbatm_extract_cells(instance, merge_start, merge_length);		} else			if (!urb->status)				usbatm_extract_cells(instance, urb->transfer_buffer, urb->actual_length);			else				instance->buf_usage = 0;		if (usbatm_submit_urb(urb))			return;	}}/*************  send  *************/static void usbatm_tx_process(unsigned long data){	struct usbatm_data *instance = (struct usbatm_data *)data;	struct sk_buff *skb = instance->current_skb;	struct urb *urb = NULL;	const unsigned int buf_size = instance->tx_channel.buf_size;	unsigned int bytes_written = 0;	u8 *buffer = NULL;	if (!skb)		skb = skb_dequeue(&instance->sndqueue);	while (skb) {		if (!urb) {			urb = usbatm_pop_urb(&instance->tx_channel);			if (!urb)				break;		/* no more senders */			buffer = urb->transfer_buffer;			bytes_written = (urb->status == -EAGAIN) ?				urb->transfer_buffer_length : 0;		}		bytes_written += usbatm_write_cells(instance, skb,						  buffer + bytes_written,						  buf_size - bytes_written);		vdbg("%s: wrote %u bytes from skb 0x%p to urb 0x%p",		     __func__, bytes_written, skb, urb);		if (!UDSL_SKB(skb)->len) {			struct atm_vcc *vcc = UDSL_SKB(skb)->atm.vcc;			usbatm_pop(vcc, skb);			atomic_inc(&vcc->stats->tx);			skb = skb_dequeue(&instance->sndqueue);		}		if (bytes_written == buf_size || (!skb && bytes_written)) {			urb->transfer_buffer_length = bytes_written;			if (usbatm_submit_urb(urb))				break;			urb = NULL;		}	}	instance->current_skb = skb;}static void usbatm_cancel_send(struct usbatm_data *instance,			       struct atm_vcc *vcc){	struct sk_buff *skb, *n;	atm_dbg(instance, "%s entered\n", __func__);	spin_lock_irq(&instance->sndqueue.lock);	for (skb = instance->sndqueue.next, n = skb->next;	     skb != (struct sk_buff *)&instance->sndqueue;	     skb = n, n = skb->next)		if (UDSL_SKB(skb)->atm.vcc == vcc) {			atm_dbg(instance, "%s: popping skb 0x%p\n", __func__, skb);			__skb_unlink(skb, &instance->sndqueue);			usbatm_pop(vcc, skb);		}	spin_unlock_irq(&instance->sndqueue.lock);	tasklet_disable(&instance->tx_channel.tasklet);	if ((skb = instance->current_skb) && (UDSL_SKB(skb)->atm.vcc == vcc)) {		atm_dbg(instance, "%s: popping current skb (0x%p)\n", __func__, skb);		instance->current_skb = NULL;		usbatm_pop(vcc, skb);	}	tasklet_enable(&instance->tx_channel.tasklet);	atm_dbg(instance, "%s done\n", __func__);}static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb){	struct usbatm_data *instance = vcc->dev->dev_data;	struct usbatm_control *ctrl = UDSL_SKB(skb);	int err;	vdbg("%s called (skb 0x%p, len %u)", __func__, skb, skb->len);	/* racy disconnection check - fine */	if (!instance || instance->disconnected) {#ifdef DEBUG		if (printk_ratelimit())			printk(KERN_DEBUG "%s: %s!\n", __func__, instance ? "disconnected" : "NULL instance");#endif		err = -ENODEV;		goto fail;	}	if (vcc->qos.aal != ATM_AAL5) {		atm_rldbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);		err = -EINVAL;		goto fail;	}	if (skb->len > ATM_MAX_AAL5_PDU) {		atm_rldbg(instance, "%s: packet too long (%d vs %d)!\n",				__func__, skb->len, ATM_MAX_AAL5_PDU);		err = -EINVAL;		goto fail;	}	PACKETDEBUG(skb->data, skb->len);	/* initialize the control block */	ctrl->atm.vcc = vcc;	ctrl->len = skb->len;	ctrl->crc = crc32_be(~0, skb->data, skb->len);	skb_queue_tail(&instance->sndqueue, skb);	tasklet_schedule(&instance->tx_channel.tasklet);	return 0; fail:	usbatm_pop(vcc, skb);	return err;}/**********************  bean counting  **********************/static void usbatm_destroy_instance(struct kref *kref){	struct usbatm_data *instance = container_of(kref, struct usbatm_data, refcount);	dbg("%s", __func__);	tasklet_kill(&instance->rx_channel.tasklet);	tasklet_kill(&instance->tx_channel.tasklet);	usb_put_dev(instance->usb_dev);	kfree(instance);}static void usbatm_get_instance(struct usbatm_data *instance){	dbg("%s", __func__);	kref_get(&instance->refcount);}static void usbatm_put_instance(struct usbatm_data *instance){	dbg("%s", __func__);	kref_put(&instance->refcount, usbatm_destroy_instance);}/************  ATM  ************/static void usbatm_atm_dev_close(struct atm_dev *atm_dev){	struct usbatm_data *instance = atm_dev->dev_data;	dbg("%s", __func__);	if (!instance)		return;	atm_dev->dev_data = NULL; /* catch bugs */	usbatm_put_instance(instance);	/* taken in usbatm_atm_init */}static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page){	struct usbatm_data *instance = atm_dev->dev_data;	int left = *pos;	if (!instance) {		dbg("%s: NULL instance!", __func__);		return -ENODEV;	}	if (!left--)		return sprintf(page, "%s\n", instance->description);	if (!left--)		return sprintf(page, "MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",			       atm_dev->esi[0], atm_dev->esi[1],			       atm_dev->esi[2], atm_dev->esi[3],			       atm_dev->esi[4], atm_dev->esi[5]);	if (!left--)		return sprintf(page,			       "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n",			       atomic_read(&atm_dev->stats.aal5.tx),			       atomic_read(&atm_dev->stats.aal5.tx_err),			       atomic_read(&atm_dev->stats.aal5.rx),			       atomic_read(&atm_dev->stats.aal5.rx_err),			       atomic_read(&atm_dev->stats.aal5.rx_drop));	if (!left--) {		if (instance->disconnected)			return sprintf(page, "Disconnected\n");		else			switch (atm_dev->signal) {			case ATM_PHY_SIG_FOUND:				return sprintf(page, "Line up\n");			case ATM_PHY_SIG_LOST:				return sprintf(page, "Line down\n");			default:				return sprintf(page, "Line state unknown\n");			}	}	return 0;}static int usbatm_atm_open(struct atm_vcc *vcc){	struct usbatm_data *instance = vcc->dev->dev_data;	struct usbatm_vcc_data *new = NULL;	int ret;	int vci = vcc->vci;	short vpi = vcc->vpi;	if (!instance) {		dbg("%s: NULL data!", __func__);		return -ENODEV;	}	atm_dbg(instance, "%s: vpi %hd, vci %d\n", __func__, vpi, vci);	/* only support AAL5 */	if ((vcc->qos.aal != ATM_AAL5)) {		atm_warn(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);		return -EINVAL;	}	/* sanity checks */	if ((vcc->qos.rxtp.max_sdu < 0) || (vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU)) {		atm_dbg(instance, "%s: max_sdu %d out of range!\n", __func__, vcc->qos.rxtp.max_sdu);		return -EINVAL;	}	mutex_lock(&instance->serialize);	/* vs self, usbatm_atm_close, usbatm_usb_disconnect */	if (instance->disconnected) {		atm_dbg(instance, "%s: disconnected!\n", __func__);		ret = -ENODEV;		goto fail;	}	if (usbatm_find_vcc(instance, vpi, vci)) {		atm_dbg(instance, "%s: %hd/%d already in use!\n", __func__, vpi, vci);		ret = -EADDRINUSE;		goto fail;	}	if (!(new = kzalloc(sizeof(struct usbatm_vcc_data), GFP_KERNEL))) {		atm_err(instance, "%s: no memory for vcc_data!\n", __func__);		ret = -ENOMEM;		goto fail;	}	new->vcc = vcc;	new->vpi = vpi;	new->vci = vci;	new->sarb = alloc_skb(usbatm_pdu_length(vcc->qos.rxtp.max_sdu), GFP_KERNEL);	if (!new->sarb) {		atm_err(instance, "%s: no memory for SAR buffer!\n", __func__);		ret = -ENOMEM;		goto fail;	}	vcc->dev_data = new;	tasklet_disable(&instance->rx_channel.tasklet);	instance->cached_vcc = new;	instance->cached_vpi = vpi;	instance->cached_vci = vci;	list_add(&new->list, &instance->vcc_list);	tasklet_enable(&instance->rx_channel.tasklet);	set_bit(ATM_VF_ADDR, &vcc->flags);	set_bit(ATM_VF_PARTIAL, &vcc->flags);	set_bit(ATM_VF_READY, &vcc->flags);	mutex_unlock(&instance->serialize);	atm_dbg(instance, "%s: allocated vcc data 0x%p\n", __func__, new);	return 0;fail:	kfree(new);	mutex_unlock(&instance->serialize);	return ret;}static void usbatm_atm_close(struct atm_vcc *vcc){	struct usbatm_data *instance = vcc->dev->dev_data;	struct usbatm_vcc_data *vcc_data = vcc->dev_data;	if (!instance || !vcc_data) {		dbg("%s: NULL data!", __func__);		return;	}	atm_dbg(instance, "%s entered\n", __func__);	atm_dbg(instance, "%s: deallocating vcc 0x%p with vpi %d vci %d\n",		__func__, vcc_data, vcc_data->vpi, vcc_data->vci);	usbatm_cancel_send(instance, vcc);	mutex_lock(&instance->serialize);	/* vs self, usbatm_atm_open, usbatm_usb_disconnect */	tasklet_disable(&instance->rx_channel.tasklet);	if (instance->cached_vcc == vcc_data) {		instance->cached_vcc = NULL;		instance->cached_vpi = ATM_VPI_UNSPEC;		instance->cached_vci = ATM_VCI_UNSPEC;	}	list_del(&vcc_data->list);	tasklet_enable(&instance->rx_channel.tasklet);	kfree_skb(vcc_data->sarb);	vcc_data->sarb = NULL;	kfree(vcc_data);	vcc->dev_data = NULL;	vcc->vpi = ATM_VPI_UNSPEC;	vcc->vci = ATM_VCI_UNSPEC;	clear_bit(ATM_VF_READY, &vcc->flags);	clear_bit(ATM_VF_PARTIAL, &vcc->flags);	clear_bit(ATM_VF_ADDR, &vcc->flags);	mutex_unlock(&instance->serialize);	atm_dbg(instance, "%s successful\n", __func__);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -