158 printk(KERN_INFO PFX "Module unloading.\n"); |
158 printk(KERN_INFO PFX "Module unloading.\n"); |
159 } |
159 } |
160 |
160 |
161 /*****************************************************************************/ |
161 /*****************************************************************************/ |
162 |
162 |
|
163 void ec_tty_wakeup(unsigned long data) |
|
164 { |
|
165 ec_tty_t *tty = (ec_tty_t *) data; |
|
166 |
|
167 if (tty->wakeup) { |
|
168 if (tty->tty) { |
|
169 printk("Waking up.\n"); |
|
170 tty_wakeup(tty->tty); |
|
171 } |
|
172 tty->wakeup = 0; |
|
173 } |
|
174 |
|
175 tty->timer.expires += 1; |
|
176 add_timer(&tty->timer); |
|
177 } |
|
178 |
|
179 /*****************************************************************************/ |
|
180 |
163 int ec_tty_init(ec_tty_t *tty, int minor) |
181 int ec_tty_init(ec_tty_t *tty, int minor) |
164 { |
182 { |
165 tty->minor = minor; |
183 tty->minor = minor; |
|
184 tty->tx_read_idx = 0; |
|
185 tty->tx_write_idx = 0; |
|
186 tty->wakeup = 0; |
|
187 init_timer(&tty->timer); |
|
188 tty->tty = NULL; |
166 |
189 |
167 tty->dev = tty_register_device(tty_driver, tty->minor, NULL); |
190 tty->dev = tty_register_device(tty_driver, tty->minor, NULL); |
168 if (IS_ERR(tty->dev)) { |
191 if (IS_ERR(tty->dev)) { |
169 printk(KERN_ERR PFX "Failed to register tty device.\n"); |
192 printk(KERN_ERR PFX "Failed to register tty device.\n"); |
170 return PTR_ERR(tty->dev); |
193 return PTR_ERR(tty->dev); |
171 } |
194 } |
172 |
195 |
|
196 tty->timer.function = ec_tty_wakeup; |
|
197 tty->timer.data = (unsigned long) tty; |
|
198 tty->timer.expires = jiffies + 10; |
|
199 add_timer(&tty->timer); |
173 return 0; |
200 return 0; |
174 } |
201 } |
175 |
202 |
176 /*****************************************************************************/ |
203 /*****************************************************************************/ |
177 |
204 |
178 void ec_tty_clear(ec_tty_t *tty) |
205 void ec_tty_clear(ec_tty_t *tty) |
179 { |
206 { |
|
207 del_timer_sync(&tty->timer); |
180 tty_unregister_device(tty_driver, tty->minor); |
208 tty_unregister_device(tty_driver, tty->minor); |
|
209 } |
|
210 |
|
211 /*****************************************************************************/ |
|
212 |
|
213 unsigned int ec_tty_tx_size(ec_tty_t *tty) |
|
214 { |
|
215 unsigned int ret; |
|
216 |
|
217 if (tty->tx_write_idx >= tty->tx_read_idx) { |
|
218 ret = tty->tx_write_idx - tty->tx_read_idx; |
|
219 } else { |
|
220 ret = EC_TTY_TX_BUFFER_SIZE + tty->tx_write_idx - tty->tx_read_idx; |
|
221 } |
|
222 |
|
223 return ret; |
|
224 } |
|
225 |
|
226 /*****************************************************************************/ |
|
227 |
|
228 unsigned int ec_tty_tx_space(ec_tty_t *tty) |
|
229 { |
|
230 return EC_TTY_TX_BUFFER_SIZE - 1 - ec_tty_tx_size(tty); |
181 } |
231 } |
182 |
232 |
183 /****************************************************************************** |
233 /****************************************************************************** |
184 * Device callbacks |
234 * Device callbacks |
185 *****************************************************************************/ |
235 *****************************************************************************/ |
198 t = ttys[line]; |
248 t = ttys[line]; |
199 if (!t) { |
249 if (!t) { |
200 return -ENXIO; |
250 return -ENXIO; |
201 } |
251 } |
202 |
252 |
|
253 if (t->tty) { |
|
254 return -EBUSY; |
|
255 } |
|
256 |
|
257 t->tty = tty; |
203 tty->driver_data = t; |
258 tty->driver_data = t; |
204 return 0; |
259 return 0; |
205 } |
260 } |
206 |
261 |
207 /*****************************************************************************/ |
262 /*****************************************************************************/ |
208 |
263 |
209 static void ec_tty_close(struct tty_struct *tty, struct file *file) |
264 static void ec_tty_close(struct tty_struct *tty, struct file *file) |
210 { |
265 { |
|
266 ec_tty_t *t = (ec_tty_t *) tty->driver_data; |
|
267 |
211 printk(KERN_INFO PFX "Closing line %i.\n", tty->index); |
268 printk(KERN_INFO PFX "Closing line %i.\n", tty->index); |
|
269 |
|
270 if (t->tty == tty) { |
|
271 t->tty = NULL; |
|
272 } |
212 } |
273 } |
213 |
274 |
214 /*****************************************************************************/ |
275 /*****************************************************************************/ |
215 |
276 |
216 static int ec_tty_write( |
277 static int ec_tty_write( |
217 struct tty_struct *tty, |
278 struct tty_struct *tty, |
218 const unsigned char *buffer, |
279 const unsigned char *buffer, |
219 int count |
280 int count |
220 ) |
281 ) |
221 { |
282 { |
222 return -EIO; |
283 ec_tty_t *t = (ec_tty_t *) tty->driver_data; |
223 } |
284 unsigned int data_size, i; |
|
285 |
|
286 printk(KERN_INFO PFX "%s(count=%i)\n", __func__, count); |
|
287 |
|
288 if (count <= 0) { |
|
289 return 0; |
|
290 } |
|
291 |
|
292 data_size = min(ec_tty_tx_space(t), (unsigned int) count); |
|
293 for (i = 0; i < data_size; i++) { |
|
294 t->tx_buffer[t->tx_write_idx] = buffer[i]; |
|
295 t->tx_write_idx = (t->tx_write_idx + 1) % EC_TTY_TX_BUFFER_SIZE; |
|
296 } |
|
297 |
|
298 printk(KERN_INFO PFX "%s(): %u bytes written.\n", __func__, data_size); |
|
299 return data_size; |
|
300 } |
|
301 |
|
302 /*****************************************************************************/ |
|
303 |
|
304 static void ec_tty_put_char(struct tty_struct *tty, unsigned char ch) |
|
305 { |
|
306 ec_tty_t *t = (ec_tty_t *) tty->driver_data; |
|
307 |
|
308 printk(KERN_INFO PFX "%s(): c=%02x.\n", __func__, (unsigned int) ch); |
|
309 |
|
310 if (ec_tty_tx_space(t)) { |
|
311 t->tx_buffer[t->tx_write_idx] = ch; |
|
312 t->tx_write_idx = (t->tx_write_idx + 1) % EC_TTY_TX_BUFFER_SIZE; |
|
313 } else { |
|
314 printk(KERN_WARNING PFX "%s(): Dropped a byte!\n", __func__); |
|
315 } |
|
316 } |
|
317 |
|
318 /*****************************************************************************/ |
|
319 |
|
320 static int ec_tty_write_room(struct tty_struct *tty) |
|
321 { |
|
322 ec_tty_t *t = (ec_tty_t *) tty->driver_data; |
|
323 int ret = ec_tty_tx_space(t); |
|
324 |
|
325 printk(KERN_INFO PFX "%s() = %i.\n", __func__, ret); |
|
326 |
|
327 return ret; |
|
328 } |
|
329 |
|
330 /*****************************************************************************/ |
|
331 |
|
332 static int ec_tty_chars_in_buffer(struct tty_struct *tty) |
|
333 { |
|
334 ec_tty_t *t = (ec_tty_t *) tty->driver_data; |
|
335 int ret; |
|
336 |
|
337 printk(KERN_INFO PFX "%s().\n", __func__); |
|
338 |
|
339 ret = ec_tty_tx_size(t); |
|
340 |
|
341 printk(KERN_INFO PFX "%s() = %i.\n", __func__, ret); |
|
342 |
|
343 return ret; |
|
344 } |
|
345 |
|
346 /*****************************************************************************/ |
|
347 |
|
348 static void ec_tty_flush_buffer(struct tty_struct *tty) |
|
349 { |
|
350 printk(KERN_INFO PFX "%s().\n", __func__); |
|
351 } |
|
352 |
|
353 /*****************************************************************************/ |
|
354 |
|
355 static int ec_tty_ioctl(struct tty_struct *tty, struct file *file, |
|
356 unsigned int cmd, unsigned long arg) |
|
357 { |
|
358 printk(KERN_INFO PFX "%s().\n", __func__); |
|
359 return -ENOTTY; |
|
360 } |
|
361 |
|
362 /*****************************************************************************/ |
|
363 |
|
364 static void ec_tty_throttle(struct tty_struct *tty) |
|
365 { |
|
366 printk(KERN_INFO PFX "%s().\n", __func__); |
|
367 } |
|
368 |
|
369 /*****************************************************************************/ |
|
370 |
|
371 static void ec_tty_unthrottle(struct tty_struct *tty) |
|
372 { |
|
373 printk(KERN_INFO PFX "%s().\n", __func__); |
|
374 } |
|
375 |
|
376 /*****************************************************************************/ |
|
377 |
|
378 static void ec_tty_set_termios(struct tty_struct *tty, |
|
379 struct ktermios *old_termios) |
|
380 { |
|
381 printk(KERN_INFO PFX "%s().\n", __func__); |
|
382 } |
|
383 |
|
384 /*****************************************************************************/ |
|
385 |
|
386 static void ec_tty_stop(struct tty_struct *tty) |
|
387 { |
|
388 printk(KERN_INFO PFX "%s().\n", __func__); |
|
389 } |
|
390 |
|
391 /*****************************************************************************/ |
|
392 |
|
393 static void ec_tty_start(struct tty_struct *tty) |
|
394 { |
|
395 printk(KERN_INFO PFX "%s().\n", __func__); |
|
396 } |
|
397 |
|
398 /*****************************************************************************/ |
|
399 |
|
400 static void ec_tty_hangup(struct tty_struct *tty) |
|
401 { |
|
402 printk(KERN_INFO PFX "%s().\n", __func__); |
|
403 } |
|
404 |
|
405 /*****************************************************************************/ |
|
406 |
|
407 static void ec_tty_break(struct tty_struct *tty, int break_state) |
|
408 { |
|
409 printk(KERN_INFO PFX "%s(break_state = %i).\n", __func__, break_state); |
|
410 } |
|
411 |
|
412 /*****************************************************************************/ |
|
413 |
|
414 static void ec_tty_send_xchar(struct tty_struct *tty, char ch) |
|
415 { |
|
416 printk(KERN_INFO PFX "%s(ch=%02x).\n", __func__, (unsigned int) ch); |
|
417 } |
|
418 |
|
419 /*****************************************************************************/ |
|
420 |
|
421 static void ec_tty_wait_until_sent(struct tty_struct *tty, int timeout) |
|
422 { |
|
423 printk(KERN_INFO PFX "%s(timeout=%i).\n", __func__, timeout); |
|
424 } |
|
425 |
|
426 /*****************************************************************************/ |
|
427 |
|
428 static int ec_tty_tiocmget(struct tty_struct *tty, struct file *file) |
|
429 { |
|
430 printk(KERN_INFO PFX "%s().\n", __func__); |
|
431 return -EBUSY; |
|
432 } |
|
433 |
|
434 /*****************************************************************************/ |
|
435 |
|
436 static int ec_tty_tiocmset(struct tty_struct *tty, struct file *file, |
|
437 unsigned int set, unsigned int clear) |
|
438 { |
|
439 printk(KERN_INFO PFX "%s(set=%u, clear=%u).\n", __func__, set, clear); |
|
440 return -EBUSY; |
|
441 } |
|
442 |
|
443 /*****************************************************************************/ |
|
444 |
|
445 static const struct tty_operations ec_tty_ops = { |
|
446 .open = ec_tty_open, |
|
447 .close = ec_tty_close, |
|
448 .write = ec_tty_write, |
|
449 .put_char = ec_tty_put_char, |
|
450 .write_room = ec_tty_write_room, |
|
451 .chars_in_buffer = ec_tty_chars_in_buffer, |
|
452 .flush_buffer = ec_tty_flush_buffer, |
|
453 .ioctl = ec_tty_ioctl, |
|
454 .throttle = ec_tty_throttle, |
|
455 .unthrottle = ec_tty_unthrottle, |
|
456 .set_termios = ec_tty_set_termios, |
|
457 .stop = ec_tty_stop, |
|
458 .start = ec_tty_start, |
|
459 .hangup = ec_tty_hangup, |
|
460 .break_ctl = ec_tty_break, |
|
461 .send_xchar = ec_tty_send_xchar, |
|
462 .wait_until_sent = ec_tty_wait_until_sent, |
|
463 .tiocmget = ec_tty_tiocmget, |
|
464 .tiocmset = ec_tty_tiocmset, |
|
465 }; |
224 |
466 |
225 /****************************************************************************** |
467 /****************************************************************************** |
226 * Public functions and methods |
468 * Public functions and methods |
227 *****************************************************************************/ |
469 *****************************************************************************/ |
228 |
470 |
264 |
508 |
265 /*****************************************************************************/ |
509 /*****************************************************************************/ |
266 |
510 |
267 void ectty_free(ec_tty_t *tty) |
511 void ectty_free(ec_tty_t *tty) |
268 { |
512 { |
|
513 printk(KERN_INFO PFX "Freeing TTY interface %i.\n", tty->minor); |
|
514 |
269 ec_tty_clear(tty); |
515 ec_tty_clear(tty); |
270 ttys[tty->minor] = NULL; |
516 ttys[tty->minor] = NULL; |
271 kfree(tty); |
517 kfree(tty); |
272 } |
518 } |
273 |
519 |
274 /*****************************************************************************/ |
520 /*****************************************************************************/ |
275 |
521 |
|
522 unsigned int ectty_tx_data(ec_tty_t *tty, uint8_t *buffer, size_t size) |
|
523 { |
|
524 unsigned int data_size = min(ec_tty_tx_size(tty), size), i; |
|
525 |
|
526 if (data_size) { |
|
527 printk(KERN_INFO PFX "Fetching %u bytes to send.\n", data_size); |
|
528 } |
|
529 |
|
530 for (i = 0; i < data_size; i++) { |
|
531 buffer[i] = tty->tx_buffer[tty->tx_read_idx]; |
|
532 tty->tx_read_idx = (tty->tx_read_idx + 1) % EC_TTY_TX_BUFFER_SIZE; |
|
533 } |
|
534 |
|
535 if (data_size) { |
|
536 tty->wakeup = 1; |
|
537 } |
|
538 |
|
539 return data_size; |
|
540 } |
|
541 |
|
542 /*****************************************************************************/ |
|
543 |
276 /** \cond */ |
544 /** \cond */ |
277 |
545 |
278 module_init(ec_tty_init_module); |
546 module_init(ec_tty_init_module); |
279 module_exit(ec_tty_cleanup_module); |
547 module_exit(ec_tty_cleanup_module); |
280 |
548 |
281 EXPORT_SYMBOL(ectty_create); |
549 EXPORT_SYMBOL(ectty_create); |
282 EXPORT_SYMBOL(ectty_free); |
550 EXPORT_SYMBOL(ectty_free); |
|
551 EXPORT_SYMBOL(ectty_tx_data); |
283 |
552 |
284 /** \endcond */ |
553 /** \endcond */ |
285 |
554 |
286 /*****************************************************************************/ |
555 /*****************************************************************************/ |