diff options
author | bart.hartgers@gmail.com <bart.hartgers@gmail.com> | 2009-10-28 05:43:26 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-12-11 14:55:21 -0500 |
commit | f4c1e8d597d1a440175db0d709c921cf3a49cfe7 (patch) | |
tree | b65c8b7142afa92732915491af1211b7a91e92a9 /drivers/usb/serial/ark3116.c | |
parent | 149fc791a452df5e8fa155f553b3027a874adf62 (diff) |
USB: ark3116: Make existing functions 16450-aware and add close and release functions.
Signed-off-by: Bart Hartgers <bart.hartgers@gmail.com>
Cc: Mike McCormack <mikem@ring3k.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial/ark3116.c')
-rw-r--r-- | drivers/usb/serial/ark3116.c | 495 |
1 files changed, 276 insertions, 219 deletions
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 5c947410c857..d12df9484677 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c | |||
@@ -152,79 +152,105 @@ static inline void ARK3116_RCV_QUIET(struct usb_serial *serial, | |||
152 | buf, 0x0000001, 1000); | 152 | buf, 0x0000001, 1000); |
153 | } | 153 | } |
154 | 154 | ||
155 | static inline int calc_divisor(int bps) | ||
156 | { | ||
157 | /* Original ark3116 made some exceptions in rounding here | ||
158 | * because windows did the same. Assume that is not really | ||
159 | * necessary. | ||
160 | * Crystal is 12MHz, probably because of USB, but we divide by 4? | ||
161 | */ | ||
162 | return (12000000 + 2*bps) / (4*bps); | ||
163 | } | ||
164 | |||
155 | static int ark3116_attach(struct usb_serial *serial) | 165 | static int ark3116_attach(struct usb_serial *serial) |
156 | { | 166 | { |
157 | char *buf; | 167 | struct usb_serial_port *port = serial->port[0]; |
168 | struct ark3116_private *priv; | ||
169 | |||
170 | /* make sure we have our end-points */ | ||
171 | if ((serial->num_bulk_in == 0) || | ||
172 | (serial->num_bulk_out == 0) || | ||
173 | (serial->num_interrupt_in == 0)) { | ||
174 | dev_err(&serial->dev->dev, | ||
175 | "%s - missing endpoint - " | ||
176 | "bulk in: %d, bulk out: %d, int in %d\n", | ||
177 | KBUILD_MODNAME, | ||
178 | serial->num_bulk_in, | ||
179 | serial->num_bulk_out, | ||
180 | serial->num_interrupt_in); | ||
181 | return -EINVAL; | ||
182 | } | ||
158 | 183 | ||
159 | buf = kmalloc(1, GFP_KERNEL); | 184 | priv = kzalloc(sizeof(struct ark3116_private), |
160 | if (!buf) { | 185 | GFP_KERNEL); |
161 | dbg("error kmalloc -> out of mem?"); | 186 | if (!priv) |
162 | return -ENOMEM; | 187 | return -ENOMEM; |
163 | } | ||
164 | 188 | ||
165 | if (is_irda(serial)) | 189 | init_waitqueue_head(&priv->delta_msr_wait); |
166 | dbg("IrDA mode"); | 190 | mutex_init(&priv->hw_lock); |
191 | spin_lock_init(&priv->status_lock); | ||
192 | |||
193 | priv->irda = is_irda(serial); | ||
194 | |||
195 | usb_set_serial_port_data(port, priv); | ||
167 | 196 | ||
168 | /* 3 */ | 197 | /* setup the hardware */ |
169 | ARK3116_SND(serial, 3, 0xFE, 0x40, 0x0008, 0x0002); | 198 | ark3116_write_reg(serial, UART_IER, 0); |
170 | ARK3116_SND(serial, 4, 0xFE, 0x40, 0x0008, 0x0001); | 199 | /* disable DMA */ |
171 | ARK3116_SND(serial, 5, 0xFE, 0x40, 0x0000, 0x0008); | 200 | ark3116_write_reg(serial, UART_FCR, 0); |
172 | ARK3116_SND(serial, 6, 0xFE, 0x40, is_irda(serial) ? 0x0001 : 0x0000, | 201 | /* handshake control */ |
173 | 0x000B); | 202 | priv->hcr = 0; |
203 | ark3116_write_reg(serial, 0x8 , 0); | ||
204 | /* modem control */ | ||
205 | priv->mcr = 0; | ||
206 | ark3116_write_reg(serial, UART_MCR, 0); | ||
174 | 207 | ||
175 | if (is_irda(serial)) { | 208 | if (!(priv->irda)) { |
176 | ARK3116_SND(serial, 1001, 0xFE, 0x40, 0x0000, 0x000C); | 209 | ark3116_write_reg(serial, 0xb , 0); |
177 | ARK3116_SND(serial, 1002, 0xFE, 0x40, 0x0041, 0x000D); | 210 | } else { |
178 | ARK3116_SND(serial, 1003, 0xFE, 0x40, 0x0001, 0x000A); | 211 | ark3116_write_reg(serial, 0xb , 1); |
212 | ark3116_write_reg(serial, 0xc , 0); | ||
213 | ark3116_write_reg(serial, 0xd , 0x41); | ||
214 | ark3116_write_reg(serial, 0xa , 1); | ||
179 | } | 215 | } |
180 | 216 | ||
181 | /* <-- seq7 */ | 217 | /* setup baudrate */ |
182 | ARK3116_RCV(serial, 7, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf); | 218 | ark3116_write_reg(serial, UART_LCR, UART_LCR_DLAB); |
183 | ARK3116_SND(serial, 8, 0xFE, 0x40, 0x0080, 0x0003); | ||
184 | ARK3116_SND(serial, 9, 0xFE, 0x40, 0x001A, 0x0000); | ||
185 | ARK3116_SND(serial, 10, 0xFE, 0x40, 0x0000, 0x0001); | ||
186 | ARK3116_SND(serial, 11, 0xFE, 0x40, 0x0000, 0x0003); | ||
187 | |||
188 | /* <-- seq12 */ | ||
189 | ARK3116_RCV(serial, 12, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf); | ||
190 | ARK3116_SND(serial, 13, 0xFE, 0x40, 0x0000, 0x0004); | ||
191 | |||
192 | /* 14 */ | ||
193 | ARK3116_RCV(serial, 14, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf); | ||
194 | ARK3116_SND(serial, 15, 0xFE, 0x40, 0x0000, 0x0004); | ||
195 | |||
196 | /* 16 */ | ||
197 | ARK3116_RCV(serial, 16, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf); | ||
198 | /* --> seq17 */ | ||
199 | ARK3116_SND(serial, 17, 0xFE, 0x40, 0x0001, 0x0004); | ||
200 | |||
201 | /* <-- seq18 */ | ||
202 | ARK3116_RCV(serial, 18, 0xFE, 0xC0, 0x0000, 0x0004, 0x01, buf); | ||
203 | |||
204 | /* --> seq19 */ | ||
205 | ARK3116_SND(serial, 19, 0xFE, 0x40, 0x0003, 0x0004); | ||
206 | |||
207 | /* <-- seq20 */ | ||
208 | /* seems like serial port status info (RTS, CTS, ...) */ | ||
209 | /* returns modem control line status?! */ | ||
210 | ARK3116_RCV(serial, 20, 0xFE, 0xC0, 0x0000, 0x0006, 0xFF, buf); | ||
211 | |||
212 | /* set 9600 baud & do some init?! */ | ||
213 | ARK3116_SND(serial, 147, 0xFE, 0x40, 0x0083, 0x0003); | ||
214 | ARK3116_SND(serial, 148, 0xFE, 0x40, 0x0038, 0x0000); | ||
215 | ARK3116_SND(serial, 149, 0xFE, 0x40, 0x0001, 0x0001); | ||
216 | if (is_irda(serial)) | ||
217 | ARK3116_SND(serial, 1004, 0xFE, 0x40, 0x0000, 0x0009); | ||
218 | ARK3116_SND(serial, 150, 0xFE, 0x40, 0x0003, 0x0003); | ||
219 | ARK3116_RCV(serial, 151, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf); | ||
220 | ARK3116_SND(serial, 152, 0xFE, 0x40, 0x0000, 0x0003); | ||
221 | ARK3116_RCV(serial, 153, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf); | ||
222 | ARK3116_SND(serial, 154, 0xFE, 0x40, 0x0003, 0x0003); | ||
223 | 219 | ||
224 | kfree(buf); | 220 | /* setup for 9600 8N1 */ |
221 | priv->quot = calc_divisor(9600); | ||
222 | ark3116_write_reg(serial, UART_DLL, priv->quot & 0xff); | ||
223 | ark3116_write_reg(serial, UART_DLM, (priv->quot>>8) & 0xff); | ||
224 | |||
225 | priv->lcr = UART_LCR_WLEN8; | ||
226 | ark3116_write_reg(serial, UART_LCR, UART_LCR_WLEN8); | ||
227 | |||
228 | ark3116_write_reg(serial, 0xe, 0); | ||
229 | |||
230 | if (priv->irda) | ||
231 | ark3116_write_reg(serial, 0x9, 0); | ||
232 | |||
233 | dev_info(&serial->dev->dev, | ||
234 | "%s using %s mode\n", | ||
235 | KBUILD_MODNAME, | ||
236 | priv->irda ? "IrDA" : "RS232"); | ||
225 | return 0; | 237 | return 0; |
226 | } | 238 | } |
227 | 239 | ||
240 | static void ark3116_release(struct usb_serial *serial) | ||
241 | { | ||
242 | struct usb_serial_port *port = serial->port[0]; | ||
243 | struct ark3116_private *priv = usb_get_serial_port_data(port); | ||
244 | |||
245 | /* device is closed, so URBs and DMA should be down */ | ||
246 | |||
247 | usb_set_serial_port_data(port, NULL); | ||
248 | |||
249 | mutex_destroy(&priv->hw_lock); | ||
250 | |||
251 | kfree(priv); | ||
252 | } | ||
253 | |||
228 | static void ark3116_init_termios(struct tty_struct *tty) | 254 | static void ark3116_init_termios(struct tty_struct *tty) |
229 | { | 255 | { |
230 | struct ktermios *termios = tty->termios; | 256 | struct ktermios *termios = tty->termios; |
@@ -240,200 +266,189 @@ static void ark3116_set_termios(struct tty_struct *tty, | |||
240 | struct ktermios *old_termios) | 266 | struct ktermios *old_termios) |
241 | { | 267 | { |
242 | struct usb_serial *serial = port->serial; | 268 | struct usb_serial *serial = port->serial; |
269 | struct ark3116_private *priv = usb_get_serial_port_data(port); | ||
243 | struct ktermios *termios = tty->termios; | 270 | struct ktermios *termios = tty->termios; |
244 | unsigned int cflag = termios->c_cflag; | 271 | unsigned int cflag = termios->c_cflag; |
245 | int baud; | 272 | int bps = tty_get_baud_rate(tty); |
246 | int ark3116_baud; | 273 | int quot; |
247 | char *buf; | 274 | __u8 lcr, hcr, eval; |
248 | char config; | 275 | |
249 | 276 | /* set data bit count */ | |
250 | config = 0; | 277 | switch (cflag & CSIZE) { |
278 | case CS5: | ||
279 | lcr = UART_LCR_WLEN5; | ||
280 | break; | ||
281 | case CS6: | ||
282 | lcr = UART_LCR_WLEN6; | ||
283 | break; | ||
284 | case CS7: | ||
285 | lcr = UART_LCR_WLEN7; | ||
286 | break; | ||
287 | default: | ||
288 | case CS8: | ||
289 | lcr = UART_LCR_WLEN8; | ||
290 | break; | ||
291 | } | ||
292 | if (cflag & CSTOPB) | ||
293 | lcr |= UART_LCR_STOP; | ||
294 | if (cflag & PARENB) | ||
295 | lcr |= UART_LCR_PARITY; | ||
296 | if (!(cflag & PARODD)) | ||
297 | lcr |= UART_LCR_EPAR; | ||
298 | #ifdef CMSPAR | ||
299 | if (cflag & CMSPAR) | ||
300 | lcr |= UART_LCR_SPAR; | ||
301 | #endif | ||
302 | /* handshake control */ | ||
303 | hcr = (cflag & CRTSCTS) ? 0x03 : 0x00; | ||
304 | |||
305 | /* calc baudrate */ | ||
306 | dbg("%s - setting bps to %d", __func__, bps); | ||
307 | eval = 0; | ||
308 | switch (bps) { | ||
309 | case 0: | ||
310 | quot = calc_divisor(9600); | ||
311 | break; | ||
312 | default: | ||
313 | if ((bps < 75) || (bps > 3000000)) | ||
314 | bps = 9600; | ||
315 | quot = calc_divisor(bps); | ||
316 | break; | ||
317 | case 460800: | ||
318 | eval = 1; | ||
319 | quot = calc_divisor(bps); | ||
320 | break; | ||
321 | case 921600: | ||
322 | eval = 2; | ||
323 | quot = calc_divisor(bps); | ||
324 | break; | ||
325 | } | ||
251 | 326 | ||
252 | dbg("%s - port %d", __func__, port->number); | 327 | /* Update state: synchronize */ |
328 | mutex_lock(&priv->hw_lock); | ||
253 | 329 | ||
330 | /* keep old LCR_SBC bit */ | ||
331 | lcr |= (priv->lcr & UART_LCR_SBC); | ||
254 | 332 | ||
255 | cflag = termios->c_cflag; | 333 | dbg("%s - setting hcr:0x%02x,lcr:0x%02x,quot:%d", |
256 | termios->c_cflag &= ~(CMSPAR|CRTSCTS); | 334 | __func__, hcr, lcr, quot); |
257 | 335 | ||
258 | buf = kmalloc(1, GFP_KERNEL); | 336 | /* handshake control */ |
259 | if (!buf) { | 337 | if (priv->hcr != hcr) { |
260 | dbg("error kmalloc"); | 338 | priv->hcr = hcr; |
261 | *termios = *old_termios; | 339 | ark3116_write_reg(serial, 0x8, hcr); |
262 | return; | ||
263 | } | 340 | } |
264 | 341 | ||
265 | /* set data bit count (8/7/6/5) */ | 342 | /* baudrate */ |
266 | if (cflag & CSIZE) { | 343 | if (priv->quot != quot) { |
267 | switch (cflag & CSIZE) { | 344 | priv->quot = quot; |
268 | case CS5: | 345 | priv->lcr = lcr; /* need to write lcr anyway */ |
269 | config |= 0x00; | 346 | |
270 | dbg("setting CS5"); | 347 | /* disable DMA since transmit/receive is |
271 | break; | 348 | * shadowed by UART_DLL |
272 | case CS6: | 349 | */ |
273 | config |= 0x01; | 350 | ark3116_write_reg(serial, UART_FCR, 0); |
274 | dbg("setting CS6"); | 351 | |
275 | break; | 352 | ark3116_write_reg(serial, UART_LCR, |
276 | case CS7: | 353 | lcr|UART_LCR_DLAB); |
277 | config |= 0x02; | 354 | ark3116_write_reg(serial, UART_DLL, quot & 0xff); |
278 | dbg("setting CS7"); | 355 | ark3116_write_reg(serial, UART_DLM, (quot>>8) & 0xff); |
279 | break; | 356 | |
280 | default: | 357 | /* restore lcr */ |
281 | dbg("CSIZE was set but not CS5-CS8, using CS8!"); | 358 | ark3116_write_reg(serial, UART_LCR, lcr); |
282 | /* fall through */ | 359 | /* magic baudrate thingy: not sure what it does, |
283 | case CS8: | 360 | * but windows does this as well. |
284 | config |= 0x03; | 361 | */ |
285 | dbg("setting CS8"); | 362 | ark3116_write_reg(serial, 0xe, eval); |
286 | break; | 363 | |
287 | } | 364 | /* enable DMA */ |
365 | ark3116_write_reg(serial, UART_FCR, UART_FCR_DMA_SELECT); | ||
366 | } else if (priv->lcr != lcr) { | ||
367 | priv->lcr = lcr; | ||
368 | ark3116_write_reg(serial, UART_LCR, lcr); | ||
288 | } | 369 | } |
289 | 370 | ||
290 | /* set parity (NONE/EVEN/ODD) */ | 371 | mutex_unlock(&priv->hw_lock); |
291 | if (cflag & PARENB) { | ||
292 | if (cflag & PARODD) { | ||
293 | config |= 0x08; | ||
294 | dbg("setting parity to ODD"); | ||
295 | } else { | ||
296 | config |= 0x18; | ||
297 | dbg("setting parity to EVEN"); | ||
298 | } | ||
299 | } else { | ||
300 | dbg("setting parity to NONE"); | ||
301 | } | ||
302 | 372 | ||
303 | /* set stop bit (1/2) */ | 373 | /* check for software flow control */ |
304 | if (cflag & CSTOPB) { | 374 | if (I_IXOFF(tty) || I_IXON(tty)) { |
305 | config |= 0x04; | 375 | dev_warn(&serial->dev->dev, |
306 | dbg("setting 2 stop bits"); | 376 | "%s: don't know how to do software flow control\n", |
307 | } else { | 377 | KBUILD_MODNAME); |
308 | dbg("setting 1 stop bit"); | ||
309 | } | 378 | } |
310 | 379 | ||
311 | /* set baudrate */ | 380 | /* Don't rewrite B0 */ |
312 | baud = tty_get_baud_rate(tty); | 381 | if (tty_termios_baud_rate(termios)) |
313 | 382 | tty_termios_encode_baud_rate(termios, bps, bps); | |
314 | switch (baud) { | 383 | } |
315 | case 75: | ||
316 | case 150: | ||
317 | case 300: | ||
318 | case 600: | ||
319 | case 1200: | ||
320 | case 1800: | ||
321 | case 2400: | ||
322 | case 4800: | ||
323 | case 9600: | ||
324 | case 19200: | ||
325 | case 38400: | ||
326 | case 57600: | ||
327 | case 115200: | ||
328 | case 230400: | ||
329 | case 460800: | ||
330 | /* Report the resulting rate back to the caller */ | ||
331 | tty_encode_baud_rate(tty, baud, baud); | ||
332 | break; | ||
333 | /* set 9600 as default (if given baudrate is invalid for example) */ | ||
334 | default: | ||
335 | tty_encode_baud_rate(tty, 9600, 9600); | ||
336 | case 0: | ||
337 | baud = 9600; | ||
338 | } | ||
339 | |||
340 | /* | ||
341 | * found by try'n'error, be careful, maybe there are other options | ||
342 | * for multiplicator etc! (3.5 for example) | ||
343 | */ | ||
344 | if (baud == 460800) | ||
345 | /* strange, for 460800 the formula is wrong | ||
346 | * if using round() then 9600baud is wrong) */ | ||
347 | ark3116_baud = 7; | ||
348 | else | ||
349 | ark3116_baud = 3000000 / baud; | ||
350 | |||
351 | /* ? */ | ||
352 | ARK3116_RCV(serial, 0, 0xFE, 0xC0, 0x0000, 0x0003, 0x03, buf); | ||
353 | |||
354 | /* offset = buf[0]; */ | ||
355 | /* offset = 0x03; */ | ||
356 | /* dbg("using 0x%04X as target for 0x0003:", 0x0080 + offset); */ | ||
357 | |||
358 | /* set baudrate */ | ||
359 | dbg("setting baudrate to %d (->reg=%d)", baud, ark3116_baud); | ||
360 | ARK3116_SND(serial, 147, 0xFE, 0x40, 0x0083, 0x0003); | ||
361 | ARK3116_SND(serial, 148, 0xFE, 0x40, | ||
362 | (ark3116_baud & 0x00FF), 0x0000); | ||
363 | ARK3116_SND(serial, 149, 0xFE, 0x40, | ||
364 | (ark3116_baud & 0xFF00) >> 8, 0x0001); | ||
365 | ARK3116_SND(serial, 150, 0xFE, 0x40, 0x0003, 0x0003); | ||
366 | |||
367 | /* ? */ | ||
368 | ARK3116_RCV(serial, 151, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf); | ||
369 | ARK3116_SND(serial, 152, 0xFE, 0x40, 0x0000, 0x0003); | ||
370 | |||
371 | /* set data bit count, stop bit count & parity: */ | ||
372 | dbg("updating bit count, stop bit or parity (cfg=0x%02X)", config); | ||
373 | ARK3116_RCV(serial, 153, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf); | ||
374 | ARK3116_SND(serial, 154, 0xFE, 0x40, config, 0x0003); | ||
375 | 384 | ||
376 | if (cflag & CRTSCTS) | 385 | static void ark3116_close(struct usb_serial_port *port) |
377 | dbg("CRTSCTS not supported by chipset?!"); | 386 | { |
387 | struct usb_serial *serial = port->serial; | ||
378 | 388 | ||
379 | /* TEST ARK3116_SND(154, 0xFE, 0x40, 0xFFFF, 0x0006); */ | 389 | if (serial->dev) { |
390 | /* disable DMA */ | ||
391 | ark3116_write_reg(serial, UART_FCR, 0); | ||
380 | 392 | ||
381 | kfree(buf); | 393 | /* deactivate interrupts */ |
394 | ark3116_write_reg(serial, UART_IER, 0); | ||
382 | 395 | ||
383 | return; | 396 | /* shutdown any bulk reads that might be going on */ |
397 | if (serial->num_bulk_out) | ||
398 | usb_kill_urb(port->write_urb); | ||
399 | if (serial->num_bulk_in) | ||
400 | usb_kill_urb(port->read_urb); | ||
401 | if (serial->num_interrupt_in) | ||
402 | usb_kill_urb(port->interrupt_in_urb); | ||
403 | } | ||
384 | } | 404 | } |
385 | 405 | ||
386 | static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) | 406 | static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) |
387 | { | 407 | { |
388 | struct ktermios tmp_termios; | 408 | struct ark3116_private *priv = usb_get_serial_port_data(port); |
389 | struct usb_serial *serial = port->serial; | 409 | struct usb_serial *serial = port->serial; |
390 | char *buf; | 410 | unsigned char *buf; |
391 | int result = 0; | 411 | int result; |
392 | |||
393 | dbg("%s - port %d", __func__, port->number); | ||
394 | 412 | ||
395 | buf = kmalloc(1, GFP_KERNEL); | 413 | buf = kmalloc(1, GFP_KERNEL); |
396 | if (!buf) { | 414 | if (buf == NULL) |
397 | dbg("error kmalloc -> out of mem?"); | ||
398 | return -ENOMEM; | 415 | return -ENOMEM; |
399 | } | ||
400 | 416 | ||
401 | result = usb_serial_generic_open(tty, port); | 417 | result = usb_serial_generic_open(tty, port); |
402 | if (result) | 418 | if (result) { |
419 | dbg("%s - usb_serial_generic_open failed: %d", | ||
420 | __func__, result); | ||
403 | goto err_out; | 421 | goto err_out; |
422 | } | ||
404 | 423 | ||
405 | /* open */ | 424 | /* setup termios */ |
406 | ARK3116_RCV(serial, 111, 0xFE, 0xC0, 0x0000, 0x0003, 0x02, buf); | 425 | if (tty) |
407 | 426 | ark3116_set_termios(tty, port, NULL); | |
408 | ARK3116_SND(serial, 112, 0xFE, 0x40, 0x0082, 0x0003); | ||
409 | ARK3116_SND(serial, 113, 0xFE, 0x40, 0x001A, 0x0000); | ||
410 | ARK3116_SND(serial, 114, 0xFE, 0x40, 0x0000, 0x0001); | ||
411 | ARK3116_SND(serial, 115, 0xFE, 0x40, 0x0002, 0x0003); | ||
412 | |||
413 | ARK3116_RCV(serial, 116, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf); | ||
414 | ARK3116_SND(serial, 117, 0xFE, 0x40, 0x0002, 0x0004); | ||
415 | |||
416 | ARK3116_RCV(serial, 118, 0xFE, 0xC0, 0x0000, 0x0004, 0x02, buf); | ||
417 | ARK3116_SND(serial, 119, 0xFE, 0x40, 0x0000, 0x0004); | ||
418 | |||
419 | ARK3116_RCV(serial, 120, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf); | ||
420 | 427 | ||
421 | ARK3116_SND(serial, 121, 0xFE, 0x40, 0x0001, 0x0004); | 428 | /* remove any data still left: also clears error state */ |
429 | ark3116_read_reg(serial, UART_RX, buf); | ||
422 | 430 | ||
423 | ARK3116_RCV(serial, 122, 0xFE, 0xC0, 0x0000, 0x0004, 0x01, buf); | 431 | /* read modem status */ |
432 | priv->msr = ark3116_read_reg(serial, UART_MSR, buf); | ||
433 | /* read line status */ | ||
434 | priv->lsr = ark3116_read_reg(serial, UART_LSR, buf); | ||
424 | 435 | ||
425 | ARK3116_SND(serial, 123, 0xFE, 0x40, 0x0003, 0x0004); | 436 | result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); |
437 | if (result) { | ||
438 | dev_err(&port->dev, "submit irq_in urb failed %d\n", | ||
439 | result); | ||
440 | ark3116_close(port); | ||
441 | goto err_out; | ||
442 | } | ||
426 | 443 | ||
427 | /* returns different values (control lines?!) */ | 444 | /* activate interrupts */ |
428 | ARK3116_RCV(serial, 124, 0xFE, 0xC0, 0x0000, 0x0006, 0xFF, buf); | 445 | ark3116_write_reg(port->serial, UART_IER, UART_IER_MSI|UART_IER_RLSI); |
429 | 446 | ||
430 | /* initialise termios */ | 447 | /* enable DMA */ |
431 | if (tty) | 448 | ark3116_write_reg(port->serial, UART_FCR, UART_FCR_DMA_SELECT); |
432 | ark3116_set_termios(tty, port, &tmp_termios); | ||
433 | 449 | ||
434 | err_out: | 450 | err_out: |
435 | kfree(buf); | 451 | kfree(buf); |
436 | |||
437 | return result; | 452 | return result; |
438 | } | 453 | } |
439 | 454 | ||
@@ -441,6 +456,7 @@ static int ark3116_ioctl(struct tty_struct *tty, struct file *file, | |||
441 | unsigned int cmd, unsigned long arg) | 456 | unsigned int cmd, unsigned long arg) |
442 | { | 457 | { |
443 | struct usb_serial_port *port = tty->driver_data; | 458 | struct usb_serial_port *port = tty->driver_data; |
459 | struct ark3116_private *priv = usb_get_serial_port_data(port); | ||
444 | struct serial_struct serstruct; | 460 | struct serial_struct serstruct; |
445 | void __user *user_arg = (void __user *)arg; | 461 | void __user *user_arg = (void __user *)arg; |
446 | 462 | ||
@@ -462,9 +478,48 @@ static int ark3116_ioctl(struct tty_struct *tty, struct file *file, | |||
462 | if (copy_from_user(&serstruct, user_arg, sizeof(serstruct))) | 478 | if (copy_from_user(&serstruct, user_arg, sizeof(serstruct))) |
463 | return -EFAULT; | 479 | return -EFAULT; |
464 | return 0; | 480 | return 0; |
465 | default: | 481 | case TIOCMIWAIT: |
466 | dbg("%s cmd 0x%04x not supported", __func__, cmd); | 482 | for (;;) { |
483 | struct async_icount prev = priv->icount; | ||
484 | interruptible_sleep_on(&priv->delta_msr_wait); | ||
485 | /* see if a signal did it */ | ||
486 | if (signal_pending(current)) | ||
487 | return -ERESTARTSYS; | ||
488 | if ((prev.rng == priv->icount.rng) && | ||
489 | (prev.dsr == priv->icount.dsr) && | ||
490 | (prev.dcd == priv->icount.dcd) && | ||
491 | (prev.cts == priv->icount.cts)) | ||
492 | return -EIO; | ||
493 | if ((arg & TIOCM_RNG && | ||
494 | (prev.rng != priv->icount.rng)) || | ||
495 | (arg & TIOCM_DSR && | ||
496 | (prev.dsr != priv->icount.dsr)) || | ||
497 | (arg & TIOCM_CD && | ||
498 | (prev.dcd != priv->icount.dcd)) || | ||
499 | (arg & TIOCM_CTS && | ||
500 | (prev.cts != priv->icount.cts))) | ||
501 | return 0; | ||
502 | } | ||
467 | break; | 503 | break; |
504 | case TIOCGICOUNT: { | ||
505 | struct serial_icounter_struct icount; | ||
506 | struct async_icount cnow = priv->icount; | ||
507 | memset(&icount, 0, sizeof(icount)); | ||
508 | icount.cts = cnow.cts; | ||
509 | icount.dsr = cnow.dsr; | ||
510 | icount.rng = cnow.rng; | ||
511 | icount.dcd = cnow.dcd; | ||
512 | icount.rx = cnow.rx; | ||
513 | icount.tx = cnow.tx; | ||
514 | icount.frame = cnow.frame; | ||
515 | icount.overrun = cnow.overrun; | ||
516 | icount.parity = cnow.parity; | ||
517 | icount.brk = cnow.brk; | ||
518 | icount.buf_overrun = cnow.buf_overrun; | ||
519 | if (copy_to_user(user_arg, &icount, sizeof(icount))) | ||
520 | return -EFAULT; | ||
521 | return 0; | ||
522 | } | ||
468 | } | 523 | } |
469 | 524 | ||
470 | return -ENOIOCTLCMD; | 525 | return -ENOIOCTLCMD; |
@@ -518,11 +573,13 @@ static struct usb_serial_driver ark3116_device = { | |||
518 | .usb_driver = &ark3116_driver, | 573 | .usb_driver = &ark3116_driver, |
519 | .num_ports = 1, | 574 | .num_ports = 1, |
520 | .attach = ark3116_attach, | 575 | .attach = ark3116_attach, |
576 | .release = ark3116_release, | ||
521 | .set_termios = ark3116_set_termios, | 577 | .set_termios = ark3116_set_termios, |
522 | .init_termios = ark3116_init_termios, | 578 | .init_termios = ark3116_init_termios, |
523 | .ioctl = ark3116_ioctl, | 579 | .ioctl = ark3116_ioctl, |
524 | .tiocmget = ark3116_tiocmget, | 580 | .tiocmget = ark3116_tiocmget, |
525 | .open = ark3116_open, | 581 | .open = ark3116_open, |
582 | .close = ark3116_close, | ||
526 | }; | 583 | }; |
527 | 584 | ||
528 | static int __init ark3116_init(void) | 585 | static int __init ark3116_init(void) |