1 /*
2  *---------------------------------------------------------------------------
3  * FT1000 driver for Flarion Flash OFDM NIC Device
4  *
5  * Copyright (C) 2006 Flarion Technologies, All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option) any
10  * later version. This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details. You should have received a copy of the GNU General Public
14  * License along with this program; if not, write to the
15  * Free Software Foundation, Inc., 59 Temple Place -
16  * Suite 330, Boston, MA 02111-1307, USA.
17  *---------------------------------------------------------------------------
18  *
19  * File:         ft1000_chdev.c
20  *
21  * Description:  Custom character device dispatch routines.
22  *
23  * History:
24  * 8/29/02    Whc                Ported to Linux.
25  * 6/05/06    Whc                Porting to Linux 2.6.9
26  *
27  *---------------------------------------------------------------------------
28  */
29 
30 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
31 
32 #include <linux/module.h>
33 #include <linux/kernel.h>
34 #include <linux/sched.h>
35 #include <linux/errno.h>
36 #include <linux/poll.h>
37 #include <linux/netdevice.h>
38 #include <linux/delay.h>
39 
40 #include <linux/ioctl.h>
41 #include <linux/debugfs.h>
42 #include "ft1000_usb.h"
43 
44 static int ft1000_flarion_cnt;
45 
46 static int ft1000_open(struct inode *inode, struct file *file);
47 static unsigned int ft1000_poll_dev(struct file *file, poll_table *wait);
48 static long ft1000_ioctl(struct file *file, unsigned int command,
49 			 unsigned long argument);
50 static int ft1000_release(struct inode *inode, struct file *file);
51 
52 /* List to free receive command buffer pool */
53 struct list_head freercvpool;
54 
55 /* lock to arbitrate free buffer list for receive command data */
56 spinlock_t free_buff_lock;
57 
58 int numofmsgbuf = 0;
59 
60 /*
61  * Table of entry-point routines for char device
62  */
63 static const struct file_operations ft1000fops = {
64 	.unlocked_ioctl	= ft1000_ioctl,
65 	.poll		= ft1000_poll_dev,
66 	.open		= ft1000_open,
67 	.release	= ft1000_release,
68 	.llseek		= no_llseek,
69 };
70 
71 /*
72   ---------------------------------------------------------------------------
73   * Function:    ft1000_get_buffer
74   *
75   * Parameters:
76   *
77   * Returns:
78   *
79   * Description:
80   *
81   * Notes:
82   *
83   *---------------------------------------------------------------------------
84   */
ft1000_get_buffer(struct list_head * bufflist)85 struct dpram_blk *ft1000_get_buffer(struct list_head *bufflist)
86 {
87 	unsigned long flags;
88 	struct dpram_blk *ptr;
89 
90 	spin_lock_irqsave(&free_buff_lock, flags);
91 	/* Check if buffer is available */
92 	if (list_empty(bufflist)) {
93 		pr_debug("No more buffer - %d\n", numofmsgbuf);
94 		ptr = NULL;
95 	} else {
96 		numofmsgbuf--;
97 		ptr = list_entry(bufflist->next, struct dpram_blk, list);
98 		list_del(&ptr->list);
99 		/* pr_debug("number of free msg buffers = %d\n", numofmsgbuf); */
100 	}
101 	spin_unlock_irqrestore(&free_buff_lock, flags);
102 
103 	return ptr;
104 }
105 
106 
107 
108 
109 /*
110  *---------------------------------------------------------------------------
111  * Function:    ft1000_free_buffer
112  *
113  * Parameters:
114  *
115  * Returns:
116  *
117  * Description:
118  *
119  * Notes:
120  *
121  *---------------------------------------------------------------------------
122  */
ft1000_free_buffer(struct dpram_blk * pdpram_blk,struct list_head * plist)123 void ft1000_free_buffer(struct dpram_blk *pdpram_blk, struct list_head *plist)
124 {
125 	unsigned long flags;
126 
127 	spin_lock_irqsave(&free_buff_lock, flags);
128 	/* Put memory back to list */
129 	list_add_tail(&pdpram_blk->list, plist);
130 	numofmsgbuf++;
131 	/*pr_debug("number of free msg buffers = %d\n", numofmsgbuf); */
132 	spin_unlock_irqrestore(&free_buff_lock, flags);
133 }
134 
135 /*
136  *---------------------------------------------------------------------------
137  * Function:    ft1000_CreateDevice
138  *
139  * Parameters:  dev - pointer to adapter object
140  *
141  * Returns:     0 if successful
142  *
143  * Description: Creates a private char device.
144  *
145  * Notes:       Only called by init_module().
146  *
147  *---------------------------------------------------------------------------
148  */
ft1000_create_dev(struct ft1000_usb * dev)149 int ft1000_create_dev(struct ft1000_usb *dev)
150 {
151 	int result;
152 	int i;
153 	struct dentry *dir, *file;
154 	struct ft1000_debug_dirs *tmp;
155 
156 	/* make a new device name */
157 	sprintf(dev->DeviceName, "%s%d", "FT1000_", dev->CardNumber);
158 
159 	pr_debug("number of instance = %d\n", ft1000_flarion_cnt);
160 	pr_debug("DeviceCreated = %x\n", dev->DeviceCreated);
161 
162 	if (dev->DeviceCreated) {
163 		pr_debug("\"%s\" already registered\n", dev->DeviceName);
164 		return -EIO;
165 	}
166 
167 
168 	/* register the device */
169 	pr_debug("\"%s\" debugfs device registration\n", dev->DeviceName);
170 
171 	tmp = kmalloc(sizeof(struct ft1000_debug_dirs), GFP_KERNEL);
172 	if (tmp == NULL) {
173 		result = -1;
174 		goto fail;
175 	}
176 
177 	dir = debugfs_create_dir(dev->DeviceName, NULL);
178 	if (IS_ERR(dir)) {
179 		result = PTR_ERR(dir);
180 		goto debug_dir_fail;
181 	}
182 
183 	file = debugfs_create_file("device", S_IRUGO | S_IWUSR, dir,
184 				   dev, &ft1000fops);
185 	if (IS_ERR(file)) {
186 		result = PTR_ERR(file);
187 		goto debug_file_fail;
188 	}
189 
190 	tmp->dent = dir;
191 	tmp->file = file;
192 	tmp->int_number = dev->CardNumber;
193 	list_add(&tmp->list, &dev->nodes.list);
194 
195 	pr_debug("registered debugfs directory \"%s\"\n", dev->DeviceName);
196 
197 	/* initialize application information */
198 	dev->appcnt = 0;
199 	for (i = 0; i < MAX_NUM_APP; i++) {
200 		dev->app_info[i].nTxMsg = 0;
201 		dev->app_info[i].nRxMsg = 0;
202 		dev->app_info[i].nTxMsgReject = 0;
203 		dev->app_info[i].nRxMsgMiss = 0;
204 		dev->app_info[i].fileobject = NULL;
205 		dev->app_info[i].app_id = i+1;
206 		dev->app_info[i].DspBCMsgFlag = 0;
207 		dev->app_info[i].NumOfMsg = 0;
208 		init_waitqueue_head(&dev->app_info[i].wait_dpram_msg);
209 		INIT_LIST_HEAD(&dev->app_info[i].app_sqlist);
210 	}
211 
212 	dev->DeviceCreated = TRUE;
213 	ft1000_flarion_cnt++;
214 
215 	return 0;
216 
217 debug_file_fail:
218 	debugfs_remove(dir);
219 debug_dir_fail:
220 	kfree(tmp);
221 fail:
222 	return result;
223 }
224 
225 /*
226  *---------------------------------------------------------------------------
227  * Function:    ft1000_DestroyDeviceDEBUG
228  *
229  * Parameters:  dev - pointer to adapter object
230  *
231  * Description: Destroys a private char device.
232  *
233  * Notes:       Only called by cleanup_module().
234  *
235  *---------------------------------------------------------------------------
236  */
ft1000_destroy_dev(struct net_device * netdev)237 void ft1000_destroy_dev(struct net_device *netdev)
238 {
239 	struct ft1000_info *info = netdev_priv(netdev);
240 	struct ft1000_usb *dev = info->priv;
241 	int i;
242 	struct dpram_blk *pdpram_blk;
243 	struct dpram_blk *ptr;
244 	struct list_head *pos, *q;
245 	struct ft1000_debug_dirs *dir;
246 
247 	if (dev->DeviceCreated) {
248 		ft1000_flarion_cnt--;
249 		list_for_each_safe(pos, q, &dev->nodes.list) {
250 			dir = list_entry(pos, struct ft1000_debug_dirs, list);
251 			if (dir->int_number == dev->CardNumber) {
252 				debugfs_remove(dir->file);
253 				debugfs_remove(dir->dent);
254 				list_del(pos);
255 				kfree(dir);
256 			}
257 		}
258 		pr_debug("unregistered device \"%s\"\n", dev->DeviceName);
259 
260 		/* Make sure we free any memory reserve for slow Queue */
261 		for (i = 0; i < MAX_NUM_APP; i++) {
262 			while (list_empty(&dev->app_info[i].app_sqlist) == 0) {
263 				pdpram_blk = list_entry(dev->app_info[i].app_sqlist.next, struct dpram_blk, list);
264 				list_del(&pdpram_blk->list);
265 				ft1000_free_buffer(pdpram_blk, &freercvpool);
266 
267 			}
268 			wake_up_interruptible(&dev->app_info[i].wait_dpram_msg);
269 		}
270 
271 		/* Remove buffer allocated for receive command data */
272 		if (ft1000_flarion_cnt == 0) {
273 			while (list_empty(&freercvpool) == 0) {
274 				ptr = list_entry(freercvpool.next, struct dpram_blk, list);
275 				list_del(&ptr->list);
276 				kfree(ptr->pbuffer);
277 				kfree(ptr);
278 			}
279 		}
280 		dev->DeviceCreated = FALSE;
281 	}
282 
283 
284 }
285 
286 /*
287  *---------------------------------------------------------------------------
288  * Function:    ft1000_open
289  *
290  * Parameters:
291  *
292  * Description:
293  *
294  * Notes:
295  *
296  *---------------------------------------------------------------------------
297  */
ft1000_open(struct inode * inode,struct file * file)298 static int ft1000_open(struct inode *inode, struct file *file)
299 {
300 	struct ft1000_info *info;
301 	struct ft1000_usb *dev = (struct ft1000_usb *)inode->i_private;
302 	int i, num;
303 
304 	num = MINOR(inode->i_rdev) & 0xf;
305 	pr_debug("minor number=%d\n", num);
306 
307 	info = file->private_data = netdev_priv(dev->net);
308 
309 	pr_debug("f_owner = %p number of application = %d\n",
310 		 &file->f_owner, dev->appcnt);
311 
312 	/* Check if maximum number of application exceeded */
313 	if (dev->appcnt > MAX_NUM_APP) {
314 		pr_debug("Maximum number of application exceeded\n");
315 		return -EACCES;
316 	}
317 
318 	/* Search for available application info block */
319 	for (i = 0; i < MAX_NUM_APP; i++) {
320 		if ((dev->app_info[i].fileobject == NULL))
321 			break;
322 	}
323 
324 	/* Fail due to lack of application info block */
325 	if (i == MAX_NUM_APP) {
326 		pr_debug("Could not find an application info block\n");
327 		return -EACCES;
328 	}
329 
330 	dev->appcnt++;
331 	dev->app_info[i].fileobject = &file->f_owner;
332 	dev->app_info[i].nTxMsg = 0;
333 	dev->app_info[i].nRxMsg = 0;
334 	dev->app_info[i].nTxMsgReject = 0;
335 	dev->app_info[i].nRxMsgMiss = 0;
336 
337 	nonseekable_open(inode, file);
338 	return 0;
339 }
340 
341 
342 /*
343  *---------------------------------------------------------------------------
344  * Function:    ft1000_poll_dev
345  *
346  * Parameters:
347  *
348  * Description:
349  *
350  * Notes:
351  *
352  *---------------------------------------------------------------------------
353  */
354 
ft1000_poll_dev(struct file * file,poll_table * wait)355 static unsigned int ft1000_poll_dev(struct file *file, poll_table *wait)
356 {
357 	struct net_device *netdev = file->private_data;
358 	struct ft1000_info *info = netdev_priv(netdev);
359 	struct ft1000_usb *dev = info->priv;
360 	int i;
361 
362 	if (ft1000_flarion_cnt == 0) {
363 		pr_debug("called with ft1000_flarion_cnt value zero\n");
364 		return -EBADF;
365 	}
366 
367 	/* Search for matching file object */
368 	for (i = 0; i < MAX_NUM_APP; i++) {
369 		if (dev->app_info[i].fileobject == &file->f_owner) {
370 			/* pr_debug("Message is for AppId = %d\n", dev->app_info[i].app_id); */
371 			break;
372 		}
373 	}
374 
375 	/* Could not find application info block */
376 	if (i == MAX_NUM_APP) {
377 		pr_debug("Could not find application info block\n");
378 		return -EACCES;
379 	}
380 
381 	if (list_empty(&dev->app_info[i].app_sqlist) == 0) {
382 		pr_debug("Message detected in slow queue\n");
383 		return(POLLIN | POLLRDNORM | POLLPRI);
384 	}
385 
386 	poll_wait(file, &dev->app_info[i].wait_dpram_msg, wait);
387 	/* pr_debug("Polling for data from DSP\n"); */
388 
389 	return 0;
390 }
391 
392 /*
393  *---------------------------------------------------------------------------
394  * Function:    ft1000_ioctl
395  *
396  * Parameters:
397  *
398  * Description:
399  *
400  * Notes:
401  *
402  *---------------------------------------------------------------------------
403  */
ft1000_ioctl(struct file * file,unsigned int command,unsigned long argument)404 static long ft1000_ioctl(struct file *file, unsigned int command,
405 			 unsigned long argument)
406 {
407 	void __user *argp = (void __user *)argument;
408 	struct ft1000_info *info;
409 	struct ft1000_usb *ft1000dev;
410 	int result = 0;
411 	int cmd;
412 	int i;
413 	u16 tempword;
414 	unsigned long flags;
415 	struct timeval tv;
416 	struct IOCTL_GET_VER get_ver_data;
417 	struct IOCTL_GET_DSP_STAT get_stat_data;
418 	u8 ConnectionMsg[] = {0x00, 0x44, 0x10, 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x93, 0x64,
419 			      0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0a,
420 			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
421 			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
422 			      0x00, 0x00, 0x02, 0x37, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x7f, 0x00,
423 			      0x00, 0x01, 0x00, 0x00};
424 
425 	unsigned short ledStat = 0;
426 	unsigned short conStat = 0;
427 
428 	if (ft1000_flarion_cnt == 0) {
429 		pr_debug("called with ft1000_flarion_cnt of zero\n");
430 		return -EBADF;
431 	}
432 
433 	/* pr_debug("command = 0x%x argument = 0x%8x\n", command, (u32)argument); */
434 
435 	info = file->private_data;
436 	ft1000dev = info->priv;
437 	cmd = _IOC_NR(command);
438 	/* pr_debug("cmd = 0x%x\n", cmd); */
439 
440 	/* process the command */
441 	switch (cmd) {
442 	case IOCTL_REGISTER_CMD:
443 		pr_debug("IOCTL_FT1000_REGISTER called\n");
444 		result = get_user(tempword, (__u16 __user *)argp);
445 		if (result) {
446 			pr_debug("result = %d failed to get_user\n", result);
447 			break;
448 		}
449 		if (tempword == DSPBCMSGID) {
450 			/* Search for matching file object */
451 			for (i = 0; i < MAX_NUM_APP; i++) {
452 				if (ft1000dev->app_info[i].fileobject == &file->f_owner) {
453 					ft1000dev->app_info[i].DspBCMsgFlag = 1;
454 					pr_debug("Registered for broadcast messages\n");
455 					break;
456 				}
457 			}
458 		}
459 		break;
460 
461 	case IOCTL_GET_VER_CMD:
462 		pr_debug("IOCTL_FT1000_GET_VER called\n");
463 
464 		get_ver_data.drv_ver = FT1000_DRV_VER;
465 
466 		if (copy_to_user(argp, &get_ver_data, sizeof(get_ver_data))) {
467 			pr_debug("copy fault occurred\n");
468 			result = -EFAULT;
469 			break;
470 		}
471 
472 		pr_debug("driver version = 0x%x\n",
473 			 (unsigned int)get_ver_data.drv_ver);
474 
475 		break;
476 	case IOCTL_CONNECT:
477 		/* Connect Message */
478 		pr_debug("IOCTL_FT1000_CONNECT\n");
479 		ConnectionMsg[79] = 0xfc;
480 		result = card_send_command(ft1000dev, ConnectionMsg, 0x4c);
481 
482 		break;
483 	case IOCTL_DISCONNECT:
484 		/* Disconnect Message */
485 		pr_debug("IOCTL_FT1000_DISCONNECT\n");
486 		ConnectionMsg[79] = 0xfd;
487 		result = card_send_command(ft1000dev, ConnectionMsg, 0x4c);
488 		break;
489 	case IOCTL_GET_DSP_STAT_CMD:
490 		/* pr_debug("IOCTL_FT1000_GET_DSP_STAT\n"); */
491 		memset(&get_stat_data, 0, sizeof(get_stat_data));
492 		memcpy(get_stat_data.DspVer, info->DspVer, DSPVERSZ);
493 		memcpy(get_stat_data.HwSerNum, info->HwSerNum, HWSERNUMSZ);
494 		memcpy(get_stat_data.Sku, info->Sku, SKUSZ);
495 		memcpy(get_stat_data.eui64, info->eui64, EUISZ);
496 
497 		if (info->ProgConStat != 0xFF) {
498 			ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_LED, (u8 *)&ledStat, FT1000_MAG_DSP_LED_INDX);
499 			get_stat_data.LedStat = ntohs(ledStat);
500 			pr_debug("LedStat = 0x%x\n", get_stat_data.LedStat);
501 			ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_CON_STATE, (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX);
502 			get_stat_data.ConStat = ntohs(conStat);
503 			pr_debug("ConStat = 0x%x\n", get_stat_data.ConStat);
504 		} else {
505 			get_stat_data.ConStat = 0x0f;
506 		}
507 
508 
509 		get_stat_data.nTxPkts = info->stats.tx_packets;
510 		get_stat_data.nRxPkts = info->stats.rx_packets;
511 		get_stat_data.nTxBytes = info->stats.tx_bytes;
512 		get_stat_data.nRxBytes = info->stats.rx_bytes;
513 		do_gettimeofday(&tv);
514 		get_stat_data.ConTm = (u32)(tv.tv_sec - info->ConTm);
515 		pr_debug("Connection Time = %d\n", (int)get_stat_data.ConTm);
516 		if (copy_to_user(argp, &get_stat_data, sizeof(get_stat_data))) {
517 			pr_debug("copy fault occurred\n");
518 			result = -EFAULT;
519 			break;
520 		}
521 		pr_debug("GET_DSP_STAT succeed\n");
522 		break;
523 	case IOCTL_SET_DPRAM_CMD:
524 	{
525 		struct IOCTL_DPRAM_BLK *dpram_data = NULL;
526 		/* struct IOCTL_DPRAM_COMMAND dpram_command; */
527 		u16 qtype;
528 		u16 msgsz;
529 		struct pseudo_hdr *ppseudo_hdr;
530 		u16 *pmsg;
531 		u16 total_len;
532 		u16 app_index;
533 		u16 status;
534 
535 		/* pr_debug("IOCTL_FT1000_SET_DPRAM called\n");*/
536 
537 
538 		if (ft1000_flarion_cnt == 0)
539 			return -EBADF;
540 
541 		if (ft1000dev->DrvMsgPend)
542 			return -ENOTTY;
543 
544 		if (ft1000dev->fProvComplete == 0)
545 			return -EACCES;
546 
547 		ft1000dev->fAppMsgPend = true;
548 
549 		if (info->CardReady) {
550 
551 			/* pr_debug("try to SET_DPRAM\n"); */
552 
553 			/* Get the length field to see how many bytes to copy */
554 			result = get_user(msgsz, (__u16 __user *)argp);
555 			if (result)
556 				break;
557 			msgsz = ntohs(msgsz);
558 			/* pr_debug("length of message = %d\n", msgsz); */
559 
560 			if (msgsz > MAX_CMD_SQSIZE) {
561 				pr_debug("bad message length = %d\n", msgsz);
562 				result = -EINVAL;
563 				break;
564 			}
565 
566 			result = -ENOMEM;
567 			dpram_data = kmalloc(msgsz + 2, GFP_KERNEL);
568 			if (!dpram_data)
569 				break;
570 
571 			if (copy_from_user(dpram_data, argp, msgsz+2)) {
572 				pr_debug("copy fault occurred\n");
573 				result = -EFAULT;
574 			} else {
575 				/* Check if this message came from a registered application */
576 				for (i = 0; i < MAX_NUM_APP; i++) {
577 					if (ft1000dev->app_info[i].fileobject == &file->f_owner)
578 						break;
579 				}
580 				if (i == MAX_NUM_APP) {
581 					pr_debug("No matching application fileobject\n");
582 					result = -EINVAL;
583 					kfree(dpram_data);
584 					break;
585 				}
586 				app_index = i;
587 
588 				/* Check message qtype type which is the lower byte within qos_class */
589 				qtype = ntohs(dpram_data->pseudohdr.qos_class) & 0xff;
590 				/* pr_debug("qtype = %d\n", qtype); */
591 				if (qtype) {
592 				} else {
593 					/* Put message into Slow Queue */
594 					/* Only put a message into the DPRAM if msg doorbell is available */
595 					status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
596 					/* pr_debug("READ REGISTER tempword=%x\n", tempword); */
597 					if (tempword & FT1000_DB_DPRAM_TX) {
598 						/* Suspend for 2ms and try again due to DSP doorbell busy */
599 						mdelay(2);
600 						status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
601 						if (tempword & FT1000_DB_DPRAM_TX) {
602 							/* Suspend for 1ms and try again due to DSP doorbell busy */
603 							mdelay(1);
604 							status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
605 							if (tempword & FT1000_DB_DPRAM_TX) {
606 								status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
607 								if (tempword & FT1000_DB_DPRAM_TX) {
608 									/* Suspend for 3ms and try again due to DSP doorbell busy */
609 									mdelay(3);
610 									status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
611 									if (tempword & FT1000_DB_DPRAM_TX) {
612 										pr_debug("Doorbell not available\n");
613 										result = -ENOTTY;
614 										kfree(dpram_data);
615 										break;
616 									}
617 								}
618 							}
619 						}
620 					}
621 
622 					/*pr_debug("finished reading register\n"); */
623 
624 					/* Make sure we are within the limits of the slow queue memory limitation */
625 					if ((msgsz < MAX_CMD_SQSIZE) && (msgsz > PSEUDOSZ)) {
626 						/* Need to put sequence number plus new checksum for message */
627 						pmsg = (u16 *)&dpram_data->pseudohdr;
628 						ppseudo_hdr = (struct pseudo_hdr *)pmsg;
629 						total_len = msgsz+2;
630 						if (total_len & 0x1)
631 							total_len++;
632 
633 						/* Insert slow queue sequence number */
634 						ppseudo_hdr->seq_num = info->squeseqnum++;
635 						ppseudo_hdr->portsrc = ft1000dev->app_info[app_index].app_id;
636 						/* Calculate new checksum */
637 						ppseudo_hdr->checksum = *pmsg++;
638 						/* pr_debug("checksum = 0x%x\n", ppseudo_hdr->checksum); */
639 						for (i = 1; i < 7; i++) {
640 							ppseudo_hdr->checksum ^= *pmsg++;
641 							/* pr_debug("checksum = 0x%x\n", ppseudo_hdr->checksum); */
642 						}
643 						pmsg++;
644 						ppseudo_hdr = (struct pseudo_hdr *)pmsg;
645 						result = card_send_command(ft1000dev, dpram_data, total_len+2);
646 
647 
648 						ft1000dev->app_info[app_index].nTxMsg++;
649 					} else {
650 						result = -EINVAL;
651 					}
652 				}
653 			}
654 		} else {
655 			pr_debug("Card not ready take messages\n");
656 			result = -EACCES;
657 		}
658 		kfree(dpram_data);
659 
660 	}
661 	break;
662 	case IOCTL_GET_DPRAM_CMD:
663 	{
664 		struct dpram_blk *pdpram_blk;
665 		struct IOCTL_DPRAM_BLK __user *pioctl_dpram;
666 		int msglen;
667 
668 		/* pr_debug("IOCTL_FT1000_GET_DPRAM called\n"); */
669 
670 		if (ft1000_flarion_cnt == 0)
671 			return -EBADF;
672 
673 		/* Search for matching file object */
674 		for (i = 0; i < MAX_NUM_APP; i++) {
675 			if (ft1000dev->app_info[i].fileobject == &file->f_owner) {
676 				/*pr_debug("Message is for AppId = %d\n", ft1000dev->app_info[i].app_id); */
677 				break;
678 			}
679 		}
680 
681 		/* Could not find application info block */
682 		if (i == MAX_NUM_APP) {
683 			pr_debug("Could not find application info block\n");
684 			result = -EBADF;
685 			break;
686 		}
687 
688 		result = 0;
689 		pioctl_dpram = argp;
690 		if (list_empty(&ft1000dev->app_info[i].app_sqlist) == 0) {
691 			/* pr_debug("Message detected in slow queue\n"); */
692 			spin_lock_irqsave(&free_buff_lock, flags);
693 			pdpram_blk = list_entry(ft1000dev->app_info[i].app_sqlist.next, struct dpram_blk, list);
694 			list_del(&pdpram_blk->list);
695 			ft1000dev->app_info[i].NumOfMsg--;
696 			/* pr_debug("NumOfMsg for app %d = %d\n", i, ft1000dev->app_info[i].NumOfMsg); */
697 			spin_unlock_irqrestore(&free_buff_lock, flags);
698 			msglen = ntohs(*(u16 *)pdpram_blk->pbuffer) + PSEUDOSZ;
699 			result = get_user(msglen, &pioctl_dpram->total_len);
700 			if (result)
701 				break;
702 			msglen = htons(msglen);
703 			/* pr_debug("msg length = %x\n", msglen); */
704 			if (copy_to_user(&pioctl_dpram->pseudohdr, pdpram_blk->pbuffer, msglen)) {
705 				pr_debug("copy fault occurred\n");
706 				result = -EFAULT;
707 				break;
708 			}
709 
710 			ft1000_free_buffer(pdpram_blk, &freercvpool);
711 			result = msglen;
712 		}
713 		/* pr_debug("IOCTL_FT1000_GET_DPRAM no message\n"); */
714 	}
715 	break;
716 
717 	default:
718 		pr_debug("unknown command: 0x%x\n", command);
719 		result = -ENOTTY;
720 		break;
721 	}
722 	ft1000dev->fAppMsgPend = false;
723 	return result;
724 }
725 
726 /*
727  *---------------------------------------------------------------------------
728  * Function:    ft1000_release
729  *
730  * Parameters:
731  *
732  * Description:
733  *
734  * Notes:
735  *
736  *---------------------------------------------------------------------------
737  */
ft1000_release(struct inode * inode,struct file * file)738 static int ft1000_release(struct inode *inode, struct file *file)
739 {
740 	struct ft1000_info *info;
741 	struct net_device *dev;
742 	struct ft1000_usb *ft1000dev;
743 	int i;
744 	struct dpram_blk *pdpram_blk;
745 	struct dpram_blk *tmp;
746 
747 	dev = file->private_data;
748 	info = netdev_priv(dev);
749 	ft1000dev = info->priv;
750 
751 	if (ft1000_flarion_cnt == 0) {
752 		ft1000dev->appcnt--;
753 		return -EBADF;
754 	}
755 
756 	/* Search for matching file object */
757 	for (i = 0; i < MAX_NUM_APP; i++) {
758 		if (ft1000dev->app_info[i].fileobject == &file->f_owner) {
759 			/* pr_debug("Message is for AppId = %d\n", ft1000dev->app_info[i].app_id); */
760 			break;
761 		}
762 	}
763 
764 	if (i == MAX_NUM_APP)
765 		return 0;
766 
767 	list_for_each_entry_safe(pdpram_blk, tmp, &ft1000dev->app_info[i].app_sqlist, list) {
768 		pr_debug("Remove and free memory queue up on slow queue\n");
769 		list_del(&pdpram_blk->list);
770 		ft1000_free_buffer(pdpram_blk, &freercvpool);
771 	}
772 
773 	/* initialize application information */
774 	ft1000dev->appcnt--;
775 	pr_debug("appcnt = %d\n", ft1000dev->appcnt);
776 	ft1000dev->app_info[i].fileobject = NULL;
777 
778 	return 0;
779 }
780