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