staging: make new character devices nonseekable
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / staging / ft1000 / ft1000-usb / ft1000_chdev.c
1 //---------------------------------------------------------------------------
2 // FT1000 driver for Flarion Flash OFDM NIC Device
3 //
4 // Copyright (C) 2006 Flarion Technologies, All rights reserved.
5 //
6 // This program is free software; you can redistribute it and/or modify it
7 // under the terms of the GNU General Public License as published by the Free
8 // Software Foundation; either version 2 of the License, or (at your option) any
9 // later version. This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 // or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12 // more details. You should have received a copy of the GNU General Public
13 // License along with this program; if not, write to the
14 // Free Software Foundation, Inc., 59 Temple Place -
15 // Suite 330, Boston, MA 02111-1307, USA.
16 //---------------------------------------------------------------------------
17 //
18 // File:         ft1000_chdev.c
19 //
20 // Description:  Custom character device dispatch routines.
21 //
22 // History:
23 // 8/29/02    Whc                Ported to Linux.
24 // 6/05/06    Whc                Porting to Linux 2.6.9
25 //
26 //---------------------------------------------------------------------------
27 #include <linux/module.h>
28 #include <linux/kernel.h>
29 #include <linux/sched.h>
30 #include <linux/signal.h>
31 #include <linux/errno.h>
32 #include <linux/poll.h>
33 #include <linux/netdevice.h>
34 #include <linux/delay.h>
35
36 #include <linux/fs.h>
37 #include <linux/kmod.h>
38 #include <linux/ioctl.h>
39 #include <linux/unistd.h>
40
41 #include "ft1000_usb.h"
42 //#include "ft1000_ioctl.h"
43
44 void ft1000_DestroyDevice(struct net_device *dev);
45 u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, u8 highlow);
46 u16 ft1000_read_register(struct ft1000_device *ft1000dev, short* Data, u16 nRegIndx);
47
48 extern inline u16 ft1000_asic_read (struct net_device *dev, u16 offset);
49 extern inline void ft1000_asic_write (struct net_device *dev, u16 offset, u16 value);
50 extern void CardSendCommand(struct ft1000_device *ft1000dev, unsigned short *ptempbuffer, int size);
51
52 static int ft1000_ChOpen (struct inode *Inode, struct file *File);
53 static unsigned int ft1000_ChPoll(struct file *file, poll_table *wait);
54 static int ft1000_ChIoctl(struct file *File, unsigned int Command,
55                            unsigned long Argument);
56 static int ft1000_ChRelease (struct inode *Inode, struct file *File);
57
58 static int ft1000_flarion_cnt = 0;
59
60 //need to looking usage of ft1000Handle
61
62
63
64 // Global pointer to device object
65 static struct ft1000_device *pdevobj[MAX_NUM_CARDS + 2];
66 //static devfs_handle_t ft1000Handle[MAX_NUM_CARDS];
67
68 // List to free receive command buffer pool
69 struct list_head freercvpool;
70
71 // lock to arbitrate free buffer list for receive command data
72 spinlock_t free_buff_lock;
73
74 int numofmsgbuf = 0;
75
76 // Global variable to indicate that all provisioning data is sent to DSP
77 //BOOLEAN fProvComplete;
78
79 //
80 // Table of entry-point routines for char device
81 //
82 static struct file_operations ft1000fops =
83 {
84         .unlocked_ioctl = ft1000_ChIoctl,
85         .poll           = ft1000_ChPoll,
86         .open           = ft1000_ChOpen,
87         .release        = ft1000_ChRelease,
88         .llseek         = no_llseek,
89 };
90
91
92
93
94 //---------------------------------------------------------------------------
95 // Function:    exec_mknod
96 //
97 // Parameters:
98 //
99 // Returns:
100 //
101 // Description:
102 //
103 // Notes:
104 //
105 //---------------------------------------------------------------------------
106 static int exec_mknod (void *pdata)
107 {
108     PFT1000_INFO info;
109     char mjnum[4];
110     char minornum[4];
111     char temp[32];
112     int retcode;
113 //    int i;                                    //aelias [-] reason : unused variable
114     char *envp[] = { "HOME=/", "PATH=/usr/bin:/bin", NULL };
115     char *argv[]={"-m 666",temp,"c",mjnum,minornum,NULL};
116
117     info = pdata;
118     DEBUG("ft1000_chdev:exec_mknod is called with major number = %d\n", info->DeviceMajor);
119     sprintf(temp, "%s%s", "/dev/", info->DeviceName) ;
120     sprintf(mjnum, "%d", info->DeviceMajor);
121     sprintf(minornum, "%d", info->CardNumber);
122
123     //char *argv[]={"mknod","-m 666",temp,"c",mjnum,minornum,NULL};
124 //    char *argv[]={"-m 666",temp,"c",mjnum,minornum,NULL};
125
126     //for (i=0; i<7;i++)
127     //    DEBUG("argv[%d]=%s\n", i, argv[i]);
128
129
130     retcode = call_usermodehelper ("/bin/mknod", argv, envp, 1);
131     if (retcode) {
132         DEBUG("ft1000_chdev:exec_mknod failed to make the node: retcode = %d\n", retcode);
133     }
134
135
136
137     return retcode;
138
139 }
140
141 //---------------------------------------------------------------------------
142 // Function:    rm_mknod
143 //
144 // Description: This module removes the FT1000 device file
145 //
146 //---------------------------------------------------------------------------
147 static int rm_mknod (void *pdata)
148 {
149
150     PFT1000_INFO info;
151     //char *argv[4]={"rm", "-f", "/dev/FT1000", NULL};
152     int retcode;
153     char temp[32];
154     char *argv[]={"rm", "-f", temp, NULL};
155
156     info = (PFT1000_INFO)pdata;
157     DEBUG("ft1000_chdev:rm_mknod is called for device %s\n", info->DeviceName);
158     sprintf(temp, "%s%s", "/dev/", info->DeviceName) ;
159
160 //    char *argv[]={"rm", "-f", temp, NULL};
161
162     retcode = call_usermodehelper ("/bin/rm", argv, NULL, 1);
163     if (retcode) {
164         DEBUG("ft1000_chdev:rm_mknod failed to remove the node: retcode = %d\n", retcode);
165     }
166     else
167         DEBUG("ft1000_chdev:rm_mknod done!\n");
168
169
170     return retcode;
171
172 }
173 //---------------------------------------------------------------------------
174 // Function:    ft1000_get_buffer
175 //
176 // Parameters:
177 //
178 // Returns:
179 //
180 // Description:
181 //
182 // Notes:
183 //
184 //---------------------------------------------------------------------------
185 PDPRAM_BLK ft1000_get_buffer (struct list_head *bufflist)
186 {
187     unsigned long flags;
188     PDPRAM_BLK ptr;
189
190     spin_lock_irqsave(&free_buff_lock, flags);
191     // Check if buffer is available
192     if ( list_empty(bufflist) ) {
193         DEBUG("ft1000_get_buffer:  No more buffer - %d\n", numofmsgbuf);
194         ptr = NULL;
195     }
196     else {
197         numofmsgbuf--;
198         ptr = list_entry(bufflist->next, DPRAM_BLK, list);
199         list_del(&ptr->list);
200         //DEBUG("ft1000_get_buffer: number of free msg buffers = %d\n", numofmsgbuf);
201     }
202     spin_unlock_irqrestore(&free_buff_lock, flags);
203
204     return ptr;
205 }
206
207
208
209
210 //---------------------------------------------------------------------------
211 // Function:    ft1000_free_buffer
212 //
213 // Parameters:
214 //
215 // Returns:
216 //
217 // Description:
218 //
219 // Notes:
220 //
221 //---------------------------------------------------------------------------
222 void ft1000_free_buffer (PDPRAM_BLK pdpram_blk, struct list_head *plist)
223 {
224     unsigned long flags;
225
226     spin_lock_irqsave(&free_buff_lock, flags);
227     // Put memory back to list
228     list_add_tail(&pdpram_blk->list, plist);
229     numofmsgbuf++;
230     //DEBUG("ft1000_free_buffer: number of free msg buffers = %d\n", numofmsgbuf);
231     spin_unlock_irqrestore(&free_buff_lock, flags);
232 }
233
234 //---------------------------------------------------------------------------
235 // Function:    ft1000_CreateDevice
236 //
237 // Parameters:  dev - pointer to adapter object
238 //
239 // Returns:     0 if successful
240 //
241 // Description: Creates a private char device.
242 //
243 // Notes:       Only called by init_module().
244 //
245 //---------------------------------------------------------------------------
246 int ft1000_CreateDevice(struct ft1000_device *dev)
247 {
248     PFT1000_INFO info = netdev_priv(dev->net);
249     int result;
250     int i;
251     pid_t pid;
252
253     // make a new device name
254     sprintf(info->DeviceName, "%s%d", "FT100", info->CardNumber);
255
256     // Delete any existing FT1000 node
257     pid = kernel_thread (rm_mknod,(void *)info, 0);
258     msleep(1000);
259
260     DEBUG("ft1000_CreateDevice: number of instance = %d\n", ft1000_flarion_cnt);
261     DEBUG("DeviceCreated = %x\n", info->DeviceCreated);
262
263     //save the device info to global array
264     pdevobj[info->CardNumber] = dev;
265
266     DEBUG("ft1000_CreateDevice: ******SAVED pdevobj[%d]=%x\n", info->CardNumber, (unsigned int)pdevobj[info->CardNumber]);      //aelias [+] reason:up
267
268     if (info->DeviceCreated)
269     {
270         DEBUG("ft1000_CreateDevice: \"%s\" already registered\n", info->DeviceName);
271         return -EIO;
272     }
273
274
275     // register the device
276     DEBUG("ft1000_CreateDevice: \"%s\" device registration\n", info->DeviceName);
277     info->DeviceMajor = 0;
278
279     result = register_chrdev(info->DeviceMajor, info->DeviceName, &ft1000fops);
280     if (result < 0)
281     {
282         DEBUG("ft1000_CreateDevice: unable to get major %d\n", info->DeviceMajor);
283         return result;
284     }
285
286     DEBUG("ft1000_CreateDevice: registered char device \"%s\"\n", info->DeviceName);
287
288     // save a dynamic device major number
289     if (info->DeviceMajor == 0)
290     {
291         info->DeviceMajor = result;
292         DEBUG("ft1000_PcdCreateDevice: device major = %d\n", info->DeviceMajor);
293     }
294
295     // Create a thread to call user mode app to mknod
296     pid = kernel_thread (exec_mknod, (void *)info, 0);
297
298     // initialize application information
299     info->appcnt = 0;
300
301 //    if (ft1000_flarion_cnt == 0) {
302 //
303 //        DEBUG("Initialize free_buff_lock and freercvpool\n");
304 //        spin_lock_init(&free_buff_lock);
305 //
306 //        // initialize a list of buffers to be use for queuing up receive command data
307 //        INIT_LIST_HEAD (&freercvpool);
308 //
309 //        // create list of free buffers
310 //        for (i=0; i<NUM_OF_FREE_BUFFERS; i++) {
311 //            // Get memory for DPRAM_DATA link list
312 //            pdpram_blk = kmalloc ( sizeof(DPRAM_BLK), GFP_KERNEL );
313 //            // Get a block of memory to store command data
314 //            pdpram_blk->pbuffer = kmalloc ( MAX_CMD_SQSIZE, GFP_KERNEL );
315 //            // link provisioning data
316 //            list_add_tail (&pdpram_blk->list, &freercvpool);
317 //        }
318 //        numofmsgbuf = NUM_OF_FREE_BUFFERS;
319 //    }
320
321
322     // initialize application information
323     info->appcnt = 0;
324     for (i=0; i<MAX_NUM_APP; i++) {
325         info->app_info[i].nTxMsg = 0;
326         info->app_info[i].nRxMsg = 0;
327         info->app_info[i].nTxMsgReject = 0;
328         info->app_info[i].nRxMsgMiss = 0;
329         info->app_info[i].fileobject = 0;
330         info->app_info[i].app_id = i+1;
331         info->app_info[i].DspBCMsgFlag = 0;
332         info->app_info[i].NumOfMsg = 0;
333         init_waitqueue_head(&info->app_info[i].wait_dpram_msg);
334         INIT_LIST_HEAD (&info->app_info[i].app_sqlist);
335     }
336
337
338
339
340 //    ft1000Handle[info->CardNumber] = devfs_register(NULL, info->DeviceName, DEVFS_FL_AUTO_DEVNUM, 0, 0,
341 //                                  S_IFCHR | S_IRUGO | S_IWUGO, &ft1000fops, NULL);
342
343
344     info->DeviceCreated = TRUE;
345     ft1000_flarion_cnt++;
346
347     return result;
348 }
349
350 //---------------------------------------------------------------------------
351 // Function:    ft1000_DestroyDeviceDEBUG
352 //
353 // Parameters:  dev - pointer to adapter object
354 //
355 // Description: Destroys a private char device.
356 //
357 // Notes:       Only called by cleanup_module().
358 //
359 //---------------------------------------------------------------------------
360 void ft1000_DestroyDevice(struct net_device *dev)
361 {
362     PFT1000_INFO info = netdev_priv(dev);
363     int result = 0;
364     pid_t pid;
365                 int i;
366     PDPRAM_BLK pdpram_blk;
367     DPRAM_BLK *ptr;
368
369     DEBUG("ft1000_chdev:ft1000_DestroyDevice called\n");
370
371
372
373     if (info->DeviceCreated)
374         {
375         ft1000_flarion_cnt--;
376                 unregister_chrdev(info->DeviceMajor, info->DeviceName);
377                 DEBUG("ft1000_DestroyDevice: unregistered device \"%s\", result = %d\n",
378                                            info->DeviceName, result);
379
380        pid = kernel_thread (rm_mknod, (void *)info, 0);
381
382         // Make sure we free any memory reserve for slow Queue
383         for (i=0; i<MAX_NUM_APP; i++) {
384             while (list_empty(&info->app_info[i].app_sqlist) == 0) {
385                 pdpram_blk = list_entry(info->app_info[i].app_sqlist.next, DPRAM_BLK, list);
386                 list_del(&pdpram_blk->list);
387                 ft1000_free_buffer(pdpram_blk, &freercvpool);
388
389             }
390             wake_up_interruptible(&info->app_info[i].wait_dpram_msg);
391         }
392
393         // Remove buffer allocated for receive command data
394         if (ft1000_flarion_cnt == 0) {
395             while (list_empty(&freercvpool) == 0) {
396                 ptr = list_entry(freercvpool.next, DPRAM_BLK, list);
397                 list_del(&ptr->list);
398                 kfree(ptr->pbuffer);
399                 kfree(ptr);
400             }
401         }
402
403 //        devfs_unregister(ft1000Handle[info->CardNumber]);
404
405                 info->DeviceCreated = FALSE;
406
407                 pdevobj[info->CardNumber] = NULL;
408         }
409
410
411 }
412
413 //---------------------------------------------------------------------------
414 // Function:    ft1000_ChOpen
415 //
416 // Parameters:
417 //
418 // Description:
419 //
420 // Notes:
421 //
422 //---------------------------------------------------------------------------
423 static int ft1000_ChOpen (struct inode *Inode, struct file *File)
424 {
425     PFT1000_INFO info;
426     int i,num;
427
428     DEBUG("ft1000_ChOpen called\n");
429     num = (MINOR(Inode->i_rdev) & 0xf);
430     DEBUG("ft1000_ChOpen: minor number=%d\n", num);
431
432     for (i=0; i<5; i++)
433         DEBUG("pdevobj[%d]=%x\n", i, (unsigned int)pdevobj[i]); //aelias [+] reason: down
434
435     if ( pdevobj[num] != NULL )
436         //info = (PFT1000_INFO)(pdevobj[num]->net->priv);
437         info = (FT1000_INFO *) netdev_priv (pdevobj[num]->net);
438     else
439     {
440         DEBUG("ft1000_ChOpen: can not find device object %d\n", num);
441         return -1;
442     }
443
444     DEBUG("f_owner = 0x%8x number of application = %d\n", (u32)(&File->f_owner), info->appcnt );
445
446     // Check if maximum number of application exceeded
447     if (info->appcnt > MAX_NUM_APP) {
448         DEBUG("Maximum number of application exceeded\n");
449         return -EACCES;
450     }
451
452     // Search for available application info block
453     for (i=0; i<MAX_NUM_APP; i++) {
454         if ( (info->app_info[i].fileobject == 0) ) {
455             break;
456         }
457     }
458
459     // Fail due to lack of application info block
460     if (i == MAX_NUM_APP) {
461         DEBUG("Could not find an application info block\n");
462         return -EACCES;
463     }
464
465     info->appcnt++;
466     info->app_info[i].fileobject = (u32)(&File->f_owner);
467     info->app_info[i].nTxMsg = 0;
468     info->app_info[i].nRxMsg = 0;
469     info->app_info[i].nTxMsgReject = 0;
470     info->app_info[i].nRxMsgMiss = 0;
471
472     File->private_data = pdevobj[num]->net;
473
474         nonseekable_open(Inode, File);
475     return 0;
476 }
477
478
479 //---------------------------------------------------------------------------
480 // Function:    ft1000_ChPoll
481 //
482 // Parameters:
483 //
484 // Description:
485 //
486 // Notes:
487 //
488 //---------------------------------------------------------------------------
489
490 static unsigned int ft1000_ChPoll(struct file *file, poll_table *wait)
491 {
492     struct net_device *dev = file->private_data;
493     PFT1000_INFO info;
494     int i;
495
496     //DEBUG("ft1000_ChPoll called\n");
497     if (ft1000_flarion_cnt == 0) {
498         DEBUG("FT1000:ft1000_ChPoll called when ft1000_flarion_cnt is zero\n");
499         return (-EBADF);
500     }
501
502         info = (FT1000_INFO *) netdev_priv (dev);
503
504     // Search for matching file object
505     for (i=0; i<MAX_NUM_APP; i++) {
506         if ( info->app_info[i].fileobject == (u32)(&file->f_owner) ) {
507             //DEBUG("FT1000:ft1000_ChIoctl: Message is for AppId = %d\n", info->app_info[i].app_id);
508             break;
509         }
510     }
511
512     // Could not find application info block
513     if (i == MAX_NUM_APP) {
514         DEBUG("FT1000:ft1000_ChIoctl:Could not find application info block\n");
515         return ( -EACCES );
516     }
517
518     if (list_empty(&info->app_info[i].app_sqlist) == 0) {
519         DEBUG("FT1000:ft1000_ChPoll:Message detected in slow queue\n");
520         return(POLLIN | POLLRDNORM | POLLPRI);
521     }
522
523     poll_wait (file, &info->app_info[i].wait_dpram_msg, wait);
524     //DEBUG("FT1000:ft1000_ChPoll:Polling for data from DSP\n");
525
526     return (0);
527 }
528
529 //---------------------------------------------------------------------------
530 // Function:    ft1000_ChIoctl
531 //
532 // Parameters:
533 //
534 // Description:
535 //
536 // Notes:
537 //
538 //---------------------------------------------------------------------------
539 static int ft1000_ChIoctl (struct file *File, unsigned int Command,
540                            unsigned long Argument)
541 {
542     struct net_device *dev;
543     PFT1000_INFO info;
544     struct ft1000_device *ft1000dev;
545     int result=0;
546     int cmd;
547     int i;
548     u16 tempword;
549     unsigned long flags;
550     struct timeval tv;
551     IOCTL_GET_VER get_ver_data;
552     IOCTL_GET_DSP_STAT get_stat_data;
553     u8 ConnectionMsg[] = {0x00,0x44,0x10,0x20,0x80,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x93,0x64,
554                           0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x0a,
555                           0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
556                           0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
557                           0x00,0x00,0x02,0x37,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x01,0x7f,0x00,
558                           0x00,0x01,0x00,0x00};
559
560     unsigned short ledStat=0;
561     unsigned short conStat=0;
562
563     //DEBUG("ft1000_ChIoctl called\n");
564
565     if (ft1000_flarion_cnt == 0) {
566         DEBUG("FT1000:ft1000_ChIoctl called when ft1000_flarion_cnt is zero\n");
567         return (-EBADF);
568     }
569
570     //DEBUG("FT1000:ft1000_ChIoctl:Command = 0x%x Argument = 0x%8x\n", Command, (u32)Argument);
571
572     dev = File->private_data;
573         info = (FT1000_INFO *) netdev_priv (dev);
574     ft1000dev = info->pFt1000Dev;
575     cmd = _IOC_NR(Command);
576     //DEBUG("FT1000:ft1000_ChIoctl:cmd = 0x%x\n", cmd);
577
578     // process the command
579     switch (cmd) {
580     case IOCTL_REGISTER_CMD:
581             DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_REGISTER called\n");
582             result = get_user(tempword, (unsigned short *)Argument);
583             if (result) {
584                 DEBUG("result = %d failed to get_user\n", result);
585                 break;
586             }
587             if (tempword == DSPBCMSGID) {
588                 // Search for matching file object
589                 for (i=0; i<MAX_NUM_APP; i++) {
590                     if ( info->app_info[i].fileobject == (u32)(&File->f_owner) ) {
591                         info->app_info[i].DspBCMsgFlag = 1;
592                         DEBUG("FT1000:ft1000_ChIoctl:Registered for broadcast messages\n");
593                         break;
594                     }
595                 }
596             }
597             break;
598
599     case IOCTL_GET_VER_CMD:
600         DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_GET_VER called\n");
601
602         get_ver_data.drv_ver = FT1000_DRV_VER;
603
604         if (copy_to_user((PIOCTL_GET_VER)Argument, &get_ver_data, sizeof(get_ver_data)) ) {
605             DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n");
606             result = -EFAULT;
607             break;
608         }
609
610         DEBUG("FT1000:ft1000_ChIoctl:driver version = 0x%x\n",(unsigned int)get_ver_data.drv_ver);
611
612         break;
613     case IOCTL_CONNECT:
614         // Connect Message
615         DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_CONNECT\n");
616         ConnectionMsg[79] = 0xfc;
617                            CardSendCommand(ft1000dev, (unsigned short *)ConnectionMsg, 0x4c);
618
619         break;
620     case IOCTL_DISCONNECT:
621         // Disconnect Message
622         DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_DISCONNECT\n");
623         ConnectionMsg[79] = 0xfd;
624                            CardSendCommand(ft1000dev, (unsigned short *)ConnectionMsg, 0x4c);
625         break;
626     case IOCTL_GET_DSP_STAT_CMD:
627         //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_GET_DSP_STAT called\n");
628
629         memcpy(get_stat_data.DspVer, info->DspVer, DSPVERSZ);
630         memcpy(get_stat_data.HwSerNum, info->HwSerNum, HWSERNUMSZ);
631         memcpy(get_stat_data.Sku, info->Sku, SKUSZ);
632         memcpy(get_stat_data.eui64, info->eui64, EUISZ);
633
634             if (info->ProgConStat != 0xFF) {
635                 ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_LED, (PUCHAR)&ledStat, FT1000_MAG_DSP_LED_INDX);
636                 get_stat_data.LedStat = ntohs(ledStat);
637                 DEBUG("FT1000:ft1000_ChIoctl: LedStat = 0x%x\n", get_stat_data.LedStat);
638                 ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_CON_STATE, (PUCHAR)&conStat, FT1000_MAG_DSP_CON_STATE_INDX);
639                 get_stat_data.ConStat = ntohs(conStat);
640                 DEBUG("FT1000:ft1000_ChIoctl: ConStat = 0x%x\n", get_stat_data.ConStat);
641             }
642             else {
643                 get_stat_data.ConStat = 0x0f;
644             }
645
646
647         get_stat_data.nTxPkts = info->stats.tx_packets;
648         get_stat_data.nRxPkts = info->stats.rx_packets;
649         get_stat_data.nTxBytes = info->stats.tx_bytes;
650         get_stat_data.nRxBytes = info->stats.rx_bytes;
651         do_gettimeofday ( &tv );
652         get_stat_data.ConTm = (u32)(tv.tv_sec - info->ConTm);
653         DEBUG("Connection Time = %d\n", (int)get_stat_data.ConTm);
654         if (copy_to_user((PIOCTL_GET_DSP_STAT)Argument, &get_stat_data, sizeof(get_stat_data)) ) {
655             DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n");
656             result = -EFAULT;
657             break;
658         }
659         DEBUG("ft1000_chioctl: GET_DSP_STAT succeed\n");
660         break;
661     case IOCTL_SET_DPRAM_CMD:
662         {
663             IOCTL_DPRAM_BLK dpram_data;
664             //IOCTL_DPRAM_COMMAND dpram_command;
665             USHORT qtype;
666             USHORT msgsz;
667             PPSEUDO_HDR ppseudo_hdr;
668             PUSHORT pmsg;
669             USHORT total_len;
670             USHORT app_index;
671             u16 status;
672
673             //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_SET_DPRAM called\n");
674
675
676             if (ft1000_flarion_cnt == 0) {
677                 return (-EBADF);
678             }
679
680             if (info->DrvMsgPend) {
681                 return (-ENOTTY);
682             }
683
684             if ( (info->DspAsicReset) || (info->fProvComplete == 0) ) {
685                 return (-EACCES);
686             }
687
688             info->fAppMsgPend = 1;
689
690             if (info->CardReady) {
691
692                //DEBUG("FT1000:ft1000_ChIoctl: try to SET_DPRAM \n");
693
694                 // Get the length field to see how many bytes to copy
695                 result = get_user(msgsz, (unsigned short *)Argument);
696                 msgsz = ntohs (msgsz);
697                 //DEBUG("FT1000:ft1000_ChIoctl: length of message = %d\n", msgsz);
698
699                 if (msgsz > MAX_CMD_SQSIZE) {
700                     DEBUG("FT1000:ft1000_ChIoctl: bad message length = %d\n", msgsz);
701                     result = -EINVAL;
702                     break;
703                 }
704
705                 //if ( copy_from_user(&(dpram_command.dpram_blk), (PIOCTL_DPRAM_BLK)Argument, msgsz+2) ) {
706                 if ( copy_from_user(&dpram_data, (PIOCTL_DPRAM_BLK)Argument, msgsz+2) ) {
707                     DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n");
708                     result = -EFAULT;
709                 }
710                 else {
711 #if 0
712                     // whc - for debugging only
713                     ptr = (char *)&dpram_data;
714                     for (i=0; i<msgsz; i++) {
715                         DEBUG(1,"FT1000:ft1000_ChIoctl: data %d = 0x%x\n", i, *ptr++);
716                     }
717 #endif
718                     // Check if this message came from a registered application
719                     for (i=0; i<MAX_NUM_APP; i++) {
720                         if ( info->app_info[i].fileobject == (u32)(&File->f_owner) ) {
721                             break;
722                         }
723                     }
724                     if (i==MAX_NUM_APP) {
725                         DEBUG("FT1000:No matching application fileobject\n");
726                         result = -EINVAL;
727                         break;
728                     }
729                     app_index = i;
730
731                     // Check message qtype type which is the lower byte within qos_class
732                     //qtype = ntohs(dpram_command.dpram_blk.pseudohdr.qos_class) & 0xff;
733                     qtype = ntohs(dpram_data.pseudohdr.qos_class) & 0xff;
734                     //DEBUG("FT1000_ft1000_ChIoctl: qtype = %d\n", qtype);
735                     if (qtype) {
736                     }
737                     else {
738                         // Put message into Slow Queue
739                         // Only put a message into the DPRAM if msg doorbell is available
740                         status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
741                         //DEBUG("FT1000_ft1000_ChIoctl: READ REGISTER tempword=%x\n", tempword);
742                         if (tempword & FT1000_DB_DPRAM_TX) {
743                             // Suspend for 2ms and try again due to DSP doorbell busy
744                             mdelay(2);
745                             status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
746                             if (tempword & FT1000_DB_DPRAM_TX) {
747                                 // Suspend for 1ms and try again due to DSP doorbell busy
748                                 mdelay(1);
749                                 status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
750                                 if (tempword & FT1000_DB_DPRAM_TX) {
751                                     status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
752                                     if (tempword & FT1000_DB_DPRAM_TX) {
753                                         // Suspend for 3ms and try again due to DSP doorbell busy
754                                         mdelay(3);
755                                         status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
756                                         if (tempword & FT1000_DB_DPRAM_TX) {
757                                             DEBUG("FT1000:ft1000_ChIoctl:Doorbell not available\n");
758                                             result = -ENOTTY;
759                                             break;
760                                         }
761                                     }
762                                 }
763                             }
764                         }
765
766                         //DEBUG("FT1000_ft1000_ChIoctl: finished reading register\n");
767
768                         // Make sure we are within the limits of the slow queue memory limitation
769                         if ( (msgsz < MAX_CMD_SQSIZE) && (msgsz > PSEUDOSZ) ) {
770                             // Need to put sequence number plus new checksum for message
771                             //pmsg = (PUSHORT)&dpram_command.dpram_blk.pseudohdr;
772                             pmsg = (PUSHORT)&dpram_data.pseudohdr;
773                             ppseudo_hdr = (PPSEUDO_HDR)pmsg;
774                             total_len = msgsz+2;
775                             if (total_len & 0x1) {
776                                 total_len++;
777                             }
778
779                             // Insert slow queue sequence number
780                             ppseudo_hdr->seq_num = info->squeseqnum++;
781                             ppseudo_hdr->portsrc = info->app_info[app_index].app_id;
782                             // Calculate new checksum
783                             ppseudo_hdr->checksum = *pmsg++;
784                             //DEBUG("checksum = 0x%x\n", ppseudo_hdr->checksum);
785                             for (i=1; i<7; i++) {
786                                 ppseudo_hdr->checksum ^= *pmsg++;
787                                 //DEBUG("checksum = 0x%x\n", ppseudo_hdr->checksum);
788                             }
789                             pmsg++;
790                             ppseudo_hdr = (PPSEUDO_HDR)pmsg;
791 #if 0
792                             ptr = (char *)&dpram_data;
793                             DEBUG("FT1000:ft1000_ChIoctl: Command Send\n");
794                             for (i=0; i<total_len; i++) {
795                                 DEBUG("FT1000:ft1000_ChIoctl: data %d = 0x%x\n", i, *ptr++);
796                             }
797 #endif
798                             //dpram_command.extra = 0;
799
800                             //CardSendCommand(ft1000dev,(unsigned char*)&dpram_command,total_len+2);
801                             CardSendCommand(ft1000dev,(unsigned short*)&dpram_data,total_len+2);
802
803
804                             info->app_info[app_index].nTxMsg++;
805                             break;
806                         }
807                         else {
808                             result = -EINVAL;
809                             break;
810                         }
811                     }
812                 }
813             }
814             else {
815                 DEBUG("FT1000:ft1000_ChIoctl: Card not ready take messages\n");
816                 result = -EACCES;
817             }
818
819         }
820         break;
821     case IOCTL_GET_DPRAM_CMD:
822         {
823             PDPRAM_BLK pdpram_blk;
824             PIOCTL_DPRAM_BLK pioctl_dpram;
825             int msglen;
826
827             //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_GET_DPRAM called\n");
828
829             if (ft1000_flarion_cnt == 0) {
830                 return (-EBADF);
831             }
832
833             // Search for matching file object
834             for (i=0; i<MAX_NUM_APP; i++) {
835                 if ( info->app_info[i].fileobject == (u32)(&File->f_owner) ) {
836                     //DEBUG("FT1000:ft1000_ChIoctl: Message is for AppId = %d\n", info->app_info[i].app_id);
837                     break;
838                 }
839             }
840
841             // Could not find application info block
842             if (i == MAX_NUM_APP) {
843                 DEBUG("FT1000:ft1000_ChIoctl:Could not find application info block\n");
844                 result = -EBADF;
845                 break;
846             }
847
848             result = 0;
849             pioctl_dpram = (PIOCTL_DPRAM_BLK)Argument;
850             if (list_empty(&info->app_info[i].app_sqlist) == 0) {
851                 //DEBUG("FT1000:ft1000_ChIoctl:Message detected in slow queue\n");
852                 spin_lock_irqsave(&free_buff_lock, flags);
853                 pdpram_blk = list_entry(info->app_info[i].app_sqlist.next, DPRAM_BLK, list);
854                 list_del(&pdpram_blk->list);
855                 info->app_info[i].NumOfMsg--;
856                 //DEBUG("FT1000:ft1000_ChIoctl:NumOfMsg for app %d = %d\n", i, info->app_info[i].NumOfMsg);
857                 spin_unlock_irqrestore(&free_buff_lock, flags);
858                 msglen = ntohs(*(u16 *)pdpram_blk->pbuffer) + PSEUDOSZ;
859                 pioctl_dpram->total_len = htons(msglen);
860                 //DEBUG("FT1000:ft1000_ChIoctl:msg length = %x\n", msglen);
861                 if(copy_to_user (&pioctl_dpram->pseudohdr, pdpram_blk->pbuffer, msglen))
862                                 {
863                                         DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n");
864                         result = -EFAULT;
865                         break;
866                                 }
867
868                 ft1000_free_buffer(pdpram_blk, &freercvpool);
869                 result = msglen;
870             }
871             //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_GET_DPRAM no message\n");
872         }
873         break;
874
875     default:
876         DEBUG("FT1000:ft1000_ChIoctl:unknown command: 0x%x\n", Command);
877         result = -ENOTTY;
878         break;
879     }
880     info->fAppMsgPend = 0;
881     return result;
882 }
883
884 //---------------------------------------------------------------------------
885 // Function:    ft1000_ChRelease
886 //
887 // Parameters:
888 //
889 // Description:
890 //
891 // Notes:
892 //
893 //---------------------------------------------------------------------------
894 static int ft1000_ChRelease (struct inode *Inode, struct file *File)
895 {
896     PFT1000_INFO info;
897     struct net_device *dev;
898     int i;
899     PDPRAM_BLK pdpram_blk;
900
901     DEBUG("ft1000_ChRelease called\n");
902
903     dev = File->private_data;
904         info = (FT1000_INFO *) netdev_priv (dev);
905
906     if (ft1000_flarion_cnt == 0) {
907         info->appcnt--;
908         return (-EBADF);
909     }
910
911     // Search for matching file object
912     for (i=0; i<MAX_NUM_APP; i++) {
913         if ( info->app_info[i].fileobject == (u32)(&File->f_owner) ) {
914             //DEBUG("FT1000:ft1000_ChIoctl: Message is for AppId = %d\n", info->app_info[i].app_id);
915             break;
916         }
917     }
918
919     if (i==MAX_NUM_APP)
920             return 0;
921
922     while (list_empty(&info->app_info[i].app_sqlist) == 0) {
923         DEBUG("Remove and free memory queue up on slow queue\n");
924         pdpram_blk = list_entry(info->app_info[i].app_sqlist.next, DPRAM_BLK, list);
925         list_del(&pdpram_blk->list);
926         ft1000_free_buffer(pdpram_blk, &freercvpool);
927     }
928
929     // initialize application information
930     info->appcnt--;
931     DEBUG("ft1000_chdev:%s:appcnt = %d\n", __FUNCTION__, info->appcnt);
932     info->app_info[i].fileobject = 0;
933
934     return 0;
935 }
936