blob: 1d4cd01d46851027776fac05f92c88f91dbb883d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * hfc_usb.c
3 *
Martin Bachem7441dd12007-10-14 18:10:30 +02004 * $Id: hfc_usb.c,v 2.3.2.24 2007/10/14 08:40:29 mbachem Exp $
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
6 * modular HiSax ISDN driver for Colognechip HFC-S USB chip
7 *
Martin Bachemd6c59c12007-08-21 14:26:21 +02008 * Authors : Peter Sprenger (sprenger@moving-bytes.de)
9 * Martin Bachem (m.bachem@gmx.de, info@colognechip.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * based on the first hfc_usb driver of
12 * Werner Cornelius (werner@isdn-development.de)
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2, or (at your option)
17 * any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 *
28 * See Version Histroy at the bottom of this file
29 *
Joe Perches475be4d2012-02-19 19:52:38 -080030 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#include <linux/types.h>
33#include <linux/stddef.h>
34#include <linux/timer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/init.h>
36#include <linux/module.h>
37#include <linux/kernel_stat.h>
38#include <linux/usb.h>
39#include <linux/kernel.h>
Martin Bachemd6c59c12007-08-21 14:26:21 +020040#include <linux/sched.h>
41#include <linux/moduleparam.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090042#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include "hisax.h"
44#include "hisax_if.h"
45#include "hfc_usb.h"
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047static const char *hfcusb_revision =
Joe Perches475be4d2012-02-19 19:52:38 -080048 "$Revision: 2.3.2.24 $ $Date: 2007/10/14 08:40:29 $ ";
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50/* Hisax debug support
Joe Perches475be4d2012-02-19 19:52:38 -080051 * debug flags defined in hfc_usb.h as HFCUSB_DBG_[*]
52 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#define __debug_variable hfc_debug
54#include "hisax_debug.h"
55static u_int debug;
56module_param(debug, uint, 0);
Adrian Bunk672c3fd2005-06-25 14:59:18 -070057static int hfc_debug;
Martin Bachemd6c59c12007-08-21 14:26:21 +020058
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Martin Bachem597a1072005-11-07 01:00:20 -080060/* private vendor specific data */
61typedef struct {
62 __u8 led_scheme; // led display scheme
63 signed short led_bits[8]; // array of 8 possible LED bitmask settings
64 char *vend_name; // device name
65} hfcsusb_vdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Martin Bachemd6c59c12007-08-21 14:26:21 +020067/* VID/PID device list */
Arvind Yadav585f46a2017-08-08 22:19:27 +053068static const struct usb_device_id hfcusb_idtab[] = {
Martin Bachem597a1072005-11-07 01:00:20 -080069 {
Joe Perches475be4d2012-02-19 19:52:38 -080070 USB_DEVICE(0x0959, 0x2bd0),
71 .driver_info = (unsigned long) &((hfcsusb_vdata)
72 {LED_OFF, {4, 0, 2, 1},
73 "ISDN USB TA (Cologne Chip HFC-S USB based)"}),
Martin Bachem597a1072005-11-07 01:00:20 -080074 },
75 {
Joe Perches475be4d2012-02-19 19:52:38 -080076 USB_DEVICE(0x0675, 0x1688),
77 .driver_info = (unsigned long) &((hfcsusb_vdata)
78 {LED_SCHEME1, {1, 2, 0, 0},
79 "DrayTek miniVigor 128 USB ISDN TA"}),
Martin Bachem597a1072005-11-07 01:00:20 -080080 },
81 {
Joe Perches475be4d2012-02-19 19:52:38 -080082 USB_DEVICE(0x07b0, 0x0007),
83 .driver_info = (unsigned long) &((hfcsusb_vdata)
84 {LED_SCHEME1, {0x80, -64, -32, -16},
85 "Billion tiny USB ISDN TA 128"}),
Martin Bachem597a1072005-11-07 01:00:20 -080086 },
87 {
Joe Perches475be4d2012-02-19 19:52:38 -080088 USB_DEVICE(0x0742, 0x2008),
89 .driver_info = (unsigned long) &((hfcsusb_vdata)
90 {LED_SCHEME1, {4, 0, 2, 1},
91 "Stollmann USB TA"}),
Martin Bachemd6c59c12007-08-21 14:26:21 +020092 },
Martin Bachem597a1072005-11-07 01:00:20 -080093 {
Joe Perches475be4d2012-02-19 19:52:38 -080094 USB_DEVICE(0x0742, 0x2009),
95 .driver_info = (unsigned long) &((hfcsusb_vdata)
96 {LED_SCHEME1, {4, 0, 2, 1},
97 "Aceex USB ISDN TA"}),
Martin Bachemd6c59c12007-08-21 14:26:21 +020098 },
Martin Bachem597a1072005-11-07 01:00:20 -080099 {
Joe Perches475be4d2012-02-19 19:52:38 -0800100 USB_DEVICE(0x0742, 0x200A),
101 .driver_info = (unsigned long) &((hfcsusb_vdata)
102 {LED_SCHEME1, {4, 0, 2, 1},
103 "OEM USB ISDN TA"}),
Martin Bachemd6c59c12007-08-21 14:26:21 +0200104 },
Martin Bachem597a1072005-11-07 01:00:20 -0800105 {
Joe Perches475be4d2012-02-19 19:52:38 -0800106 USB_DEVICE(0x08e3, 0x0301),
107 .driver_info = (unsigned long) &((hfcsusb_vdata)
108 {LED_SCHEME1, {2, 0, 1, 4},
109 "Olitec USB RNIS"}),
Martin Bachemd6c59c12007-08-21 14:26:21 +0200110 },
Martin Bachem597a1072005-11-07 01:00:20 -0800111 {
Joe Perches475be4d2012-02-19 19:52:38 -0800112 USB_DEVICE(0x07fa, 0x0846),
113 .driver_info = (unsigned long) &((hfcsusb_vdata)
114 {LED_SCHEME1, {0x80, -64, -32, -16},
115 "Bewan Modem RNIS USB"}),
Martin Bachemd6c59c12007-08-21 14:26:21 +0200116 },
Martin Bachem597a1072005-11-07 01:00:20 -0800117 {
Joe Perches475be4d2012-02-19 19:52:38 -0800118 USB_DEVICE(0x07fa, 0x0847),
119 .driver_info = (unsigned long) &((hfcsusb_vdata)
120 {LED_SCHEME1, {0x80, -64, -32, -16},
121 "Djinn Numeris USB"}),
Martin Bachemd6c59c12007-08-21 14:26:21 +0200122 },
Martin Bachem597a1072005-11-07 01:00:20 -0800123 {
Joe Perches475be4d2012-02-19 19:52:38 -0800124 USB_DEVICE(0x07b0, 0x0006),
125 .driver_info = (unsigned long) &((hfcsusb_vdata)
126 {LED_SCHEME1, {0x80, -64, -32, -16},
127 "Twister ISDN TA"}),
Martin Bachemd6c59c12007-08-21 14:26:21 +0200128 },
Martin Bachem7441dd12007-10-14 18:10:30 +0200129 {
Joe Perches475be4d2012-02-19 19:52:38 -0800130 USB_DEVICE(0x071d, 0x1005),
131 .driver_info = (unsigned long) &((hfcsusb_vdata)
132 {LED_SCHEME1, {0x02, 0, 0x01, 0x04},
133 "Eicon DIVA USB 4.0"}),
Martin Bachem7441dd12007-10-14 18:10:30 +0200134 },
Andrew Mortond6a1a642005-11-15 00:09:13 -0800135 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136};
137
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138/* structure defining input+output fifos (interrupt/bulk mode) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139struct usb_fifo; /* forward definition */
140typedef struct iso_urb_struct {
141 struct urb *purb;
142 __u8 buffer[ISO_BUFFER_SIZE]; /* buffer incoming/outgoing data */
143 struct usb_fifo *owner_fifo; /* pointer to owner fifo */
144} iso_urb_struct;
145
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146struct hfcusb_data; /* forward definition */
Martin Bachemd6c59c12007-08-21 14:26:21 +0200147
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148typedef struct usb_fifo {
149 int fifonum; /* fifo index attached to this structure */
150 int active; /* fifo is currently active */
151 struct hfcusb_data *hfc; /* pointer to main structure */
152 int pipe; /* address of endpoint */
153 __u8 usb_packet_maxlen; /* maximum length for usb transfer */
154 unsigned int max_size; /* maximum size of receive/send packet */
155 __u8 intervall; /* interrupt interval */
156 struct sk_buff *skbuff; /* actual used buffer */
157 struct urb *urb; /* transfer structure for usb routines */
158 __u8 buffer[128]; /* buffer incoming/outgoing data */
159 int bit_line; /* how much bits are in the fifo? */
160
161 volatile __u8 usb_transfer_mode; /* switched between ISO and INT */
162 iso_urb_struct iso[2]; /* need two urbs to have one always for pending */
163 struct hisax_if *hif; /* hisax interface */
164 int delete_flg; /* only delete skbuff once */
165 int last_urblen; /* remember length of last packet */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166} usb_fifo;
167
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168/* structure holding all data for one device */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169typedef struct hfcusb_data {
170 /* HiSax Interface for loadable Layer1 drivers */
Martin Bachemd6c59c12007-08-21 14:26:21 +0200171 struct hisax_d_if d_if; /* see hisax_if.h */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 struct hisax_b_if b_if[2]; /* see hisax_if.h */
173 int protocol;
174
175 struct usb_device *dev; /* our device */
176 int if_used; /* used interface number */
177 int alt_used; /* used alternate config */
178 int ctrl_paksize; /* control pipe packet size */
Martin Bachemd6c59c12007-08-21 14:26:21 +0200179 int ctrl_in_pipe, /* handles for control pipe */
Joe Perches475be4d2012-02-19 19:52:38 -0800180 ctrl_out_pipe;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 int cfg_used; /* configuration index used */
182 int vend_idx; /* vendor found */
183 int b_mode[2]; /* B-channel mode */
184 int l1_activated; /* layer 1 activated */
Martin Bachemd6c59c12007-08-21 14:26:21 +0200185 int disc_flag; /* TRUE if device was disonnected to avoid some USB actions */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 int packet_size, iso_packet_size;
187
188 /* control pipe background handling */
189 ctrl_buft ctrl_buff[HFC_CTRL_BUFSIZE]; /* buffer holding queued data */
190 volatile int ctrl_in_idx, ctrl_out_idx, ctrl_cnt; /* input/output pointer + count */
191 struct urb *ctrl_urb; /* transfer structure for control channel */
192
193 struct usb_ctrlrequest ctrl_write; /* buffer for control write request */
194 struct usb_ctrlrequest ctrl_read; /* same for read request */
195
Martin Bachem7441dd12007-10-14 18:10:30 +0200196 __u8 old_led_state, led_state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
198 volatile __u8 threshold_mask; /* threshold actually reported */
199 volatile __u8 bch_enables; /* or mask for sctrl_r and sctrl register values */
200
201 usb_fifo fifos[HFCUSB_NUM_FIFOS]; /* structure holding all fifo data */
202
203 volatile __u8 l1_state; /* actual l1 state */
204 struct timer_list t3_timer; /* timer 3 for activation/deactivation */
205 struct timer_list t4_timer; /* timer 4 for activation/deactivation */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206} hfcusb_data;
207
208
Joe Perches475be4d2012-02-19 19:52:38 -0800209static void collect_rx_frame(usb_fifo *fifo, __u8 *data, int len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 int finish);
211
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212static inline const char *
213symbolic(struct hfcusb_symbolic_list list[], const int num)
214{
215 int i;
216 for (i = 0; list[i].name != NULL; i++)
217 if (list[i].num == num)
218 return (list[i].name);
Karsten Keilb05121b2006-03-06 15:42:41 -0800219 return "<unknown ERROR>";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220}
221
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222static void
Joe Perches475be4d2012-02-19 19:52:38 -0800223ctrl_start_transfer(hfcusb_data *hfc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
225 if (hfc->ctrl_cnt) {
226 hfc->ctrl_urb->pipe = hfc->ctrl_out_pipe;
Joe Perches475be4d2012-02-19 19:52:38 -0800227 hfc->ctrl_urb->setup_packet = (u_char *)&hfc->ctrl_write;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 hfc->ctrl_urb->transfer_buffer = NULL;
229 hfc->ctrl_urb->transfer_buffer_length = 0;
230 hfc->ctrl_write.wIndex =
Joe Perches475be4d2012-02-19 19:52:38 -0800231 cpu_to_le16(hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 hfc->ctrl_write.wValue =
Joe Perches475be4d2012-02-19 19:52:38 -0800233 cpu_to_le16(hfc->ctrl_buff[hfc->ctrl_out_idx].reg_val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
235 usb_submit_urb(hfc->ctrl_urb, GFP_ATOMIC); /* start transfer */
236 }
237} /* ctrl_start_transfer */
238
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239static int
Joe Perches475be4d2012-02-19 19:52:38 -0800240queue_control_request(hfcusb_data *hfc, __u8 reg, __u8 val, int action)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241{
242 ctrl_buft *buf;
243
244 if (hfc->ctrl_cnt >= HFC_CTRL_BUFSIZE)
245 return (1); /* no space left */
246 buf = &hfc->ctrl_buff[hfc->ctrl_in_idx]; /* pointer to new index */
247 buf->hfc_reg = reg;
248 buf->reg_val = val;
249 buf->action = action;
250 if (++hfc->ctrl_in_idx >= HFC_CTRL_BUFSIZE)
251 hfc->ctrl_in_idx = 0; /* pointer wrap */
252 if (++hfc->ctrl_cnt == 1)
253 ctrl_start_transfer(hfc);
254 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255}
256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257static void
David Howells7d12e782006-10-05 14:55:46 +0100258ctrl_complete(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259{
260 hfcusb_data *hfc = (hfcusb_data *) urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
262 urb->dev = hfc->dev;
263 if (hfc->ctrl_cnt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 hfc->ctrl_cnt--; /* decrement actual count */
265 if (++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE)
266 hfc->ctrl_out_idx = 0; /* pointer wrap */
267
268 ctrl_start_transfer(hfc); /* start next transfer */
269 }
Martin Bachem7441dd12007-10-14 18:10:30 +0200270}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272/* write led data to auxport & invert if necessary */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273static void
Joe Perches475be4d2012-02-19 19:52:38 -0800274write_led(hfcusb_data *hfc, __u8 led_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275{
276 if (led_state != hfc->old_led_state) {
277 hfc->old_led_state = led_state;
278 queue_control_request(hfc, HFCUSB_P_DATA, led_state, 1);
279 }
280}
281
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282static void
Joe Perches475be4d2012-02-19 19:52:38 -0800283set_led_bit(hfcusb_data *hfc, signed short led_bits, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284{
Martin Bachem7441dd12007-10-14 18:10:30 +0200285 if (on) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 if (led_bits < 0)
287 hfc->led_state &= ~abs(led_bits);
288 else
289 hfc->led_state |= led_bits;
Martin Bachem7441dd12007-10-14 18:10:30 +0200290 } else {
291 if (led_bits < 0)
292 hfc->led_state |= abs(led_bits);
293 else
294 hfc->led_state &= ~led_bits;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 }
296}
297
Martin Bachemd6c59c12007-08-21 14:26:21 +0200298/* handle LED requests */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299static void
Joe Perches475be4d2012-02-19 19:52:38 -0800300handle_led(hfcusb_data *hfc, int event)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301{
Martin Bachem597a1072005-11-07 01:00:20 -0800302 hfcsusb_vdata *driver_info =
Joe Perches475be4d2012-02-19 19:52:38 -0800303 (hfcsusb_vdata *) hfcusb_idtab[hfc->vend_idx].driver_info;
Martin Bachem597a1072005-11-07 01:00:20 -0800304
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 /* if no scheme -> no LED action */
Martin Bachem597a1072005-11-07 01:00:20 -0800306 if (driver_info->led_scheme == LED_OFF)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 return;
308
309 switch (event) {
Joe Perches475be4d2012-02-19 19:52:38 -0800310 case LED_POWER_ON:
311 set_led_bit(hfc, driver_info->led_bits[0], 1);
312 set_led_bit(hfc, driver_info->led_bits[1], 0);
313 set_led_bit(hfc, driver_info->led_bits[2], 0);
314 set_led_bit(hfc, driver_info->led_bits[3], 0);
315 break;
316 case LED_POWER_OFF:
317 set_led_bit(hfc, driver_info->led_bits[0], 0);
318 set_led_bit(hfc, driver_info->led_bits[1], 0);
319 set_led_bit(hfc, driver_info->led_bits[2], 0);
320 set_led_bit(hfc, driver_info->led_bits[3], 0);
321 break;
322 case LED_S0_ON:
323 set_led_bit(hfc, driver_info->led_bits[1], 1);
324 break;
325 case LED_S0_OFF:
326 set_led_bit(hfc, driver_info->led_bits[1], 0);
327 break;
328 case LED_B1_ON:
329 set_led_bit(hfc, driver_info->led_bits[2], 1);
330 break;
331 case LED_B1_OFF:
332 set_led_bit(hfc, driver_info->led_bits[2], 0);
333 break;
334 case LED_B2_ON:
335 set_led_bit(hfc, driver_info->led_bits[3], 1);
336 break;
337 case LED_B2_OFF:
338 set_led_bit(hfc, driver_info->led_bits[3], 0);
339 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 write_led(hfc, hfc->led_state);
342}
343
Martin Bachemd6c59c12007-08-21 14:26:21 +0200344/* ISDN l1 timer T3 expires */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345static void
Kees Cook5e8b8242017-10-16 17:28:54 -0700346l1_timer_expire_t3(struct timer_list *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
Kees Cook5e8b8242017-10-16 17:28:54 -0700348 hfcusb_data *hfc = from_timer(hfc, t, t3_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION,
350 NULL);
Martin Bachemd6c59c12007-08-21 14:26:21 +0200351
352 DBG(HFCUSB_DBG_STATES,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 "HFC-S USB: PH_DEACTIVATE | INDICATION sent (T3 expire)");
Martin Bachemd6c59c12007-08-21 14:26:21 +0200354
355 hfc->l1_activated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 handle_led(hfc, LED_S0_OFF);
357 /* deactivate : */
358 queue_control_request(hfc, HFCUSB_STATES, 0x10, 1);
359 queue_control_request(hfc, HFCUSB_STATES, 3, 1);
360}
361
Martin Bachemd6c59c12007-08-21 14:26:21 +0200362/* ISDN l1 timer T4 expires */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363static void
Kees Cook5e8b8242017-10-16 17:28:54 -0700364l1_timer_expire_t4(struct timer_list *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
Kees Cook5e8b8242017-10-16 17:28:54 -0700366 hfcusb_data *hfc = from_timer(hfc, t, t4_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION,
368 NULL);
Martin Bachemd6c59c12007-08-21 14:26:21 +0200369
370 DBG(HFCUSB_DBG_STATES,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 "HFC-S USB: PH_DEACTIVATE | INDICATION sent (T4 expire)");
Martin Bachemd6c59c12007-08-21 14:26:21 +0200372
373 hfc->l1_activated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 handle_led(hfc, LED_S0_OFF);
375}
376
Martin Bachemd6c59c12007-08-21 14:26:21 +0200377/* S0 state changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378static void
Joe Perches475be4d2012-02-19 19:52:38 -0800379s0_state_handler(hfcusb_data *hfc, __u8 state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
381 __u8 old_state;
382
383 old_state = hfc->l1_state;
384 if (state == old_state || state < 1 || state > 8)
385 return;
386
Martin Bachemd6c59c12007-08-21 14:26:21 +0200387 DBG(HFCUSB_DBG_STATES, "HFC-S USB: S0 statechange(%d -> %d)",
388 old_state, state);
389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 if (state < 4 || state == 7 || state == 8) {
391 if (timer_pending(&hfc->t3_timer))
392 del_timer(&hfc->t3_timer);
Martin Bachemd6c59c12007-08-21 14:26:21 +0200393 DBG(HFCUSB_DBG_STATES, "HFC-S USB: T3 deactivated");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 }
395 if (state >= 7) {
396 if (timer_pending(&hfc->t4_timer))
397 del_timer(&hfc->t4_timer);
Martin Bachemd6c59c12007-08-21 14:26:21 +0200398 DBG(HFCUSB_DBG_STATES, "HFC-S USB: T4 deactivated");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 }
400
401 if (state == 7 && !hfc->l1_activated) {
402 hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
403 PH_ACTIVATE | INDICATION, NULL);
Martin Bachemd6c59c12007-08-21 14:26:21 +0200404 DBG(HFCUSB_DBG_STATES, "HFC-S USB: PH_ACTIVATE | INDICATION sent");
405 hfc->l1_activated = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 handle_led(hfc, LED_S0_ON);
Joe Perches475be4d2012-02-19 19:52:38 -0800407 } else if (state <= 3 /* && activated */) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 if (old_state == 7 || old_state == 8) {
Martin Bachemd6c59c12007-08-21 14:26:21 +0200409 DBG(HFCUSB_DBG_STATES, "HFC-S USB: T4 activated");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 if (!timer_pending(&hfc->t4_timer)) {
411 hfc->t4_timer.expires =
Joe Perches475be4d2012-02-19 19:52:38 -0800412 jiffies + (HFC_TIMER_T4 * HZ) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 add_timer(&hfc->t4_timer);
414 }
415 } else {
416 hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
417 PH_DEACTIVATE | INDICATION,
418 NULL);
Martin Bachemd6c59c12007-08-21 14:26:21 +0200419 DBG(HFCUSB_DBG_STATES,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 "HFC-S USB: PH_DEACTIVATE | INDICATION sent");
Martin Bachemd6c59c12007-08-21 14:26:21 +0200421 hfc->l1_activated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 handle_led(hfc, LED_S0_OFF);
423 }
424 }
425 hfc->l1_state = state;
426}
427
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428static void
429fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe,
430 void *buf, int num_packets, int packet_size, int interval,
431 usb_complete_t complete, void *context)
432{
433 int k;
434
Sebastian Andrzej Siewiordd3adc42018-06-20 12:40:26 +0200435 usb_fill_int_urb(urb, dev, pipe, buf, packet_size * num_packets,
436 complete, context, interval);
437
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 urb->number_of_packets = num_packets;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 urb->transfer_flags = URB_ISO_ASAP;
440 urb->actual_length = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 for (k = 0; k < num_packets; k++) {
442 urb->iso_frame_desc[k].offset = packet_size * k;
443 urb->iso_frame_desc[k].length = packet_size;
444 urb->iso_frame_desc[k].actual_length = 0;
445 }
446}
447
448/* allocs urbs and start isoc transfer with two pending urbs to avoid
Martin Bachemd6c59c12007-08-21 14:26:21 +0200449 * gaps in the transfer chain
450 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451static int
Joe Perches475be4d2012-02-19 19:52:38 -0800452start_isoc_chain(usb_fifo *fifo, int num_packets_per_urb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 usb_complete_t complete, int packet_size)
454{
455 int i, k, errcode;
456
Martin Bachemd6c59c12007-08-21 14:26:21 +0200457 DBG(HFCUSB_DBG_INIT, "HFC-S USB: starting ISO-URBs for fifo:%d\n",
458 fifo->fifonum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
460 /* allocate Memory for Iso out Urbs */
461 for (i = 0; i < 2; i++) {
462 if (!(fifo->iso[i].purb)) {
463 fifo->iso[i].purb =
Joe Perches475be4d2012-02-19 19:52:38 -0800464 usb_alloc_urb(num_packets_per_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 if (!(fifo->iso[i].purb)) {
466 printk(KERN_INFO
467 "alloc urb for fifo %i failed!!!",
468 fifo->fifonum);
469 }
470 fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo;
471
472 /* Init the first iso */
473 if (ISO_BUFFER_SIZE >=
474 (fifo->usb_packet_maxlen *
475 num_packets_per_urb)) {
476 fill_isoc_urb(fifo->iso[i].purb,
477 fifo->hfc->dev, fifo->pipe,
478 fifo->iso[i].buffer,
479 num_packets_per_urb,
480 fifo->usb_packet_maxlen,
481 fifo->intervall, complete,
482 &fifo->iso[i]);
483 memset(fifo->iso[i].buffer, 0,
484 sizeof(fifo->iso[i].buffer));
485 /* defining packet delimeters in fifo->buffer */
486 for (k = 0; k < num_packets_per_urb; k++) {
487 fifo->iso[i].purb->
Joe Perches475be4d2012-02-19 19:52:38 -0800488 iso_frame_desc[k].offset =
489 k * packet_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 fifo->iso[i].purb->
Joe Perches475be4d2012-02-19 19:52:38 -0800491 iso_frame_desc[k].length =
492 packet_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 }
494 } else {
495 printk(KERN_INFO
496 "HFC-S USB: ISO Buffer size to small!\n");
497 }
498 }
499 fifo->bit_line = BITLINE_INF;
500
501 errcode = usb_submit_urb(fifo->iso[i].purb, GFP_KERNEL);
502 fifo->active = (errcode >= 0) ? 1 : 0;
Martin Bachemd6c59c12007-08-21 14:26:21 +0200503 if (errcode < 0)
504 printk(KERN_INFO "HFC-S USB: usb_submit_urb URB nr:%d, error(%i): '%s'\n",
505 i, errcode, symbolic(urb_errlist, errcode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 }
507 return (fifo->active);
508}
509
510/* stops running iso chain and frees their pending urbs */
511static void
Joe Perches475be4d2012-02-19 19:52:38 -0800512stop_isoc_chain(usb_fifo *fifo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513{
514 int i;
515
516 for (i = 0; i < 2; i++) {
517 if (fifo->iso[i].purb) {
Martin Bachemd6c59c12007-08-21 14:26:21 +0200518 DBG(HFCUSB_DBG_INIT,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 "HFC-S USB: Stopping iso chain for fifo %i.%i",
520 fifo->fifonum, i);
Alan Sternae2d9902007-05-23 13:58:12 -0700521 usb_kill_urb(fifo->iso[i].purb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 usb_free_urb(fifo->iso[i].purb);
523 fifo->iso[i].purb = NULL;
524 }
525 }
Martin Bachemd6c59c12007-08-21 14:26:21 +0200526
Alan Sternae2d9902007-05-23 13:58:12 -0700527 usb_kill_urb(fifo->urb);
528 usb_free_urb(fifo->urb);
529 fifo->urb = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 fifo->active = 0;
531}
532
533/* defines how much ISO packets are handled in one URB */
534static int iso_packets[8] =
Joe Perches475be4d2012-02-19 19:52:38 -0800535{ ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B,
536 ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537};
538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539static void
David Howells7d12e782006-10-05 14:55:46 +0100540tx_iso_complete(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541{
542 iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
543 usb_fifo *fifo = context_iso_urb->owner_fifo;
544 hfcusb_data *hfc = fifo->hfc;
545 int k, tx_offset, num_isoc_packets, sink, len, current_len,
Joe Perches475be4d2012-02-19 19:52:38 -0800546 errcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 int frame_complete, transp_mode, fifon, status;
548 __u8 threshbit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
550 fifon = fifo->fifonum;
551 status = urb->status;
552
553 tx_offset = 0;
554
Martin Bachemd6c59c12007-08-21 14:26:21 +0200555 /* ISO transfer only partially completed,
556 look at individual frame status for details */
557 if (status == -EXDEV) {
558 DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: tx_iso_complete with -EXDEV"
559 ", urb->status %d, fifonum %d\n",
560 status, fifon);
561
562 for (k = 0; k < iso_packets[fifon]; ++k) {
563 errcode = urb->iso_frame_desc[k].status;
564 if (errcode)
565 DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: tx_iso_complete "
Joe Perches475be4d2012-02-19 19:52:38 -0800566 "packet %i, status: %i\n",
567 k, errcode);
Martin Bachemd6c59c12007-08-21 14:26:21 +0200568 }
569
570 // clear status, so go on with ISO transfers
571 status = 0;
572 }
573
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 if (fifo->active && !status) {
575 transp_mode = 0;
576 if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS)
Martin Bachemd6c59c12007-08-21 14:26:21 +0200577 transp_mode = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
579 /* is FifoFull-threshold set for our channel? */
Martin Bachemd6c59c12007-08-21 14:26:21 +0200580 threshbit = (hfc->threshold_mask & (1 << fifon));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 num_isoc_packets = iso_packets[fifon];
582
583 /* predict dataflow to avoid fifo overflow */
584 if (fifon >= HFCUSB_D_TX) {
585 sink = (threshbit) ? SINK_DMIN : SINK_DMAX;
586 } else {
587 sink = (threshbit) ? SINK_MIN : SINK_MAX;
588 }
589 fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,
590 context_iso_urb->buffer, num_isoc_packets,
591 fifo->usb_packet_maxlen, fifo->intervall,
592 tx_iso_complete, urb->context);
593 memset(context_iso_urb->buffer, 0,
594 sizeof(context_iso_urb->buffer));
Martin Bachemd6c59c12007-08-21 14:26:21 +0200595 frame_complete = 0;
596
597 /* Generate next ISO Packets */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 for (k = 0; k < num_isoc_packets; ++k) {
599 if (fifo->skbuff) {
600 len = fifo->skbuff->len;
601 /* we lower data margin every msec */
602 fifo->bit_line -= sink;
603 current_len = (0 - fifo->bit_line) / 8;
604 /* maximum 15 byte for every ISO packet makes our life easier */
605 if (current_len > 14)
606 current_len = 14;
607 current_len =
Joe Perches475be4d2012-02-19 19:52:38 -0800608 (len <=
609 current_len) ? len : current_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 /* how much bit do we put on the line? */
611 fifo->bit_line += current_len * 8;
612
613 context_iso_urb->buffer[tx_offset] = 0;
614 if (current_len == len) {
615 if (!transp_mode) {
616 /* here frame completion */
617 context_iso_urb->
Joe Perches475be4d2012-02-19 19:52:38 -0800618 buffer[tx_offset] = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 /* add 2 byte flags and 16bit CRC at end of ISDN frame */
620 fifo->bit_line += 32;
621 }
Martin Bachemd6c59c12007-08-21 14:26:21 +0200622 frame_complete = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 }
624
625 memcpy(context_iso_urb->buffer +
626 tx_offset + 1, fifo->skbuff->data,
627 current_len);
628 skb_pull(fifo->skbuff, current_len);
629
630 /* define packet delimeters within the URB buffer */
631 urb->iso_frame_desc[k].offset = tx_offset;
632 urb->iso_frame_desc[k].length =
Joe Perches475be4d2012-02-19 19:52:38 -0800633 current_len + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
635 tx_offset += (current_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 } else {
637 urb->iso_frame_desc[k].offset =
Joe Perches475be4d2012-02-19 19:52:38 -0800638 tx_offset++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640 urb->iso_frame_desc[k].length = 1;
641 fifo->bit_line -= sink; /* we lower data margin every msec */
642
643 if (fifo->bit_line < BITLINE_INF) {
644 fifo->bit_line = BITLINE_INF;
645 }
646 }
647
648 if (frame_complete) {
Martin Bachemd6c59c12007-08-21 14:26:21 +0200649 fifo->delete_flg = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 fifo->hif->l1l2(fifo->hif,
651 PH_DATA | CONFIRM,
Alan Cox17a45062006-10-03 01:13:55 -0700652 (void *) (unsigned long) fifo->skbuff->
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 truesize);
654 if (fifo->skbuff && fifo->delete_flg) {
655 dev_kfree_skb_any(fifo->skbuff);
656 fifo->skbuff = NULL;
Martin Bachemd6c59c12007-08-21 14:26:21 +0200657 fifo->delete_flg = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 }
Martin Bachemd6c59c12007-08-21 14:26:21 +0200659 frame_complete = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 }
661 }
662 errcode = usb_submit_urb(urb, GFP_ATOMIC);
663 if (errcode < 0) {
664 printk(KERN_INFO
Martin Bachemd6c59c12007-08-21 14:26:21 +0200665 "HFC-S USB: error submitting ISO URB: %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 errcode);
667 }
668 } else {
669 if (status && !hfc->disc_flag) {
670 printk(KERN_INFO
Martin Bachemd6c59c12007-08-21 14:26:21 +0200671 "HFC-S USB: tx_iso_complete: error(%i): '%s', fifonum=%d\n",
672 status, symbolic(urb_errlist, status), fifon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 }
674 }
Martin Bachemd6c59c12007-08-21 14:26:21 +0200675}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677static void
David Howells7d12e782006-10-05 14:55:46 +0100678rx_iso_complete(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
680 iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
681 usb_fifo *fifo = context_iso_urb->owner_fifo;
682 hfcusb_data *hfc = fifo->hfc;
683 int k, len, errcode, offset, num_isoc_packets, fifon, maxlen,
Joe Perches475be4d2012-02-19 19:52:38 -0800684 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 unsigned int iso_status;
686 __u8 *buf;
687 static __u8 eof[8];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
689 fifon = fifo->fifonum;
690 status = urb->status;
691
692 if (urb->status == -EOVERFLOW) {
Martin Bachemd6c59c12007-08-21 14:26:21 +0200693 DBG(HFCUSB_DBG_VERBOSE_USB,
694 "HFC-USB: ignoring USB DATAOVERRUN fifo(%i)", fifon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 status = 0;
696 }
Martin Bachemd6c59c12007-08-21 14:26:21 +0200697
698 /* ISO transfer only partially completed,
699 look at individual frame status for details */
700 if (status == -EXDEV) {
701 DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: rx_iso_complete with -EXDEV "
702 "urb->status %d, fifonum %d\n",
703 status, fifon);
704 status = 0;
705 }
706
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 if (fifo->active && !status) {
708 num_isoc_packets = iso_packets[fifon];
709 maxlen = fifo->usb_packet_maxlen;
710 for (k = 0; k < num_isoc_packets; ++k) {
711 len = urb->iso_frame_desc[k].actual_length;
712 offset = urb->iso_frame_desc[k].offset;
713 buf = context_iso_urb->buffer + offset;
714 iso_status = urb->iso_frame_desc[k].status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
Martin Bachemd6c59c12007-08-21 14:26:21 +0200716 if (iso_status && !hfc->disc_flag)
717 DBG(HFCUSB_DBG_VERBOSE_USB,
718 "HFC-S USB: rx_iso_complete "
719 "ISO packet %i, status: %i\n",
720 k, iso_status);
721
722 if (fifon == HFCUSB_D_RX) {
723 DBG(HFCUSB_DBG_VERBOSE_USB,
Joe Perches475be4d2012-02-19 19:52:38 -0800724 "HFC-S USB: ISO-D-RX lst_urblen:%2d "
725 "act_urblen:%2d max-urblen:%2d EOF:0x%0x",
726 fifo->last_urblen, len, maxlen,
727 eof[5]);
Martin Bachemd6c59c12007-08-21 14:26:21 +0200728
729 DBG_PACKET(HFCUSB_DBG_VERBOSE_USB, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 }
Martin Bachemd6c59c12007-08-21 14:26:21 +0200731
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 if (fifo->last_urblen != maxlen) {
733 /* the threshold mask is in the 2nd status byte */
734 hfc->threshold_mask = buf[1];
735 /* care for L1 state only for D-Channel
736 to avoid overlapped iso completions */
Martin Bachemd6c59c12007-08-21 14:26:21 +0200737 if (fifon == HFCUSB_D_RX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 /* the S0 state is in the upper half
739 of the 1st status byte */
Martin Bachemd6c59c12007-08-21 14:26:21 +0200740 s0_state_handler(hfc, buf[0] >> 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 }
742 eof[fifon] = buf[0] & 1;
743 if (len > 2)
744 collect_rx_frame(fifo, buf + 2,
745 len - 2,
Martin Bachemd6c59c12007-08-21 14:26:21 +0200746 (len < maxlen) ?
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 eof[fifon] : 0);
748 } else {
749 collect_rx_frame(fifo, buf, len,
750 (len <
751 maxlen) ? eof[fifon] :
752 0);
753 }
754 fifo->last_urblen = len;
755 }
756
757 fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,
758 context_iso_urb->buffer, num_isoc_packets,
759 fifo->usb_packet_maxlen, fifo->intervall,
760 rx_iso_complete, urb->context);
761 errcode = usb_submit_urb(urb, GFP_ATOMIC);
762 if (errcode < 0) {
Martin Bachemd6c59c12007-08-21 14:26:21 +0200763 printk(KERN_ERR
764 "HFC-S USB: error submitting ISO URB: %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 errcode);
766 }
767 } else {
768 if (status && !hfc->disc_flag) {
Martin Bachemd6c59c12007-08-21 14:26:21 +0200769 printk(KERN_ERR
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 "HFC-S USB: rx_iso_complete : "
771 "urb->status %d, fifonum %d\n",
772 status, fifon);
773 }
774 }
Martin Bachemd6c59c12007-08-21 14:26:21 +0200775}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
Martin Bachemd6c59c12007-08-21 14:26:21 +0200777/* collect rx data from INT- and ISO-URBs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778static void
Joe Perches475be4d2012-02-19 19:52:38 -0800779collect_rx_frame(usb_fifo *fifo, __u8 *data, int len, int finish)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780{
781 hfcusb_data *hfc = fifo->hfc;
782 int transp_mode, fifon;
Martin Bachemd6c59c12007-08-21 14:26:21 +0200783
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 fifon = fifo->fifonum;
785 transp_mode = 0;
786 if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS)
Martin Bachemd6c59c12007-08-21 14:26:21 +0200787 transp_mode = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
789 if (!fifo->skbuff) {
790 fifo->skbuff = dev_alloc_skb(fifo->max_size + 3);
791 if (!fifo->skbuff) {
Martin Bachemd6c59c12007-08-21 14:26:21 +0200792 printk(KERN_ERR
793 "HFC-S USB: cannot allocate buffer for fifo(%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 fifon);
795 return;
796 }
797 }
798 if (len) {
799 if (fifo->skbuff->len + len < fifo->max_size) {
Johannes Berg59ae1d12017-06-16 14:29:20 +0200800 skb_put_data(fifo->skbuff, data, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 } else {
Martin Bachemd6c59c12007-08-21 14:26:21 +0200802 DBG(HFCUSB_DBG_FIFO_ERR,
Joe Perches475be4d2012-02-19 19:52:38 -0800803 "HCF-USB: got frame exceeded fifo->max_size(%d) fifo(%d)",
804 fifo->max_size, fifon);
Martin Bachemd6c59c12007-08-21 14:26:21 +0200805 DBG_SKB(HFCUSB_DBG_VERBOSE_USB, fifo->skbuff);
806 skb_trim(fifo->skbuff, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 }
808 }
809 if (transp_mode && fifo->skbuff->len >= 128) {
810 fifo->hif->l1l2(fifo->hif, PH_DATA | INDICATION,
811 fifo->skbuff);
812 fifo->skbuff = NULL;
813 return;
814 }
815 /* we have a complete hdlc packet */
816 if (finish) {
Roel Kluin286e6332009-11-04 08:31:59 -0800817 if (fifo->skbuff->len > 3 &&
Joe Perches475be4d2012-02-19 19:52:38 -0800818 !fifo->skbuff->data[fifo->skbuff->len - 1]) {
Martin Bachemd6c59c12007-08-21 14:26:21 +0200819
820 if (fifon == HFCUSB_D_RX) {
821 DBG(HFCUSB_DBG_DCHANNEL,
822 "HFC-S USB: D-RX len(%d)", fifo->skbuff->len);
823 DBG_SKB(HFCUSB_DBG_DCHANNEL, fifo->skbuff);
824 }
825
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 /* remove CRC & status */
827 skb_trim(fifo->skbuff, fifo->skbuff->len - 3);
828 if (fifon == HFCUSB_PCM_RX) {
829 fifo->hif->l1l2(fifo->hif,
830 PH_DATA_E | INDICATION,
831 fifo->skbuff);
832 } else
833 fifo->hif->l1l2(fifo->hif,
834 PH_DATA | INDICATION,
835 fifo->skbuff);
836 fifo->skbuff = NULL; /* buffer was freed from upper layer */
837 } else {
Martin Bachemd6c59c12007-08-21 14:26:21 +0200838 DBG(HFCUSB_DBG_FIFO_ERR,
839 "HFC-S USB: ERROR frame len(%d) fifo(%d)",
840 fifo->skbuff->len, fifon);
841 DBG_SKB(HFCUSB_DBG_VERBOSE_USB, fifo->skbuff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 skb_trim(fifo->skbuff, 0);
843 }
844 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845}
846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847static void
Martin Bachemd6c59c12007-08-21 14:26:21 +0200848rx_int_complete(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849{
850 int len;
851 int status;
852 __u8 *buf, maxlen, fifon;
853 usb_fifo *fifo = (usb_fifo *) urb->context;
854 hfcusb_data *hfc = fifo->hfc;
855 static __u8 eof[8];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
857 urb->dev = hfc->dev; /* security init */
858
859 fifon = fifo->fifonum;
860 if ((!fifo->active) || (urb->status)) {
Martin Bachemd6c59c12007-08-21 14:26:21 +0200861 DBG(HFCUSB_DBG_INIT, "HFC-S USB: RX-Fifo %i is going down (%i)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 fifon, urb->status);
Martin Bachemd6c59c12007-08-21 14:26:21 +0200863
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 fifo->urb->interval = 0; /* cancel automatic rescheduling */
865 if (fifo->skbuff) {
866 dev_kfree_skb_any(fifo->skbuff);
867 fifo->skbuff = NULL;
868 }
869 return;
870 }
871 len = urb->actual_length;
872 buf = fifo->buffer;
873 maxlen = fifo->usb_packet_maxlen;
874
Martin Bachemd6c59c12007-08-21 14:26:21 +0200875 if (fifon == HFCUSB_D_RX) {
876 DBG(HFCUSB_DBG_VERBOSE_USB,
Joe Perches475be4d2012-02-19 19:52:38 -0800877 "HFC-S USB: INT-D-RX lst_urblen:%2d "
878 "act_urblen:%2d max-urblen:%2d EOF:0x%0x",
879 fifo->last_urblen, len, maxlen,
880 eof[5]);
Martin Bachemd6c59c12007-08-21 14:26:21 +0200881 DBG_PACKET(HFCUSB_DBG_VERBOSE_USB, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
884 if (fifo->last_urblen != fifo->usb_packet_maxlen) {
885 /* the threshold mask is in the 2nd status byte */
886 hfc->threshold_mask = buf[1];
887 /* the S0 state is in the upper half of the 1st status byte */
Martin Bachemd6c59c12007-08-21 14:26:21 +0200888 s0_state_handler(hfc, buf[0] >> 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 eof[fifon] = buf[0] & 1;
890 /* if we have more than the 2 status bytes -> collect data */
891 if (len > 2)
892 collect_rx_frame(fifo, buf + 2,
893 urb->actual_length - 2,
894 (len < maxlen) ? eof[fifon] : 0);
895 } else {
896 collect_rx_frame(fifo, buf, urb->actual_length,
897 (len < maxlen) ? eof[fifon] : 0);
898 }
899 fifo->last_urblen = urb->actual_length;
900 status = usb_submit_urb(urb, GFP_ATOMIC);
901 if (status) {
902 printk(KERN_INFO
Martin Bachemd6c59c12007-08-21 14:26:21 +0200903 "HFC-S USB: %s error resubmitting URB fifo(%d)\n",
Harvey Harrison156f1ed2008-04-28 02:14:40 -0700904 __func__, fifon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 }
Martin Bachemd6c59c12007-08-21 14:26:21 +0200906}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
Martin Bachemd6c59c12007-08-21 14:26:21 +0200908/* start initial INT-URB for certain fifo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909static void
Joe Perches475be4d2012-02-19 19:52:38 -0800910start_int_fifo(usb_fifo *fifo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911{
912 int errcode;
913
Martin Bachemd6c59c12007-08-21 14:26:21 +0200914 DBG(HFCUSB_DBG_INIT, "HFC-S USB: starting RX INT-URB for fifo:%d\n",
915 fifo->fifonum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
917 if (!fifo->urb) {
918 fifo->urb = usb_alloc_urb(0, GFP_KERNEL);
919 if (!fifo->urb)
920 return;
921 }
922 usb_fill_int_urb(fifo->urb, fifo->hfc->dev, fifo->pipe,
923 fifo->buffer, fifo->usb_packet_maxlen,
Martin Bachemd6c59c12007-08-21 14:26:21 +0200924 rx_int_complete, fifo, fifo->intervall);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 fifo->active = 1; /* must be marked active */
926 errcode = usb_submit_urb(fifo->urb, GFP_KERNEL);
927 if (errcode) {
Julia Lawalleeb4e6d2014-12-07 20:20:47 +0100928 printk(KERN_ERR "HFC-S USB: submit URB error(%s): status:%i\n",
929 __func__, errcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 fifo->active = 0;
931 fifo->skbuff = NULL;
932 }
Martin Bachemd6c59c12007-08-21 14:26:21 +0200933}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935static void
Joe Perches475be4d2012-02-19 19:52:38 -0800936setup_bchannel(hfcusb_data *hfc, int channel, int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937{
938 __u8 val, idx_table[2] = { 0, 2 };
939
940 if (hfc->disc_flag) {
941 return;
942 }
Martin Bachemd6c59c12007-08-21 14:26:21 +0200943 DBG(HFCUSB_DBG_STATES, "HFC-S USB: setting channel %d to mode %d",
944 channel, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 hfc->b_mode[channel] = mode;
946
947 /* setup CON_HDLC */
948 val = 0;
949 if (mode != L1_MODE_NULL)
950 val = 8; /* enable fifo? */
951 if (mode == L1_MODE_TRANS)
952 val |= 2; /* set transparent bit */
953
954 /* set FIFO to transmit register */
955 queue_control_request(hfc, HFCUSB_FIFO, idx_table[channel], 1);
956 queue_control_request(hfc, HFCUSB_CON_HDLC, val, 1);
957 /* reset fifo */
958 queue_control_request(hfc, HFCUSB_INC_RES_F, 2, 1);
959 /* set FIFO to receive register */
960 queue_control_request(hfc, HFCUSB_FIFO, idx_table[channel] + 1, 1);
961 queue_control_request(hfc, HFCUSB_CON_HDLC, val, 1);
962 /* reset fifo */
963 queue_control_request(hfc, HFCUSB_INC_RES_F, 2, 1);
964
965 val = 0x40;
966 if (hfc->b_mode[0])
967 val |= 1;
968 if (hfc->b_mode[1])
969 val |= 2;
970 queue_control_request(hfc, HFCUSB_SCTRL, val, 1);
971
972 val = 0;
973 if (hfc->b_mode[0])
974 val |= 1;
975 if (hfc->b_mode[1])
976 val |= 2;
977 queue_control_request(hfc, HFCUSB_SCTRL_R, val, 1);
978
979 if (mode == L1_MODE_NULL) {
980 if (channel)
981 handle_led(hfc, LED_B2_OFF);
982 else
983 handle_led(hfc, LED_B1_OFF);
984 } else {
985 if (channel)
986 handle_led(hfc, LED_B2_ON);
987 else
988 handle_led(hfc, LED_B1_ON);
989 }
990}
991
Adrian Bunk672c3fd2005-06-25 14:59:18 -0700992static void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
994{
995 usb_fifo *fifo = my_hisax_if->priv;
996 hfcusb_data *hfc = fifo->hfc;
997
998 switch (pr) {
Joe Perches475be4d2012-02-19 19:52:38 -0800999 case PH_ACTIVATE | REQUEST:
1000 if (fifo->fifonum == HFCUSB_D_TX) {
1001 DBG(HFCUSB_DBG_STATES,
1002 "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_ACTIVATE | REQUEST");
Martin Bachemd6c59c12007-08-21 14:26:21 +02001003
Joe Perches475be4d2012-02-19 19:52:38 -08001004 if (hfc->l1_state != 3
1005 && hfc->l1_state != 7) {
1006 hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
1007 PH_DEACTIVATE |
1008 INDICATION,
1009 NULL);
1010 DBG(HFCUSB_DBG_STATES,
1011 "HFC-S USB: PH_DEACTIVATE | INDICATION sent (not state 3 or 7)");
1012 } else {
1013 if (hfc->l1_state == 7) { /* l1 already active */
1014 hfc->d_if.ifc.l1l2(&hfc->
1015 d_if.
1016 ifc,
1017 PH_ACTIVATE
1018 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 INDICATION,
1020 NULL);
Martin Bachemd6c59c12007-08-21 14:26:21 +02001021 DBG(HFCUSB_DBG_STATES,
Joe Perches475be4d2012-02-19 19:52:38 -08001022 "HFC-S USB: PH_ACTIVATE | INDICATION sent again ;)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 } else {
Joe Perches475be4d2012-02-19 19:52:38 -08001024 /* force sending sending INFO1 */
1025 queue_control_request(hfc,
1026 HFCUSB_STATES,
1027 0x14,
1028 1);
1029 mdelay(1);
1030 /* start l1 activation */
1031 queue_control_request(hfc,
1032 HFCUSB_STATES,
1033 0x04,
1034 1);
1035 if (!timer_pending
1036 (&hfc->t3_timer)) {
1037 hfc->t3_timer.
1038 expires =
1039 jiffies +
1040 (HFC_TIMER_T3 *
1041 HZ) / 1000;
1042 add_timer(&hfc->
1043 t3_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 }
1045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 }
Joe Perches475be4d2012-02-19 19:52:38 -08001047 } else {
Martin Bachemd6c59c12007-08-21 14:26:21 +02001048 DBG(HFCUSB_DBG_STATES,
Joe Perches475be4d2012-02-19 19:52:38 -08001049 "HFC_USB: hfc_usb_d_l2l1 B-chan: PH_ACTIVATE | REQUEST");
1050 setup_bchannel(hfc,
1051 (fifo->fifonum ==
1052 HFCUSB_B1_TX) ? 0 : 1,
1053 (long) arg);
1054 fifo->hif->l1l2(fifo->hif,
1055 PH_ACTIVATE | INDICATION,
1056 NULL);
1057 }
1058 break;
1059 case PH_DEACTIVATE | REQUEST:
1060 if (fifo->fifonum == HFCUSB_D_TX) {
1061 DBG(HFCUSB_DBG_STATES,
1062 "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DEACTIVATE | REQUEST");
1063 } else {
1064 DBG(HFCUSB_DBG_STATES,
1065 "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DEACTIVATE | REQUEST");
1066 setup_bchannel(hfc,
1067 (fifo->fifonum ==
1068 HFCUSB_B1_TX) ? 0 : 1,
1069 (int) L1_MODE_NULL);
1070 fifo->hif->l1l2(fifo->hif,
1071 PH_DEACTIVATE | INDICATION,
1072 NULL);
1073 }
1074 break;
1075 case PH_DATA | REQUEST:
1076 if (fifo->skbuff && fifo->delete_flg) {
1077 dev_kfree_skb_any(fifo->skbuff);
1078 fifo->skbuff = NULL;
1079 fifo->delete_flg = 0;
1080 }
1081 fifo->skbuff = arg; /* we have a new buffer */
1082 break;
1083 default:
1084 DBG(HFCUSB_DBG_STATES,
1085 "HFC_USB: hfc_usb_d_l2l1: unknown state : %#x", pr);
1086 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 }
1088}
1089
Martin Bachemd6c59c12007-08-21 14:26:21 +02001090/* initial init HFC-S USB chip registers, HiSax interface, USB URBs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091static int
Joe Perches475be4d2012-02-19 19:52:38 -08001092hfc_usb_init(hfcusb_data *hfc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093{
1094 usb_fifo *fifo;
David S. Millera1e62162011-04-17 16:39:18 -07001095 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 u_char b;
1097 struct hisax_b_if *p_b_if[2];
1098
1099 /* check the chip id */
1100 if (read_usb(hfc, HFCUSB_CHIP_ID, &b) != 1) {
1101 printk(KERN_INFO "HFC-USB: cannot read chip id\n");
1102 return (1);
1103 }
1104 if (b != HFCUSB_CHIPID) {
1105 printk(KERN_INFO "HFC-S USB: Invalid chip id 0x%02x\n", b);
1106 return (1);
1107 }
1108
1109 /* first set the needed config, interface and alternate */
David S. Millera1e62162011-04-17 16:39:18 -07001110 usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
1112 /* do Chip reset */
1113 write_usb(hfc, HFCUSB_CIRM, 8);
1114 /* aux = output, reset off */
1115 write_usb(hfc, HFCUSB_CIRM, 0x10);
1116
Martin Bachemd6c59c12007-08-21 14:26:21 +02001117 /* set USB_SIZE to match wMaxPacketSize for INT or BULK transfers */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 write_usb(hfc, HFCUSB_USB_SIZE,
1119 (hfc->packet_size / 8) | ((hfc->packet_size / 8) << 4));
1120
Martin Bachemd6c59c12007-08-21 14:26:21 +02001121 /* set USB_SIZE_I to match wMaxPacketSize for ISO transfers */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 write_usb(hfc, HFCUSB_USB_SIZE_I, hfc->iso_packet_size);
1123
1124 /* enable PCM/GCI master mode */
1125 write_usb(hfc, HFCUSB_MST_MODE1, 0); /* set default values */
1126 write_usb(hfc, HFCUSB_MST_MODE0, 1); /* enable master mode */
1127
1128 /* init the fifos */
1129 write_usb(hfc, HFCUSB_F_THRES,
1130 (HFCUSB_TX_THRESHOLD /
1131 8) | ((HFCUSB_RX_THRESHOLD / 8) << 4));
1132
1133 fifo = hfc->fifos;
1134 for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
1135 write_usb(hfc, HFCUSB_FIFO, i); /* select the desired fifo */
1136 fifo[i].skbuff = NULL; /* init buffer pointer */
1137 fifo[i].max_size =
Joe Perches475be4d2012-02-19 19:52:38 -08001138 (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 fifo[i].last_urblen = 0;
1140 /* set 2 bit for D- & E-channel */
1141 write_usb(hfc, HFCUSB_HDLC_PAR,
1142 ((i <= HFCUSB_B2_RX) ? 0 : 2));
1143 /* rx hdlc, enable IFF for D-channel */
1144 write_usb(hfc, HFCUSB_CON_HDLC,
1145 ((i == HFCUSB_D_TX) ? 0x09 : 0x08));
1146 write_usb(hfc, HFCUSB_INC_RES_F, 2); /* reset the fifo */
1147 }
1148
1149 write_usb(hfc, HFCUSB_CLKDEL, 0x0f); /* clock delay value */
1150 write_usb(hfc, HFCUSB_STATES, 3 | 0x10); /* set deactivated mode */
1151 write_usb(hfc, HFCUSB_STATES, 3); /* enable state machine */
1152
1153 write_usb(hfc, HFCUSB_SCTRL_R, 0); /* disable both B receivers */
1154 write_usb(hfc, HFCUSB_SCTRL, 0x40); /* disable B transmitters + capacitive mode */
1155
1156 /* set both B-channel to not connected */
1157 hfc->b_mode[0] = L1_MODE_NULL;
1158 hfc->b_mode[1] = L1_MODE_NULL;
1159
Martin Bachemd6c59c12007-08-21 14:26:21 +02001160 hfc->l1_activated = 0;
1161 hfc->disc_flag = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 hfc->led_state = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 hfc->old_led_state = 0;
1164
1165 /* init the t3 timer */
Kees Cook5e8b8242017-10-16 17:28:54 -07001166 timer_setup(&hfc->t3_timer, l1_timer_expire_t3, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167
1168 /* init the t4 timer */
Kees Cook5e8b8242017-10-16 17:28:54 -07001169 timer_setup(&hfc->t4_timer, l1_timer_expire_t4, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 /* init the background machinery for control requests */
1172 hfc->ctrl_read.bRequestType = 0xc0;
1173 hfc->ctrl_read.bRequest = 1;
Karsten Keilb05121b2006-03-06 15:42:41 -08001174 hfc->ctrl_read.wLength = cpu_to_le16(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 hfc->ctrl_write.bRequestType = 0x40;
1176 hfc->ctrl_write.bRequest = 0;
1177 hfc->ctrl_write.wLength = 0;
1178 usb_fill_control_urb(hfc->ctrl_urb,
1179 hfc->dev,
1180 hfc->ctrl_out_pipe,
Joe Perches475be4d2012-02-19 19:52:38 -08001181 (u_char *)&hfc->ctrl_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 NULL, 0, ctrl_complete, hfc);
1183 /* Init All Fifos */
1184 for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
1185 hfc->fifos[i].iso[0].purb = NULL;
1186 hfc->fifos[i].iso[1].purb = NULL;
1187 hfc->fifos[i].active = 0;
1188 }
1189 /* register Modul to upper Hisax Layers */
1190 hfc->d_if.owner = THIS_MODULE;
1191 hfc->d_if.ifc.priv = &hfc->fifos[HFCUSB_D_TX];
1192 hfc->d_if.ifc.l2l1 = hfc_usb_l2l1;
1193 for (i = 0; i < 2; i++) {
1194 hfc->b_if[i].ifc.priv = &hfc->fifos[HFCUSB_B1_TX + i * 2];
1195 hfc->b_if[i].ifc.l2l1 = hfc_usb_l2l1;
1196 p_b_if[i] = &hfc->b_if[i];
1197 }
1198 /* default Prot: EURO ISDN, should be a module_param */
1199 hfc->protocol = 2;
Alan Sternae2d9902007-05-23 13:58:12 -07001200 i = hisax_register(&hfc->d_if, p_b_if, "hfc_usb", hfc->protocol);
1201 if (i) {
1202 printk(KERN_INFO "HFC-S USB: hisax_register -> %d\n", i);
1203 return i;
1204 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205
1206#ifdef CONFIG_HISAX_DEBUG
1207 hfc_debug = debug;
1208#endif
1209
1210 for (i = 0; i < 4; i++)
1211 hfc->fifos[i].hif = &p_b_if[i / 2]->ifc;
1212 for (i = 4; i < 8; i++)
1213 hfc->fifos[i].hif = &hfc->d_if.ifc;
1214
1215 /* 3 (+1) INT IN + 3 ISO OUT */
1216 if (hfc->cfg_used == CNF_3INT3ISO || hfc->cfg_used == CNF_4INT3ISO) {
1217 start_int_fifo(hfc->fifos + HFCUSB_D_RX);
1218 if (hfc->fifos[HFCUSB_PCM_RX].pipe)
1219 start_int_fifo(hfc->fifos + HFCUSB_PCM_RX);
1220 start_int_fifo(hfc->fifos + HFCUSB_B1_RX);
1221 start_int_fifo(hfc->fifos + HFCUSB_B2_RX);
1222 }
1223 /* 3 (+1) ISO IN + 3 ISO OUT */
1224 if (hfc->cfg_used == CNF_3ISO3ISO || hfc->cfg_used == CNF_4ISO3ISO) {
1225 start_isoc_chain(hfc->fifos + HFCUSB_D_RX, ISOC_PACKETS_D,
1226 rx_iso_complete, 16);
1227 if (hfc->fifos[HFCUSB_PCM_RX].pipe)
1228 start_isoc_chain(hfc->fifos + HFCUSB_PCM_RX,
1229 ISOC_PACKETS_D, rx_iso_complete,
1230 16);
1231 start_isoc_chain(hfc->fifos + HFCUSB_B1_RX, ISOC_PACKETS_B,
1232 rx_iso_complete, 16);
1233 start_isoc_chain(hfc->fifos + HFCUSB_B2_RX, ISOC_PACKETS_B,
1234 rx_iso_complete, 16);
1235 }
1236
1237 start_isoc_chain(hfc->fifos + HFCUSB_D_TX, ISOC_PACKETS_D,
1238 tx_iso_complete, 1);
1239 start_isoc_chain(hfc->fifos + HFCUSB_B1_TX, ISOC_PACKETS_B,
1240 tx_iso_complete, 1);
1241 start_isoc_chain(hfc->fifos + HFCUSB_B2_TX, ISOC_PACKETS_B,
1242 tx_iso_complete, 1);
1243
1244 handle_led(hfc, LED_POWER_ON);
1245
1246 return (0);
Martin Bachemd6c59c12007-08-21 14:26:21 +02001247}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
Martin Bachemd6c59c12007-08-21 14:26:21 +02001249/* initial callback for each plugged USB device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250static int
1251hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
1252{
1253 struct usb_device *dev = interface_to_usbdev(intf);
1254 hfcusb_data *context;
1255 struct usb_host_interface *iface = intf->cur_altsetting;
1256 struct usb_host_interface *iface_used = NULL;
1257 struct usb_host_endpoint *ep;
1258 int ifnum = iface->desc.bInterfaceNumber;
1259 int i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf,
Joe Perches475be4d2012-02-19 19:52:38 -08001260 attr, cfg_found, cidx, ep_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 int cmptbl[16], small_match, iso_packet_size, packet_size,
Joe Perches475be4d2012-02-19 19:52:38 -08001262 alt_used = 0;
Martin Bachem597a1072005-11-07 01:00:20 -08001263 hfcsusb_vdata *driver_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
1265 vend_idx = 0xffff;
Martin Bachem597a1072005-11-07 01:00:20 -08001266 for (i = 0; hfcusb_idtab[i].idVendor; i++) {
Karsten Keilb05121b2006-03-06 15:42:41 -08001267 if ((le16_to_cpu(dev->descriptor.idVendor) == hfcusb_idtab[i].idVendor)
1268 && (le16_to_cpu(dev->descriptor.idProduct) == hfcusb_idtab[i].idProduct)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 vend_idx = i;
Martin Bachem597a1072005-11-07 01:00:20 -08001270 continue;
1271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 }
Martin Bachem597a1072005-11-07 01:00:20 -08001273
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 printk(KERN_INFO
1275 "HFC-S USB: probing interface(%d) actalt(%d) minor(%d)\n",
1276 ifnum, iface->desc.bAlternateSetting, intf->minor);
1277
1278 if (vend_idx != 0xffff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 /* if vendor and product ID is OK, start probing alternate settings */
1280 alt_idx = 0;
1281 small_match = 0xffff;
1282
1283 /* default settings */
1284 iso_packet_size = 16;
1285 packet_size = 64;
1286
1287 while (alt_idx < intf->num_altsetting) {
1288 iface = intf->altsetting + alt_idx;
1289 probe_alt_setting = iface->desc.bAlternateSetting;
1290 cfg_used = 0;
1291
1292 /* check for config EOL element */
1293 while (validconf[cfg_used][0]) {
Martin Bachemd6c59c12007-08-21 14:26:21 +02001294 cfg_found = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 vcf = validconf[cfg_used];
1296 /* first endpoint descriptor */
1297 ep = iface->endpoint;
Martin Bachemd6c59c12007-08-21 14:26:21 +02001298
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 memcpy(cmptbl, vcf, 16 * sizeof(int));
1300
1301 /* check for all endpoints in this alternate setting */
1302 for (i = 0; i < iface->desc.bNumEndpoints;
1303 i++) {
1304 ep_addr =
Joe Perches475be4d2012-02-19 19:52:38 -08001305 ep->desc.bEndpointAddress;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 /* get endpoint base */
1307 idx = ((ep_addr & 0x7f) - 1) * 2;
1308 if (ep_addr & 0x80)
1309 idx++;
1310 attr = ep->desc.bmAttributes;
1311 if (cmptbl[idx] == EP_NUL) {
Martin Bachemd6c59c12007-08-21 14:26:21 +02001312 cfg_found = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 }
1314 if (attr == USB_ENDPOINT_XFER_INT
1315 && cmptbl[idx] == EP_INT)
1316 cmptbl[idx] = EP_NUL;
1317 if (attr == USB_ENDPOINT_XFER_BULK
1318 && cmptbl[idx] == EP_BLK)
1319 cmptbl[idx] = EP_NUL;
1320 if (attr == USB_ENDPOINT_XFER_ISOC
1321 && cmptbl[idx] == EP_ISO)
1322 cmptbl[idx] = EP_NUL;
1323
1324 /* check if all INT endpoints match minimum interval */
Martin Bachemd6c59c12007-08-21 14:26:21 +02001325 if ((attr == USB_ENDPOINT_XFER_INT)
1326 && (ep->desc.bInterval < vcf[17])) {
1327 cfg_found = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 }
1329 ep++;
1330 }
1331 for (i = 0; i < 16; i++) {
1332 /* all entries must be EP_NOP or EP_NUL for a valid config */
1333 if (cmptbl[i] != EP_NOP
1334 && cmptbl[i] != EP_NUL)
Martin Bachemd6c59c12007-08-21 14:26:21 +02001335 cfg_found = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 }
1337 if (cfg_found) {
1338 if (cfg_used < small_match) {
1339 small_match = cfg_used;
1340 alt_used =
Joe Perches475be4d2012-02-19 19:52:38 -08001341 probe_alt_setting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 iface_used = iface;
1343 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 }
1345 cfg_used++;
1346 }
1347 alt_idx++;
Martin Bachemd6c59c12007-08-21 14:26:21 +02001348 } /* (alt_idx < intf->num_altsetting) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
1350 /* found a valid USB Ta Endpint config */
1351 if (small_match != 0xffff) {
1352 iface = iface_used;
Martin Bachemd6c59c12007-08-21 14:26:21 +02001353 if (!(context = kzalloc(sizeof(hfcusb_data), GFP_KERNEL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 return (-ENOMEM); /* got no mem */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355
1356 ep = iface->endpoint;
1357 vcf = validconf[small_match];
1358
1359 for (i = 0; i < iface->desc.bNumEndpoints; i++) {
1360 ep_addr = ep->desc.bEndpointAddress;
1361 /* get endpoint base */
1362 idx = ((ep_addr & 0x7f) - 1) * 2;
1363 if (ep_addr & 0x80)
1364 idx++;
1365 cidx = idx & 7;
1366 attr = ep->desc.bmAttributes;
1367
1368 /* init Endpoints */
1369 if (vcf[idx] != EP_NOP
1370 && vcf[idx] != EP_NUL) {
1371 switch (attr) {
Joe Perches475be4d2012-02-19 19:52:38 -08001372 case USB_ENDPOINT_XFER_INT:
1373 context->
1374 fifos[cidx].
1375 pipe =
1376 usb_rcvintpipe
1377 (dev,
1378 ep->desc.
1379 bEndpointAddress);
1380 context->
1381 fifos[cidx].
1382 usb_transfer_mode
1383 = USB_INT;
1384 packet_size =
1385 le16_to_cpu(ep->desc.wMaxPacketSize);
1386 break;
1387 case USB_ENDPOINT_XFER_BULK:
1388 if (ep_addr & 0x80)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 context->
Joe Perches475be4d2012-02-19 19:52:38 -08001390 fifos
1391 [cidx].
1392 pipe =
1393 usb_rcvbulkpipe
1394 (dev,
1395 ep->
1396 desc.
1397 bEndpointAddress);
1398 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 context->
Joe Perches475be4d2012-02-19 19:52:38 -08001400 fifos
1401 [cidx].
1402 pipe =
1403 usb_sndbulkpipe
1404 (dev,
1405 ep->
1406 desc.
1407 bEndpointAddress);
1408 context->
1409 fifos[cidx].
1410 usb_transfer_mode
1411 = USB_BULK;
1412 packet_size =
1413 le16_to_cpu(ep->desc.wMaxPacketSize);
1414 break;
1415 case USB_ENDPOINT_XFER_ISOC:
1416 if (ep_addr & 0x80)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 context->
Joe Perches475be4d2012-02-19 19:52:38 -08001418 fifos
1419 [cidx].
1420 pipe =
1421 usb_rcvisocpipe
1422 (dev,
1423 ep->
1424 desc.
1425 bEndpointAddress);
1426 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 context->
Joe Perches475be4d2012-02-19 19:52:38 -08001428 fifos
1429 [cidx].
1430 pipe =
1431 usb_sndisocpipe
1432 (dev,
1433 ep->
1434 desc.
1435 bEndpointAddress);
1436 context->
1437 fifos[cidx].
1438 usb_transfer_mode
1439 = USB_ISOC;
1440 iso_packet_size =
1441 le16_to_cpu(ep->desc.wMaxPacketSize);
1442 break;
1443 default:
1444 context->
1445 fifos[cidx].
1446 pipe = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 } /* switch attribute */
1448
1449 if (context->fifos[cidx].pipe) {
1450 context->fifos[cidx].
Joe Perches475be4d2012-02-19 19:52:38 -08001451 fifonum = cidx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 context->fifos[cidx].hfc =
Joe Perches475be4d2012-02-19 19:52:38 -08001453 context;
Karsten Keilb05121b2006-03-06 15:42:41 -08001454 context->fifos[cidx].usb_packet_maxlen =
Joe Perches475be4d2012-02-19 19:52:38 -08001455 le16_to_cpu(ep->desc.wMaxPacketSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 context->fifos[cidx].
Joe Perches475be4d2012-02-19 19:52:38 -08001457 intervall =
1458 ep->desc.bInterval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 context->fifos[cidx].
Joe Perches475be4d2012-02-19 19:52:38 -08001460 skbuff = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 }
1462 }
1463 ep++;
1464 }
1465 context->dev = dev; /* save device */
1466 context->if_used = ifnum; /* save used interface */
1467 context->alt_used = alt_used; /* and alternate config */
1468 context->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */
1469 context->cfg_used = vcf[16]; /* store used config */
1470 context->vend_idx = vend_idx; /* store found vendor */
1471 context->packet_size = packet_size;
1472 context->iso_packet_size = iso_packet_size;
1473
1474 /* create the control pipes needed for register access */
1475 context->ctrl_in_pipe =
Joe Perches475be4d2012-02-19 19:52:38 -08001476 usb_rcvctrlpipe(context->dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 context->ctrl_out_pipe =
Joe Perches475be4d2012-02-19 19:52:38 -08001478 usb_sndctrlpipe(context->dev, 0);
Karsten Keil2ae46052012-07-12 22:59:46 +00001479
1480 driver_info = (hfcsusb_vdata *)
1481 hfcusb_idtab[vend_idx].driver_info;
1482
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 context->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
1484
Karsten Keil2ae46052012-07-12 22:59:46 +00001485 if (!context->ctrl_urb) {
1486 pr_warn("%s: No memory for control urb\n",
1487 driver_info->vend_name);
1488 kfree(context);
1489 return -ENOMEM;
1490 }
1491
1492 pr_info("HFC-S USB: detected \"%s\"\n",
1493 driver_info->vend_name);
Martin Bachemd6c59c12007-08-21 14:26:21 +02001494
1495 DBG(HFCUSB_DBG_INIT,
1496 "HFC-S USB: Endpoint-Config: %s (if=%d alt=%d), E-Channel(%d)",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 conf_str[small_match], context->if_used,
Martin Bachemd6c59c12007-08-21 14:26:21 +02001498 context->alt_used,
1499 validconf[small_match][18]);
1500
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 /* init the chip and register the driver */
Martin Bachemd6c59c12007-08-21 14:26:21 +02001502 if (hfc_usb_init(context)) {
Alan Sternae2d9902007-05-23 13:58:12 -07001503 usb_kill_urb(context->ctrl_urb);
1504 usb_free_urb(context->ctrl_urb);
1505 context->ctrl_urb = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 kfree(context);
1507 return (-EIO);
1508 }
1509 usb_set_intfdata(intf, context);
1510 return (0);
1511 }
1512 } else {
1513 printk(KERN_INFO
1514 "HFC-S USB: no valid vendor found in USB descriptor\n");
1515 }
1516 return (-EIO);
1517}
1518
Martin Bachemd6c59c12007-08-21 14:26:21 +02001519/* callback for unplugged USB device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520static void
Martin Bachem7441dd12007-10-14 18:10:30 +02001521hfc_usb_disconnect(struct usb_interface *intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522{
1523 hfcusb_data *context = usb_get_intfdata(intf);
1524 int i;
Martin Bachemd6c59c12007-08-21 14:26:21 +02001525
1526 handle_led(context, LED_POWER_OFF);
Martin Bachem7441dd12007-10-14 18:10:30 +02001527 schedule_timeout(HZ / 100);
Martin Bachemd6c59c12007-08-21 14:26:21 +02001528
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 printk(KERN_INFO "HFC-S USB: device disconnect\n");
Martin Bachemd6c59c12007-08-21 14:26:21 +02001530 context->disc_flag = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 usb_set_intfdata(intf, NULL);
Martin Bachem7441dd12007-10-14 18:10:30 +02001532
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 if (timer_pending(&context->t3_timer))
1534 del_timer(&context->t3_timer);
1535 if (timer_pending(&context->t4_timer))
1536 del_timer(&context->t4_timer);
Martin Bachemd6c59c12007-08-21 14:26:21 +02001537
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 /* tell all fifos to terminate */
1539 for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
1540 if (context->fifos[i].usb_transfer_mode == USB_ISOC) {
1541 if (context->fifos[i].active > 0) {
1542 stop_isoc_chain(&context->fifos[i]);
Martin Bachemd6c59c12007-08-21 14:26:21 +02001543 DBG(HFCUSB_DBG_INIT,
1544 "HFC-S USB: %s stopping ISOC chain Fifo(%i)",
Harvey Harrison156f1ed2008-04-28 02:14:40 -07001545 __func__, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 }
1547 } else {
1548 if (context->fifos[i].active > 0) {
1549 context->fifos[i].active = 0;
Martin Bachemd6c59c12007-08-21 14:26:21 +02001550 DBG(HFCUSB_DBG_INIT,
1551 "HFC-S USB: %s unlinking URB for Fifo(%i)",
Harvey Harrison156f1ed2008-04-28 02:14:40 -07001552 __func__, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 }
Alan Sternae2d9902007-05-23 13:58:12 -07001554 usb_kill_urb(context->fifos[i].urb);
1555 usb_free_urb(context->fifos[i].urb);
1556 context->fifos[i].urb = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 }
1558 context->fifos[i].active = 0;
1559 }
Alan Sternae2d9902007-05-23 13:58:12 -07001560 usb_kill_urb(context->ctrl_urb);
1561 usb_free_urb(context->ctrl_urb);
1562 context->ctrl_urb = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 hisax_unregister(&context->d_if);
1564 kfree(context); /* free our structure again */
Martin Bachemd6c59c12007-08-21 14:26:21 +02001565}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567static struct usb_driver hfc_drv = {
Martin Bachem597a1072005-11-07 01:00:20 -08001568 .name = "hfc_usb",
1569 .id_table = hfcusb_idtab,
1570 .probe = hfc_usb_probe,
1571 .disconnect = hfc_usb_disconnect,
Sarah Sharpe1f12eb2012-04-23 10:08:51 -07001572 .disable_hub_initiated_lpm = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573};
Martin Bachemd6c59c12007-08-21 14:26:21 +02001574
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575static void __exit
Martin Bachemd6c59c12007-08-21 14:26:21 +02001576hfc_usb_mod_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577{
Martin Bachemd6c59c12007-08-21 14:26:21 +02001578 usb_deregister(&hfc_drv); /* release our driver */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 printk(KERN_INFO "HFC-S USB: module removed\n");
1580}
1581
1582static int __init
Martin Bachemd6c59c12007-08-21 14:26:21 +02001583hfc_usb_mod_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 char revstr[30], datestr[30], dummy[30];
Martin Bachemd6c59c12007-08-21 14:26:21 +02001586#ifndef CONFIG_HISAX_DEBUG
1587 hfc_debug = debug;
1588#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 sscanf(hfcusb_revision,
1590 "%s %s $ %s %s %s $ ", dummy, revstr,
1591 dummy, datestr, dummy);
1592 printk(KERN_INFO
1593 "HFC-S USB: driver module revision %s date %s loaded, (debug=%i)\n",
1594 revstr, datestr, debug);
1595 if (usb_register(&hfc_drv)) {
1596 printk(KERN_INFO
1597 "HFC-S USB: Unable to register HFC-S USB module at usb stack\n");
1598 return (-1); /* unable to register */
1599 }
1600 return (0);
1601}
1602
Martin Bachemd6c59c12007-08-21 14:26:21 +02001603module_init(hfc_usb_mod_init);
1604module_exit(hfc_usb_mod_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605MODULE_AUTHOR(DRIVER_AUTHOR);
1606MODULE_DESCRIPTION(DRIVER_DESC);
1607MODULE_LICENSE("GPL");
Martin Bachem597a1072005-11-07 01:00:20 -08001608MODULE_DEVICE_TABLE(usb, hfcusb_idtab);