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