Merge tag 'char-misc-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver patches from Greg Kroah-Hartman: "Here's the big char/misc driver patches for 3.9-rc1. Nothing major here, just lots of different driver updates (mei, hyperv, ipack, extcon, vmci, etc.). All of these have been in the linux-next tree for a while." * tag 'char-misc-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (209 commits) w1: w1_therm: Add force-pullup option for "broken" sensors w1: ds2482: Added 1-Wire pull-up support to the driver vme: add missing put_device() after device_register() fails extcon: max8997: Use workqueue to check cable state after completing boot of platform extcon: max8997: Set default UART/USB path on probe extcon: max8997: Consolidate duplicate code for checking ADC/CHG cable type extcon: max8997: Set default of ADC debounce time during initialization extcon: max8997: Remove duplicate code related to set H/W line path extcon: max8997: Move defined constant to header file extcon: max77693: Make max77693_extcon_cable static extcon: max8997: Remove unreachable code extcon: max8997: Make max8997_extcon_cable static extcon: max77693: Remove unnecessary goto statement to improve readability extcon: max77693: Convert to devm_input_allocate_device() extcon: gpio: Rename filename of extcon-gpio.c according to kernel naming style CREDITS: update email and address of Harald Hoyer extcon: arizona: Use MICDET for final microphone identification extcon: arizona: Always take the first HPDET reading as the final one extcon: arizona: Clear _trig_sts bits after jack detection extcon: arizona: Don't HPDET magic when headphones are enabled ...
This commit is contained in:
@@ -20,7 +20,6 @@
|
||||
#include <linux/serial.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ipack.h>
|
||||
#include "ipoctal.h"
|
||||
@@ -38,21 +37,19 @@ struct ipoctal_channel {
|
||||
spinlock_t lock;
|
||||
unsigned int pointer_read;
|
||||
unsigned int pointer_write;
|
||||
atomic_t open;
|
||||
struct tty_port tty_port;
|
||||
union scc2698_channel __iomem *regs;
|
||||
union scc2698_block __iomem *block_regs;
|
||||
unsigned int board_id;
|
||||
unsigned char *board_write;
|
||||
u8 isr_rx_rdy_mask;
|
||||
u8 isr_tx_rdy_mask;
|
||||
unsigned int rx_enable;
|
||||
};
|
||||
|
||||
struct ipoctal {
|
||||
struct ipack_device *dev;
|
||||
unsigned int board_id;
|
||||
struct ipoctal_channel channel[NR_CHANNELS];
|
||||
unsigned char write;
|
||||
struct tty_driver *tty_drv;
|
||||
u8 __iomem *mem8_space;
|
||||
u8 __iomem *int_space;
|
||||
@@ -64,28 +61,23 @@ static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty)
|
||||
|
||||
channel = dev_get_drvdata(tty->dev);
|
||||
|
||||
/*
|
||||
* Enable RX. TX will be enabled when
|
||||
* there is something to send
|
||||
*/
|
||||
iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
|
||||
channel->rx_enable = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipoctal_open(struct tty_struct *tty, struct file *file)
|
||||
{
|
||||
int res;
|
||||
struct ipoctal_channel *channel;
|
||||
|
||||
channel = dev_get_drvdata(tty->dev);
|
||||
|
||||
if (atomic_read(&channel->open))
|
||||
return -EBUSY;
|
||||
|
||||
tty->driver_data = channel;
|
||||
|
||||
res = tty_port_open(&channel->tty_port, tty, file);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
atomic_inc(&channel->open);
|
||||
return 0;
|
||||
return tty_port_open(&channel->tty_port, tty, file);
|
||||
}
|
||||
|
||||
static void ipoctal_reset_stats(struct ipoctal_stats *stats)
|
||||
@@ -111,9 +103,7 @@ static void ipoctal_close(struct tty_struct *tty, struct file *filp)
|
||||
struct ipoctal_channel *channel = tty->driver_data;
|
||||
|
||||
tty_port_close(&channel->tty_port, tty, filp);
|
||||
|
||||
if (atomic_dec_and_test(&channel->open))
|
||||
ipoctal_free_channel(channel);
|
||||
ipoctal_free_channel(channel);
|
||||
}
|
||||
|
||||
static int ipoctal_get_icount(struct tty_struct *tty,
|
||||
@@ -137,11 +127,12 @@ static void ipoctal_irq_rx(struct ipoctal_channel *channel, u8 sr)
|
||||
{
|
||||
struct tty_port *port = &channel->tty_port;
|
||||
unsigned char value;
|
||||
unsigned char flag = TTY_NORMAL;
|
||||
unsigned char flag;
|
||||
u8 isr;
|
||||
|
||||
do {
|
||||
value = ioread8(&channel->regs->r.rhr);
|
||||
flag = TTY_NORMAL;
|
||||
/* Error: count statistics */
|
||||
if (sr & SR_ERROR) {
|
||||
iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
|
||||
@@ -183,10 +174,8 @@ static void ipoctal_irq_tx(struct ipoctal_channel *channel)
|
||||
unsigned char value;
|
||||
unsigned int *pointer_write = &channel->pointer_write;
|
||||
|
||||
if (channel->nb_bytes <= 0) {
|
||||
channel->nb_bytes = 0;
|
||||
if (channel->nb_bytes == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
value = channel->tty_port.xmit_buf[*pointer_write];
|
||||
iowrite8(value, &channel->regs->w.thr);
|
||||
@@ -194,39 +183,27 @@ static void ipoctal_irq_tx(struct ipoctal_channel *channel)
|
||||
(*pointer_write)++;
|
||||
*pointer_write = *pointer_write % PAGE_SIZE;
|
||||
channel->nb_bytes--;
|
||||
|
||||
if ((channel->nb_bytes == 0) &&
|
||||
(waitqueue_active(&channel->queue))) {
|
||||
|
||||
if (channel->board_id != IPACK1_DEVICE_ID_SBS_OCTAL_485) {
|
||||
*channel->board_write = 1;
|
||||
wake_up_interruptible(&channel->queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ipoctal_irq_channel(struct ipoctal_channel *channel)
|
||||
{
|
||||
u8 isr, sr;
|
||||
|
||||
/* If there is no client, skip the check */
|
||||
if (!atomic_read(&channel->open))
|
||||
return;
|
||||
|
||||
spin_lock(&channel->lock);
|
||||
/* The HW is organized in pair of channels. See which register we need
|
||||
* to read from */
|
||||
isr = ioread8(&channel->block_regs->r.isr);
|
||||
sr = ioread8(&channel->regs->r.sr);
|
||||
|
||||
/* In case of RS-485, change from TX to RX when finishing TX.
|
||||
* Half-duplex. */
|
||||
if ((channel->board_id == IPACK1_DEVICE_ID_SBS_OCTAL_485) &&
|
||||
(sr & SR_TX_EMPTY) && (channel->nb_bytes == 0)) {
|
||||
if ((sr & SR_TX_EMPTY) && (channel->nb_bytes == 0)) {
|
||||
iowrite8(CR_DISABLE_TX, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_NEGATE_RTSN, &channel->regs->w.cr);
|
||||
iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
|
||||
*channel->board_write = 1;
|
||||
wake_up_interruptible(&channel->queue);
|
||||
/* In case of RS-485, change from TX to RX when finishing TX.
|
||||
* Half-duplex. */
|
||||
if (channel->board_id == IPACK1_DEVICE_ID_SBS_OCTAL_485) {
|
||||
iowrite8(CR_CMD_NEGATE_RTSN, &channel->regs->w.cr);
|
||||
iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
|
||||
channel->rx_enable = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* RX data */
|
||||
@@ -237,7 +214,7 @@ static void ipoctal_irq_channel(struct ipoctal_channel *channel)
|
||||
if ((isr & channel->isr_tx_rdy_mask) && (sr & SR_TX_READY))
|
||||
ipoctal_irq_tx(channel);
|
||||
|
||||
tty_flip_buffer_push(&channel->tty_port);
|
||||
spin_unlock(&channel->lock);
|
||||
}
|
||||
|
||||
static irqreturn_t ipoctal_irq_handler(void *arg)
|
||||
@@ -245,14 +222,14 @@ static irqreturn_t ipoctal_irq_handler(void *arg)
|
||||
unsigned int i;
|
||||
struct ipoctal *ipoctal = (struct ipoctal *) arg;
|
||||
|
||||
/* Check all channels */
|
||||
for (i = 0; i < NR_CHANNELS; i++)
|
||||
ipoctal_irq_channel(&ipoctal->channel[i]);
|
||||
|
||||
/* Clear the IPack device interrupt */
|
||||
readw(ipoctal->int_space + ACK_INT_REQ0);
|
||||
readw(ipoctal->int_space + ACK_INT_REQ1);
|
||||
|
||||
/* Check all channels */
|
||||
for (i = 0; i < NR_CHANNELS; i++)
|
||||
ipoctal_irq_channel(&ipoctal->channel[i]);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -306,7 +283,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
|
||||
ipoctal->mem8_space =
|
||||
devm_ioremap_nocache(&ipoctal->dev->dev,
|
||||
region->start, 0x8000);
|
||||
if (!addr) {
|
||||
if (!ipoctal->mem8_space) {
|
||||
dev_err(&ipoctal->dev->dev,
|
||||
"Unable to map slot [%d:%d] MEM8 space!\n",
|
||||
bus_nr, slot);
|
||||
@@ -319,7 +296,6 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
|
||||
struct ipoctal_channel *channel = &ipoctal->channel[i];
|
||||
channel->regs = chan_regs + i;
|
||||
channel->block_regs = block_regs + (i >> 1);
|
||||
channel->board_write = &ipoctal->write;
|
||||
channel->board_id = ipoctal->board_id;
|
||||
if (i & 1) {
|
||||
channel->isr_tx_rdy_mask = ISR_TxRDY_B;
|
||||
@@ -330,6 +306,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
|
||||
}
|
||||
|
||||
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
|
||||
channel->rx_enable = 0;
|
||||
iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
|
||||
iowrite8(MR1_CHRL_8_BITS | MR1_ERROR_CHAR | MR1_RxINT_RxRDY,
|
||||
@@ -402,8 +379,6 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
|
||||
|
||||
ipoctal_reset_stats(&channel->stats);
|
||||
channel->nb_bytes = 0;
|
||||
init_waitqueue_head(&channel->queue);
|
||||
|
||||
spin_lock_init(&channel->lock);
|
||||
channel->pointer_read = 0;
|
||||
channel->pointer_write = 0;
|
||||
@@ -414,12 +389,6 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
|
||||
continue;
|
||||
}
|
||||
dev_set_drvdata(tty_dev, channel);
|
||||
|
||||
/*
|
||||
* Enable again the RX. TX will be enabled when
|
||||
* there is something to send
|
||||
*/
|
||||
iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -459,6 +428,7 @@ static int ipoctal_write_tty(struct tty_struct *tty,
|
||||
/* As the IP-OCTAL 485 only supports half duplex, do it manually */
|
||||
if (channel->board_id == IPACK1_DEVICE_ID_SBS_OCTAL_485) {
|
||||
iowrite8(CR_DISABLE_RX, &channel->regs->w.cr);
|
||||
channel->rx_enable = 0;
|
||||
iowrite8(CR_CMD_ASSERT_RTSN, &channel->regs->w.cr);
|
||||
}
|
||||
|
||||
@@ -467,10 +437,6 @@ static int ipoctal_write_tty(struct tty_struct *tty,
|
||||
* operations
|
||||
*/
|
||||
iowrite8(CR_ENABLE_TX, &channel->regs->w.cr);
|
||||
wait_event_interruptible(channel->queue, *channel->board_write);
|
||||
iowrite8(CR_DISABLE_TX, &channel->regs->w.cr);
|
||||
|
||||
*channel->board_write = 0;
|
||||
return char_copied;
|
||||
}
|
||||
|
||||
@@ -622,8 +588,9 @@ static void ipoctal_set_termios(struct tty_struct *tty,
|
||||
iowrite8(mr2, &channel->regs->w.mr);
|
||||
iowrite8(csr, &channel->regs->w.csr);
|
||||
|
||||
/* Enable again the RX */
|
||||
iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
|
||||
/* Enable again the RX, if it was before */
|
||||
if (channel->rx_enable)
|
||||
iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
|
||||
}
|
||||
|
||||
static void ipoctal_hangup(struct tty_struct *tty)
|
||||
@@ -643,6 +610,7 @@ static void ipoctal_hangup(struct tty_struct *tty)
|
||||
tty_port_hangup(&channel->tty_port);
|
||||
|
||||
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
|
||||
channel->rx_enable = 0;
|
||||
iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
|
||||
@@ -652,6 +620,22 @@ static void ipoctal_hangup(struct tty_struct *tty)
|
||||
wake_up_interruptible(&channel->tty_port.open_wait);
|
||||
}
|
||||
|
||||
static void ipoctal_shutdown(struct tty_struct *tty)
|
||||
{
|
||||
struct ipoctal_channel *channel = tty->driver_data;
|
||||
|
||||
if (channel == NULL)
|
||||
return;
|
||||
|
||||
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
|
||||
channel->rx_enable = 0;
|
||||
iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr);
|
||||
clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags);
|
||||
}
|
||||
|
||||
static const struct tty_operations ipoctal_fops = {
|
||||
.ioctl = NULL,
|
||||
.open = ipoctal_open,
|
||||
@@ -662,6 +646,7 @@ static const struct tty_operations ipoctal_fops = {
|
||||
.chars_in_buffer = ipoctal_chars_in_buffer,
|
||||
.get_icount = ipoctal_get_icount,
|
||||
.hangup = ipoctal_hangup,
|
||||
.shutdown = ipoctal_shutdown,
|
||||
};
|
||||
|
||||
static int ipoctal_probe(struct ipack_device *dev)
|
||||
|
مرجع در شماره جدید
Block a user