You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
(1) |
Apr
(104) |
May
(81) |
Jun
(248) |
Jul
(133) |
Aug
(33) |
Sep
(53) |
Oct
(82) |
Nov
(166) |
Dec
(71) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2002 |
Jan
(121) |
Feb
(42) |
Mar
(39) |
Apr
(84) |
May
(87) |
Jun
(58) |
Jul
(97) |
Aug
(130) |
Sep
(32) |
Oct
(139) |
Nov
(108) |
Dec
(216) |
2003 |
Jan
(299) |
Feb
(136) |
Mar
(392) |
Apr
(141) |
May
(137) |
Jun
(107) |
Jul
(94) |
Aug
(262) |
Sep
(300) |
Oct
(216) |
Nov
(72) |
Dec
(94) |
2004 |
Jan
(174) |
Feb
(192) |
Mar
(215) |
Apr
(314) |
May
(319) |
Jun
(293) |
Jul
(205) |
Aug
(161) |
Sep
(192) |
Oct
(226) |
Nov
(308) |
Dec
(89) |
2005 |
Jan
(127) |
Feb
(269) |
Mar
(588) |
Apr
(106) |
May
(77) |
Jun
(77) |
Jul
(161) |
Aug
(239) |
Sep
(86) |
Oct
(112) |
Nov
(153) |
Dec
(145) |
2006 |
Jan
(87) |
Feb
(57) |
Mar
(129) |
Apr
(109) |
May
(102) |
Jun
(232) |
Jul
(97) |
Aug
(69) |
Sep
(67) |
Oct
(69) |
Nov
(214) |
Dec
(82) |
2007 |
Jan
(133) |
Feb
(307) |
Mar
(121) |
Apr
(171) |
May
(229) |
Jun
(156) |
Jul
(185) |
Aug
(160) |
Sep
(122) |
Oct
(130) |
Nov
(78) |
Dec
(27) |
2008 |
Jan
(105) |
Feb
(137) |
Mar
(146) |
Apr
(148) |
May
(239) |
Jun
(208) |
Jul
(157) |
Aug
(244) |
Sep
(119) |
Oct
(125) |
Nov
(189) |
Dec
(225) |
2009 |
Jan
(157) |
Feb
(139) |
Mar
(106) |
Apr
(130) |
May
(246) |
Jun
(189) |
Jul
(128) |
Aug
(127) |
Sep
(88) |
Oct
(86) |
Nov
(216) |
Dec
(9) |
2010 |
Jan
(5) |
Feb
|
Mar
(11) |
Apr
(31) |
May
(3) |
Jun
|
Jul
(7) |
Aug
|
Sep
(1) |
Oct
|
Nov
(1) |
Dec
|
2012 |
Jan
|
Feb
|
Mar
(3) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2013 |
Jan
(1) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Krzysztof H. <krz...@wp...> - 2009-10-03 04:51:55
|
On Thu, 24 Sep 2009 16:37:10 +0530 Jaswinder Singh Rajput <jas...@ke...> wrote: > > fix the following 'make includecheck' warning: > > drivers/video/da8xx-fb.c: linux/device.h is included more than once. > > Signed-off-by: Jaswinder Singh Rajput <jas...@gm...> > Cc: Kevin Hilman <kh...@de...> > Cc: Krzysztof Helt <krz...@wp...> > Cc: Pavel Kiryukhin <pki...@ru...> > Cc: Steve Chen <sc...@mv...> > Cc: Sudhakar Rajashekhara <sud...@ti...> > Cc: Andrew Morton <ak...@li...> > --- > drivers/video/da8xx-fb.c | 1 - > 1 files changed, 0 insertions(+), 1 deletions(-) > Acked-by: Krzysztof Helt <krz...@wp...> |
From: Krzysztof H. <krz...@po...> - 2009-10-03 04:50:40
|
On Sun, 27 Sep 2009 11:15:20 +0800 Huang Weiyi <wei...@gm...> wrote: > Remove duplicated #include('s) in > drivers/video/msm/mddi.c > > Signed-off-by: Huang Weiyi <wei...@gm...> > --- > drivers/video/msm/mddi.c | 1 - > 1 files changed, 0 insertions(+), 1 deletions(-) > Acked-by: Krzysztof Helt <krz...@wp...> --------------------------------------------------------------- Przygotuj siê na przysz³o¶æ! Kliknij >>> http://link.interia.pl/f238a |
From: Krzysztof H. <krz...@po...> - 2009-10-03 04:48:08
|
On Thu, 01 Oct 2009 00:41:41 -0700 Alessio Sangalli <al...@ma...> wrote: > Hi, is there a standard way for a userspace program to "probe" the > supported display sizes/refresh rates/bit depths? The display I'm > writing a driver for only supports a few specific resolutions, and I'm > wondering how a userspace program can discover those. > I am not aware of such a probe function. E.g. the xorg fbdev driver just tries to select list of defined resolutions and select only the available ones. If your list of resolutions and depths is limited to few entries you can try this approach as well. Regards, Krzysztof ---------------------------------------------------------------------- Afera Hazardowa- O co tu chodzi? Sprawdz >>> http://link.interia.pl/f238e |
From: Philipp R. <phi...@li...> - 2009-10-02 22:12:27
|
Signed-off-by: Philipp Reisner <phi...@li...> --- drivers/md/dm-log-userspace-transfer.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c index 1327e1a..54abf9e 100644 --- a/drivers/md/dm-log-userspace-transfer.c +++ b/drivers/md/dm-log-userspace-transfer.c @@ -133,6 +133,9 @@ static void cn_ulog_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1); + if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) + return; + spin_lock(&receiving_list_lock); if (msg->len == 0) fill_pkg(msg, NULL); -- 1.6.0.4 |
From: Jonathan B. <jbr...@re...> - 2009-10-02 20:47:15
|
This patch (and "[dm-devel] [PATCH 3/8] connector/dm: Fixed a compilation warning") will likely collide with an earlier patch (which agk is pushing) to fix the compilation warning (https://www.redhat.com/archives/dm-devel/2009-September/msg00218.html ), but the fix-up will be trivial. The dm-log-userspace code checks that incoming messages correspond to requests that were sent to userspace by way of a sequence number. If they don't correspond, they are dropped. So, you must be able to receive the messages from this kernel module (be root) in order to be able respond with a message that will be accepted. I can't completely rule out the ability to guess a sequence number, and be able to beat the log daemon in responding while the window of that sequence number's validity is open though... If someone could manage to pull this off with accuracy, they could disrupt the creation of a device, mimic a log device failure, or cause mirror resynchronization to occur to a different area that may simultaneously be performing a write (potential data corruption of a mirror). It would be an impressive feat to accomplish this, but I very much welcome the patch rather than test fate. Reviewed-by: Jonathan Brassow <jbr...@re...> brassow On Oct 2, 2009, at 7:40 AM, Philipp Reisner wrote: > Signed-off-by: Philipp Reisner <phi...@li...> > --- > drivers/md/dm-log-userspace-transfer.c | 3 +++ > 1 files changed, 3 insertions(+), 0 deletions(-) > > diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm- > log-userspace-transfer.c > index 1327e1a..54abf9e 100644 > --- a/drivers/md/dm-log-userspace-transfer.c > +++ b/drivers/md/dm-log-userspace-transfer.c > @@ -133,6 +133,9 @@ static void cn_ulog_callback(struct cn_msg *msg, > struct netlink_skb_parms *nsp) > { > struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1); > > + if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) > + return; > + > spin_lock(&receiving_list_lock); > if (msg->len == 0) > fill_pkg(msg, NULL); > -- > 1.6.0.4 > > -- > dm-devel mailing list > dm-...@re... > https://www.redhat.com/mailman/listinfo/dm-devel |
From: Greg KH <gr...@kr...> - 2009-10-02 19:50:42
|
On Fri, Oct 02, 2009 at 05:54:12PM +0200, Philipp Reisner wrote: > > On Fri, Oct 02, 2009 at 02:40:03PM +0200, Philipp Reisner wrote: > > > Affected: All code that uses connector, in kernel and out of mainline > > > > > > The connector, as it is today, does not allow the in kernel receiving > > > parts to do any checks on privileges of a message's sender. > > > > So, assume I know nothing about the connector architecture, what does > > this mean in a security context? > > > > Think of the connector as a layer on top of netlink that allows more > than a hard coded number of subsystems to use netlink. > > Netlink is used e.g. to modify routing tables in the kernel. > > As it is today, subsystem utilising the connector can not examine > the capabilities of the user/program that sent the netlink message. > > If the same would be true for netlink, than every unprivileged user > could change the routing tables on your box. > > > > I know, there are not many out there that like connector, but as > > > long as it is in the kernel, we have to fix the security issues it has! > > > > And what specifically are the security issues? > > > > unprivileged users can trigger operations that are supposed to be only > accessible to users having CAP_SYS_ADMIN (or some other CAP_XXX) Ok, but it doesn't look like there are that many connector operations right now, right? Anyway, I have no objection to the patches, and figure they should go through David's network tree. thanks, greg k-h |
From: Lars E. <lar...@li...> - 2009-10-02 18:51:08
|
On Fri, Oct 02, 2009 at 06:58:59AM -0700, Greg KH wrote: > On Fri, Oct 02, 2009 at 02:40:03PM +0200, Philipp Reisner wrote: > > Affected: All code that uses connector, in kernel and out of mainline > > > > The connector, as it is today, does not allow the in kernel receiving > > parts to do any checks on privileges of a message's sender. > > So, assume I know nothing about the connector architecture, what does > this mean in a security context? Arbitrary unprivileged users may craft a netlink message, which gets delivered through connector to callbacks (registered in kernel with cn_add_callback). These callbacks will then act on the message, as if it originated from an "expected" source. But currently there is no mechanism to verify the origin, even if the callbacks would try to. > > I know, there are not many out there that like connector, but as > > long as it is in the kernel, we have to fix the security issues it has! > > And what specifically are the security issues? For the cn_ulog_callback (dm-log-userspace-transfer.c), someone would be able to fake completion (with or without error code) of ulog entries, copying arbitrary data into receiving_pkg entries. /* * This is the connector callback that delivers data * that was sent from userspace. */ static void cn_ulog_callback(void *data) { struct cn_msg *msg = (struct cn_msg *)data; struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1); spin_lock(&receiving_list_lock); if (msg->len == 0) fill_pkg(msg, NULL); else if (msg->len < sizeof(*tfr)) DMERR("Incomplete message received (expected %u, got %u): [%u]", (unsigned)sizeof(*tfr), msg->len, msg->seq); else fill_pkg(NULL, tfr); spin_unlock(&receiving_list_lock); } static int fill_pkg(struct cn_msg *msg, struct dm_ulog_request *tfr) { uint32_t rtn_seq = (msg) ? msg->seq : (tfr) ? tfr->seq : 0; ... } else { pkg->error = tfr->error; memcpy(pkg->data, tfr->data, tfr->data_size); *(pkg->data_size) = tfr->data_size; } complete(&pkg->complete); should make that obvious: if an unprivileged user can deliver arbitrary msg to cn_ulog_callback, that should at least be disruptive to services that use it. fix: check origin of message for proper credentials (e.g. CAP_SYS_ADMIN). what or how much damage a crafted message can do in uvesafb_cn_callback, I'm not sure. But, if I get the msg->seq right, and get by the first sanity check, again, arbitrary input is copied into some kernel object, which will likely at least confuse that subsystem, maybe do damage, or result in some sort of denial of service. I just don't know what these uvesafb_ktask do, but I doubt that anyone but root should be able to manipulate them. in the case of dst and pohemlfs, it is (re|de) configuration of respective in kernel objects, possibly exposing arbitrary data content @Evgeniy - is that statement correct? Does something prevent an unprivileged user to export arbitrary things via dst? At least some sort of denial of service should be possible there. for DRBD, we have of course similar problems as long as we use the connector in its current form as our configuration choice. I'm not sure what actual harm can be done by arbitrary calling w1_reset_select_slave(), or w1_process_command_io(), but allowing unprivileged users to meddle with arbitrary devices is most likely not the intended behaviour there, either. The "obvious" way was to first make the credentials and capabilities of the message origin available to these callbacks, and then test on "CAP_SYS_ADMIN". Note that the suggested usage of the connector for _userspace_ tools is to bind() to some netlink socket, subscribing to apropriate mutlicast groups, which will usually fail for unprivileged users in netlink_bind() because of /* Only superuser is allowed to listen multicasts */ if (nladdr->nl_groups) { if (!netlink_capable(sock, NL_NONROOT_RECV)) return -EPERM; err = netlink_realloc_groups(sk); if (err) return err; } So typical userspace tools will fail when used as non-root. But if you leave out the bind, you are perfectly able to _send_ arbitrary messages on that socket, even if you are not able to receive any replies from connector kernel space in that case. Cheers, Lars |
From: Greg KH <gr...@kr...> - 2009-10-02 18:39:50
|
On Fri, Oct 02, 2009 at 11:05:04AM -0700, David Miller wrote: > From: Greg KH <gr...@kr...> > Date: Fri, 2 Oct 2009 11:00:22 -0700 > > > On Fri, Oct 02, 2009 at 10:56:59AM -0700, David Miller wrote: > >> All applied to net-2.6, I'll push this out to Linus later > >> today. > > > > Should it also go to -stable? If so, I can pick it up once it hits > > Linus's tree. > > Yes, please take it into -stable. Will do. > Greg, I'll also send you a batch of other networking bits > for -stable later this afternoon as well, just FYI... Great, I'll queue it up for the next -stable releases, these are full enough as it is already :) thanks, greg k-h |
From: Philipp R. <phi...@li...> - 2009-10-02 18:21:07
|
> On Fri, Oct 02, 2009 at 02:40:03PM +0200, Philipp Reisner wrote: > > Affected: All code that uses connector, in kernel and out of mainline > > > > The connector, as it is today, does not allow the in kernel receiving > > parts to do any checks on privileges of a message's sender. > > So, assume I know nothing about the connector architecture, what does > this mean in a security context? > Think of the connector as a layer on top of netlink that allows more than a hard coded number of subsystems to use netlink. Netlink is used e.g. to modify routing tables in the kernel. As it is today, subsystem utilising the connector can not examine the capabilities of the user/program that sent the netlink message. If the same would be true for netlink, than every unprivileged user could change the routing tables on your box. > > I know, there are not many out there that like connector, but as > > long as it is in the kernel, we have to fix the security issues it has! > > And what specifically are the security issues? > unprivileged users can trigger operations that are supposed to be only accessible to users having CAP_SYS_ADMIN (or some other CAP_XXX) > > Please either drop connector, or someone who feels a bit responsible > > and has our beloved dictator's blessing, PLEASE PLEASE PLEASE take > > this into your tree, and send the pull request to Linus. > > > > Patches 1 to 4 are already Acked-by Evgeny, the connector's maintainer. > > Patches 5 to 7 are the obvious fixes to the connector user's code. > > Obvious in what way? > They limit processing of connector/netlink messages in these subsystems to messages sent from root (or some user having CAP_SYS_ADMIN). That is obvious for dst, because device setup and destruction is done by connector messages. This is obvious for pohmelfs becuase these connector messages are used there to change some configuration. This is obvious for uvesafb because the connector messages are used there to delegate some video bios emulation to userspace. Last not least dm's dirty logging in user space, should be immune to some crafted netlink packets sent by some unprivileged user. Patches 1 to 4 fix the framework, should be merged as soon as possible. Patches 5 to 8 (not 7) should probably be blessed by the affected subsystem's maintainers. I think I have put all on CC. HTH. -phil |
From: David M. <da...@da...> - 2009-10-02 18:18:26
|
From: Greg KH <gr...@kr...> Date: Fri, 2 Oct 2009 11:00:22 -0700 > On Fri, Oct 02, 2009 at 10:56:59AM -0700, David Miller wrote: >> All applied to net-2.6, I'll push this out to Linus later >> today. > > Should it also go to -stable? If so, I can pick it up once it hits > Linus's tree. Yes, please take it into -stable. Greg, I'll also send you a batch of other networking bits for -stable later this afternoon as well, just FYI... |
From: David M. <da...@da...> - 2009-10-02 18:13:29
|
From: Philipp Reisner <phi...@li...> Date: Fri, 2 Oct 2009 17:54:12 +0200 > Think of the connector as a layer on top of netlink that allows more > than a hard coded number of subsystems to use netlink. There are no such limits in netlink, we have 'genetlink' which allows an arbitrary number of subsystems to use netlink. What connector provides over netlink/genetlink is something different altogether. |
From: David M. <da...@da...> - 2009-10-02 18:03:29
|
From: Philipp Reisner <phi...@li...> Date: Fri, 2 Oct 2009 14:40:03 +0200 > Affected: All code that uses connector, in kernel and out of mainline > > The connector, as it is today, does not allow the in kernel receiving > parts to do any checks on privileges of a message's sender. > > I know, there are not many out there that like connector, but as > long as it is in the kernel, we have to fix the security issues it has! > > Please either drop connector, or someone who feels a bit responsible > and has our beloved dictator's blessing, PLEASE PLEASE PLEASE take > this into your tree, and send the pull request to Linus. > > Patches 1 to 4 are already Acked-by Evgeny, the connector's maintainer. > Patches 5 to 7 are the obvious fixes to the connector user's code. > > For convenience these patches are also available as git tree: > git://git.drbd.org/linux-2.6-drbd.git connector-fix All applied to net-2.6, I'll push this out to Linus later today. |
From: Greg KH <gr...@kr...> - 2009-10-02 18:03:03
|
On Fri, Oct 02, 2009 at 10:56:59AM -0700, David Miller wrote: > From: Philipp Reisner <phi...@li...> > Date: Fri, 2 Oct 2009 14:40:03 +0200 > > > Affected: All code that uses connector, in kernel and out of mainline > > > > The connector, as it is today, does not allow the in kernel receiving > > parts to do any checks on privileges of a message's sender. > > > > I know, there are not many out there that like connector, but as > > long as it is in the kernel, we have to fix the security issues it has! > > > > Please either drop connector, or someone who feels a bit responsible > > and has our beloved dictator's blessing, PLEASE PLEASE PLEASE take > > this into your tree, and send the pull request to Linus. > > > > Patches 1 to 4 are already Acked-by Evgeny, the connector's maintainer. > > Patches 5 to 7 are the obvious fixes to the connector user's code. > > > > For convenience these patches are also available as git tree: > > git://git.drbd.org/linux-2.6-drbd.git connector-fix > > All applied to net-2.6, I'll push this out to Linus later > today. Should it also go to -stable? If so, I can pick it up once it hits Linus's tree. thanks, greg k-h |
From: Greg KH <gr...@kr...> - 2009-10-02 14:12:27
|
On Fri, Oct 02, 2009 at 02:40:03PM +0200, Philipp Reisner wrote: > Affected: All code that uses connector, in kernel and out of mainline > > The connector, as it is today, does not allow the in kernel receiving > parts to do any checks on privileges of a message's sender. So, assume I know nothing about the connector architecture, what does this mean in a security context? > I know, there are not many out there that like connector, but as > long as it is in the kernel, we have to fix the security issues it has! And what specifically are the security issues? > Please either drop connector, or someone who feels a bit responsible > and has our beloved dictator's blessing, PLEASE PLEASE PLEASE take > this into your tree, and send the pull request to Linus. > > Patches 1 to 4 are already Acked-by Evgeny, the connector's maintainer. > Patches 5 to 7 are the obvious fixes to the connector user's code. Obvious in what way? thanks, greg k-h |
From: Philipp R. <phi...@li...> - 2009-10-02 12:56:19
|
Signed-off-by: Philipp Reisner <phi...@li...> Acked-by: Lars Ellenberg <lar...@li...> Acked-by: Evgeniy Polyakov <zb...@io...> --- drivers/connector/cn_queue.c | 4 ++-- drivers/connector/connector.c | 11 +++-------- include/linux/connector.h | 3 --- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c index 163c3e3..210338e 100644 --- a/drivers/connector/cn_queue.c +++ b/drivers/connector/cn_queue.c @@ -83,8 +83,8 @@ void cn_queue_wrapper(struct work_struct *work) d->callback(msg, nsp); - d->destruct_data(d->ddata); - d->ddata = NULL; + kfree_skb(d->skb); + d->skb = NULL; kfree(d->free); } diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index e59f0ab..f060246 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -129,7 +129,7 @@ EXPORT_SYMBOL_GPL(cn_netlink_send); /* * Callback helper - queues work and setup destructor for given data. */ -static int cn_call_callback(struct sk_buff *skb, void (*destruct_data)(void *), void *data) +static int cn_call_callback(struct sk_buff *skb) { struct cn_callback_entry *__cbq, *__new_cbq; struct cn_dev *dev = &cdev; @@ -140,12 +140,9 @@ static int cn_call_callback(struct sk_buff *skb, void (*destruct_data)(void *), list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) { if (cn_cb_equal(&__cbq->id.id, &msg->id)) { if (likely(!work_pending(&__cbq->work) && - __cbq->data.ddata == NULL)) { + __cbq->data.skb == NULL)) { __cbq->data.skb = skb; - __cbq->data.ddata = data; - __cbq->data.destruct_data = destruct_data; - if (queue_cn_work(__cbq, &__cbq->work)) err = 0; else @@ -159,8 +156,6 @@ static int cn_call_callback(struct sk_buff *skb, void (*destruct_data)(void *), d = &__new_cbq->data; d->skb = skb; d->callback = __cbq->data.callback; - d->ddata = data; - d->destruct_data = destruct_data; d->free = __new_cbq; __new_cbq->pdev = __cbq->pdev; @@ -208,7 +203,7 @@ static void cn_rx_skb(struct sk_buff *__skb) return; } - err = cn_call_callback(skb, (void (*)(void *))kfree_skb, skb); + err = cn_call_callback(skb); if (err < 0) kfree_skb(skb); } diff --git a/include/linux/connector.h b/include/linux/connector.h index 545728e..3a14615 100644 --- a/include/linux/connector.h +++ b/include/linux/connector.h @@ -132,9 +132,6 @@ struct cn_callback_id { }; struct cn_callback_data { - void (*destruct_data) (void *); - void *ddata; - struct sk_buff *skb; void (*callback) (struct cn_msg *, struct netlink_skb_parms *); -- 1.6.0.4 |
From: Philipp R. <phi...@li...> - 2009-10-02 12:51:29
|
Signed-off-by: Philipp Reisner <phi...@li...> --- drivers/video/uvesafb.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index aa7cd95..e35232a 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -72,6 +72,9 @@ static void uvesafb_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *ns struct uvesafb_task *utask; struct uvesafb_ktask *task; + if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) + return; + if (msg->seq >= UVESAFB_TASKS_MAX) return; -- 1.6.0.4 |
From: Philipp R. <phi...@li...> - 2009-10-02 12:51:28
|
Signed-off-by: Philipp Reisner <phi...@li...> --- drivers/staging/pohmelfs/config.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/drivers/staging/pohmelfs/config.c b/drivers/staging/pohmelfs/config.c index c9162b3..5d04bf5 100644 --- a/drivers/staging/pohmelfs/config.c +++ b/drivers/staging/pohmelfs/config.c @@ -531,6 +531,9 @@ static void pohmelfs_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *n { int err; + if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) + return; + switch (msg->flags) { case POHMELFS_FLAGS_ADD: case POHMELFS_FLAGS_DEL: -- 1.6.0.4 |
From: Philipp R. <phi...@li...> - 2009-10-02 12:42:51
|
Signed-off-by: Philipp Reisner <phi...@li...> --- drivers/staging/dst/dcore.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/drivers/staging/dst/dcore.c b/drivers/staging/dst/dcore.c index 3943c91..ee16010 100644 --- a/drivers/staging/dst/dcore.c +++ b/drivers/staging/dst/dcore.c @@ -855,6 +855,11 @@ static void cn_dst_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) struct dst_node *n = NULL, *tmp; unsigned int hash; + if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) { + err = -EPERM; + goto out; + } + if (msg->len < sizeof(struct dst_ctl)) { err = -EBADMSG; goto out; -- 1.6.0.4 |
From: Philipp R. <phi...@li...> - 2009-10-02 12:41:33
|
Signed-off-by: Philipp Reisner <phi...@li...> Acked-by: Lars Ellenberg <lar...@li...> Acked-by: Evgeniy Polyakov <zb...@io...> --- Documentation/connector/cn_test.c | 2 +- Documentation/connector/connector.txt | 8 ++++---- drivers/connector/cn_queue.c | 7 ++++--- drivers/connector/connector.c | 4 ++-- drivers/md/dm-log-userspace-transfer.c | 2 +- drivers/staging/dst/dcore.c | 2 +- drivers/staging/pohmelfs/config.c | 2 +- drivers/video/uvesafb.c | 2 +- drivers/w1/w1_netlink.c | 2 +- include/linux/connector.h | 6 +++--- 10 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Documentation/connector/cn_test.c b/Documentation/connector/cn_test.c index 1711adc..b07add3 100644 --- a/Documentation/connector/cn_test.c +++ b/Documentation/connector/cn_test.c @@ -34,7 +34,7 @@ static char cn_test_name[] = "cn_test"; static struct sock *nls; static struct timer_list cn_test_timer; -static void cn_test_callback(struct cn_msg *msg) +static void cn_test_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { pr_info("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n", __func__, jiffies, msg->id.idx, msg->id.val, diff --git a/Documentation/connector/connector.txt b/Documentation/connector/connector.txt index 81e6bf6..78c9466 100644 --- a/Documentation/connector/connector.txt +++ b/Documentation/connector/connector.txt @@ -23,7 +23,7 @@ handling, etc... The Connector driver allows any kernelspace agents to use netlink based networking for inter-process communication in a significantly easier way: -int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *)); +int cn_add_callback(struct cb_id *id, char *name, void (*callback) (struct cn_msg *, struct netlink_skb_parms *)); void cn_netlink_send(struct cn_msg *msg, u32 __group, int gfp_mask); struct cb_id @@ -53,15 +53,15 @@ struct cn_msg Connector interfaces. /*****************************************/ -int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *)); +int cn_add_callback(struct cb_id *id, char *name, void (*callback) (struct cn_msg *, struct netlink_skb_parms *)); Registers new callback with connector core. struct cb_id *id - unique connector's user identifier. It must be registered in connector.h for legal in-kernel users. char *name - connector's callback symbolic name. - void (*callback) (void *) - connector's callback. - Argument must be dereferenced to struct cn_msg *. + void (*callback) (struct cn..) - connector's callback. + cn_msg and the sender's credentials void cn_del_callback(struct cb_id *id); diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c index b4cfac9..163c3e3 100644 --- a/drivers/connector/cn_queue.c +++ b/drivers/connector/cn_queue.c @@ -79,8 +79,9 @@ void cn_queue_wrapper(struct work_struct *work) container_of(work, struct cn_callback_entry, work); struct cn_callback_data *d = &cbq->data; struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(d->skb)); + struct netlink_skb_parms *nsp = &NETLINK_CB(d->skb); - d->callback(msg); + d->callback(msg, nsp); d->destruct_data(d->ddata); d->ddata = NULL; @@ -90,7 +91,7 @@ void cn_queue_wrapper(struct work_struct *work) static struct cn_callback_entry * cn_queue_alloc_callback_entry(char *name, struct cb_id *id, - void (*callback)(struct cn_msg *)) + void (*callback)(struct cn_msg *, struct netlink_skb_parms *)) { struct cn_callback_entry *cbq; @@ -124,7 +125,7 @@ int cn_cb_equal(struct cb_id *i1, struct cb_id *i2) } int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, - void (*callback)(struct cn_msg *)) + void (*callback)(struct cn_msg *, struct netlink_skb_parms *)) { struct cn_callback_entry *cbq, *__cbq; int found = 0; diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index fc9887f..e59f0ab 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -269,7 +269,7 @@ static void cn_notify(struct cb_id *id, u32 notify_event) * May sleep. */ int cn_add_callback(struct cb_id *id, char *name, - void (*callback)(struct cn_msg *)) + void (*callback)(struct cn_msg *, struct netlink_skb_parms *)) { int err; struct cn_dev *dev = &cdev; @@ -351,7 +351,7 @@ static int cn_ctl_msg_equals(struct cn_ctl_msg *m1, struct cn_ctl_msg *m2) * * Used for notification of a request's processing. */ -static void cn_callback(struct cn_msg *msg) +static void cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { struct cn_ctl_msg *ctl; struct cn_ctl_entry *ent; diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c index ba0edad..556131f 100644 --- a/drivers/md/dm-log-userspace-transfer.c +++ b/drivers/md/dm-log-userspace-transfer.c @@ -129,7 +129,7 @@ static int fill_pkg(struct cn_msg *msg, struct dm_ulog_request *tfr) * This is the connector callback that delivers data * that was sent from userspace. */ -static void cn_ulog_callback(void *data) +static void cn_ulog_callback(void *data, struct netlink_skb_parms *nsp) { struct cn_msg *msg = (struct cn_msg *)data; struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1); diff --git a/drivers/staging/dst/dcore.c b/drivers/staging/dst/dcore.c index ac85773..3943c91 100644 --- a/drivers/staging/dst/dcore.c +++ b/drivers/staging/dst/dcore.c @@ -847,7 +847,7 @@ static dst_command_func dst_commands[] = { /* * Configuration parser. */ -static void cn_dst_callback(struct cn_msg *msg) +static void cn_dst_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { struct dst_ctl *ctl; int err; diff --git a/drivers/staging/pohmelfs/config.c b/drivers/staging/pohmelfs/config.c index 90f962e..c9162b3 100644 --- a/drivers/staging/pohmelfs/config.c +++ b/drivers/staging/pohmelfs/config.c @@ -527,7 +527,7 @@ out_unlock: return err; } -static void pohmelfs_cn_callback(struct cn_msg *msg) +static void pohmelfs_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { int err; diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index e98baf6..aa7cd95 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -67,7 +67,7 @@ static DEFINE_MUTEX(uvfb_lock); * find the kernel part of the task struct, copy the registers and * the buffer contents and then complete the task. */ -static void uvesafb_cn_callback(struct cn_msg *msg) +static void uvesafb_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { struct uvesafb_task *utask; struct uvesafb_ktask *task; diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 52ccb3d..45c126f 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c @@ -306,7 +306,7 @@ static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rm return error; } -static void w1_cn_callback(struct cn_msg *msg) +static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); struct w1_netlink_cmd *cmd; diff --git a/include/linux/connector.h b/include/linux/connector.h index 05a7a14..545728e 100644 --- a/include/linux/connector.h +++ b/include/linux/connector.h @@ -136,7 +136,7 @@ struct cn_callback_data { void *ddata; struct sk_buff *skb; - void (*callback) (struct cn_msg *); + void (*callback) (struct cn_msg *, struct netlink_skb_parms *); void *free; }; @@ -167,11 +167,11 @@ struct cn_dev { struct cn_queue_dev *cbdev; }; -int cn_add_callback(struct cb_id *, char *, void (*callback) (struct cn_msg *)); +int cn_add_callback(struct cb_id *, char *, void (*callback) (struct cn_msg *, struct netlink_skb_parms *)); void cn_del_callback(struct cb_id *); int cn_netlink_send(struct cn_msg *, u32, gfp_t); -int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(struct cn_msg *)); +int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(struct cn_msg *, struct netlink_skb_parms *)); void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id); int queue_cn_work(struct cn_callback_entry *cbq, struct work_struct *work); -- 1.6.0.4 |
From: Philipp R. <phi...@li...> - 2009-10-02 12:41:33
|
Signed-off-by: Philipp Reisner <phi...@li...> Acked-by: Lars Ellenberg <lar...@li...> Acked-by: Evgeniy Polyakov <zb...@io...> --- drivers/md/dm-log-userspace-transfer.c | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c index 556131f..1327e1a 100644 --- a/drivers/md/dm-log-userspace-transfer.c +++ b/drivers/md/dm-log-userspace-transfer.c @@ -129,9 +129,8 @@ static int fill_pkg(struct cn_msg *msg, struct dm_ulog_request *tfr) * This is the connector callback that delivers data * that was sent from userspace. */ -static void cn_ulog_callback(void *data, struct netlink_skb_parms *nsp) +static void cn_ulog_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { - struct cn_msg *msg = (struct cn_msg *)data; struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1); spin_lock(&receiving_list_lock); -- 1.6.0.4 |
From: Philipp R. <phi...@li...> - 2009-10-02 12:41:33
|
Affected: All code that uses connector, in kernel and out of mainline The connector, as it is today, does not allow the in kernel receiving parts to do any checks on privileges of a message's sender. I know, there are not many out there that like connector, but as long as it is in the kernel, we have to fix the security issues it has! Please either drop connector, or someone who feels a bit responsible and has our beloved dictator's blessing, PLEASE PLEASE PLEASE take this into your tree, and send the pull request to Linus. Patches 1 to 4 are already Acked-by Evgeny, the connector's maintainer. Patches 5 to 7 are the obvious fixes to the connector user's code. For convenience these patches are also available as git tree: git://git.drbd.org/linux-2.6-drbd.git connector-fix -Phil Philipp Reisner (8): connector: Keep the skb in cn_callback_data connector: Provide the sender's credentials to the callback connector/dm: Fixed a compilation warning connector: Removed the destruct_data callback since it is always kfree_skb() dm/connector: Only process connector packages from privileged processes dst/connector: Disallow unpliviged users to configure dst pohmelfs/connector: Disallow unpliviged users to configure pohmelfs uvesafb/connector: Disallow unpliviged users to send netlink packets Documentation/connector/cn_test.c | 2 +- Documentation/connector/connector.txt | 8 ++++---- drivers/connector/cn_queue.c | 12 +++++++----- drivers/connector/connector.c | 22 ++++++++-------------- drivers/md/dm-log-userspace-transfer.c | 6 ++++-- drivers/staging/dst/dcore.c | 7 ++++++- drivers/staging/pohmelfs/config.c | 5 ++++- drivers/video/uvesafb.c | 5 ++++- drivers/w1/w1_netlink.c | 2 +- include/linux/connector.h | 11 ++++------- 10 files changed, 43 insertions(+), 37 deletions(-) |
From: Philipp R. <phi...@li...> - 2009-10-02 12:41:33
|
Signed-off-by: Philipp Reisner <phi...@li...> Acked-by: Lars Ellenberg <lar...@li...> Acked-by: Evgeniy Polyakov <zb...@io...> --- drivers/connector/cn_queue.c | 3 ++- drivers/connector/connector.c | 11 +++++------ include/linux/connector.h | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c index 4a1dfe1..b4cfac9 100644 --- a/drivers/connector/cn_queue.c +++ b/drivers/connector/cn_queue.c @@ -78,8 +78,9 @@ void cn_queue_wrapper(struct work_struct *work) struct cn_callback_entry *cbq = container_of(work, struct cn_callback_entry, work); struct cn_callback_data *d = &cbq->data; + struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(d->skb)); - d->callback(d->callback_priv); + d->callback(msg); d->destruct_data(d->ddata); d->ddata = NULL; diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index 74f52af..fc9887f 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -129,10 +129,11 @@ EXPORT_SYMBOL_GPL(cn_netlink_send); /* * Callback helper - queues work and setup destructor for given data. */ -static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), void *data) +static int cn_call_callback(struct sk_buff *skb, void (*destruct_data)(void *), void *data) { struct cn_callback_entry *__cbq, *__new_cbq; struct cn_dev *dev = &cdev; + struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(skb)); int err = -ENODEV; spin_lock_bh(&dev->cbdev->queue_lock); @@ -140,7 +141,7 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v if (cn_cb_equal(&__cbq->id.id, &msg->id)) { if (likely(!work_pending(&__cbq->work) && __cbq->data.ddata == NULL)) { - __cbq->data.callback_priv = msg; + __cbq->data.skb = skb; __cbq->data.ddata = data; __cbq->data.destruct_data = destruct_data; @@ -156,7 +157,7 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v __new_cbq = kzalloc(sizeof(struct cn_callback_entry), GFP_ATOMIC); if (__new_cbq) { d = &__new_cbq->data; - d->callback_priv = msg; + d->skb = skb; d->callback = __cbq->data.callback; d->ddata = data; d->destruct_data = destruct_data; @@ -191,7 +192,6 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v */ static void cn_rx_skb(struct sk_buff *__skb) { - struct cn_msg *msg; struct nlmsghdr *nlh; int err; struct sk_buff *skb; @@ -208,8 +208,7 @@ static void cn_rx_skb(struct sk_buff *__skb) return; } - msg = NLMSG_DATA(nlh); - err = cn_call_callback(msg, (void (*)(void *))kfree_skb, skb); + err = cn_call_callback(skb, (void (*)(void *))kfree_skb, skb); if (err < 0) kfree_skb(skb); } diff --git a/include/linux/connector.h b/include/linux/connector.h index 47ebf41..05a7a14 100644 --- a/include/linux/connector.h +++ b/include/linux/connector.h @@ -134,8 +134,8 @@ struct cn_callback_id { struct cn_callback_data { void (*destruct_data) (void *); void *ddata; - - void *callback_priv; + + struct sk_buff *skb; void (*callback) (struct cn_msg *); void *free; -- 1.6.0.4 |
From: Alessio S. <al...@ma...> - 2009-10-01 07:41:57
|
Hi, is there a standard way for a userspace program to "probe" the supported display sizes/refresh rates/bit depths? The display I'm writing a driver for only supports a few specific resolutions, and I'm wondering how a userspace program can discover those. Thank you Alessio |
From: Mike F. <va...@ge...> - 2009-10-01 05:44:28
|
From: Michael Hennerich <mic...@an...> Framebuffer driver for the Landscape LCD EZ-Extender (ADZS-BFLLCD-EZEXT) http://docs.blackfin.uclinux.org/doku.php?id=hw:cards:landscape_lcd_ez-extender Signed-off-by: Michael Hennerich <mic...@an...> Signed-off-by: Bryan Wu <coo...@ke...> Signed-off-by: Mike Frysinger <va...@ge...> --- v2 - fix some spelling typos - rename spidev_spi to avoid section mismatches - convert output pr_* to dev_* - convert to new dev pm opts - push the global vars into dynamic state - clean up error handling code - use common mmap code arch/blackfin/include/asm/bfin-lq035q1.h | 28 + drivers/video/Kconfig | 13 + drivers/video/Makefile | 1 + drivers/video/bfin-lq035q1-fb.c | 826 ++++++++++++++++++++++++++++++ 4 files changed, 868 insertions(+), 0 deletions(-) create mode 100644 arch/blackfin/include/asm/bfin-lq035q1.h create mode 100644 drivers/video/bfin-lq035q1-fb.c diff --git a/arch/blackfin/include/asm/bfin-lq035q1.h b/arch/blackfin/include/asm/bfin-lq035q1.h new file mode 100644 index 0000000..57bc21a --- /dev/null +++ b/arch/blackfin/include/asm/bfin-lq035q1.h @@ -0,0 +1,28 @@ +/* + * Blackfin LCD Framebuffer driver SHARP LQ035Q1DH02 + * + * Copyright 2008-2009 Analog Devices Inc. + * Licensed under the GPL-2 or later. + */ + +#ifndef BFIN_LQ035Q1_H +#define BFIN_LQ035Q1_H + +#define LQ035_RL (0 << 8) /* Right -> Left Scan */ +#define LQ035_LR (1 << 8) /* Left -> Right Scan */ +#define LQ035_TB (1 << 9) /* Top -> Botton Scan */ +#define LQ035_BT (0 << 9) /* Botton -> Top Scan */ +#define LQ035_BGR (1 << 11) /* Use BGR format */ +#define LQ035_RGB (0 << 11) /* Use RGB format */ +#define LQ035_NORM (1 << 13) /* Reversal */ +#define LQ035_REV (0 << 13) /* Reversal */ + +struct bfin_lq035q1fb_disp_info { + + unsigned mode; + /* GPIOs */ + int use_bl; + unsigned gpio_bl; +}; + +#endif /* BFIN_LQ035Q1_H */ diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 9bbb285..fb87e5f 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -611,6 +611,19 @@ config FB_BFIN_T350MCQB This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK. +config FB_BFIN_LQ035Q1 + tristate "SHARP LQ035Q1DH02 TFT LCD" + depends on FB && BLACKFIN + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select BFIN_GPTIMERS + select SPI + help + This is the framebuffer device driver for a SHARP LQ035Q1DH02 TFT display found on + the Blackfin Landscape LCD EZ-Extender Card. + This display is a QVGA 320x240 18-bit RGB display interfaced by an 16-bit wide PPI + It uses PPI[0..15] PPI_FS1, PPI_FS2 and PPI_CLK. config FB_STI tristate "HP STI frame buffer device support" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 80232e1..42df98d 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -136,6 +136,7 @@ obj-$(CONFIG_FB_EFI) += efifb.o obj-$(CONFIG_FB_VGA16) += vga16fb.o obj-$(CONFIG_FB_OF) += offb.o obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o +obj-$(CONFIG_FB_BFIN_LQ035Q1) += bfin-lq035q1-fb.o obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o obj-$(CONFIG_FB_MX3) += mx3fb.o obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c new file mode 100644 index 0000000..b690c26 --- /dev/null +++ b/drivers/video/bfin-lq035q1-fb.c @@ -0,0 +1,826 @@ +/* + * Blackfin LCD Framebuffer driver SHARP LQ035Q1DH02 + * + * Copyright 2008-2009 Analog Devices Inc. + * Licensed under the GPL-2 or later. + */ + +#define DRIVER_NAME "bfin-lq035q1" +#define pr_fmt(fmt) DRIVER_NAME ": " fmt + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/backlight.h> +#include <linux/lcd.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/dma-mapping.h> + +#include <asm/blackfin.h> +#include <asm/irq.h> +#include <asm/dma.h> +#include <asm/portmux.h> +#include <asm/gptimers.h> + +#include <asm/bfin-lq035q1.h> + +#if defined(BF533_FAMILY) || defined(BF538_FAMILY) +#define TIMER_HSYNC_id TIMER1_id +#define TIMER_HSYNCbit TIMER1bit +#define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN1 +#define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1 +#define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF1 + +#define TIMER_VSYNC_id TIMER2_id +#define TIMER_VSYNCbit TIMER2bit +#define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN2 +#define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL2 +#define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF2 +#else +#define TIMER_HSYNC_id TIMER0_id +#define TIMER_HSYNCbit TIMER0bit +#define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN0 +#define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL0 +#define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF0 + +#define TIMER_VSYNC_id TIMER1_id +#define TIMER_VSYNCbit TIMER1bit +#define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN1 +#define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1 +#define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF1 +#endif + +#define LCD_X_RES 320 /* Horizontal Resolution */ +#define LCD_Y_RES 240 /* Vertical Resolution */ +#define DMA_BUS_SIZE 16 + +#define USE_RGB565_16_BIT_PPI + +#ifdef USE_RGB565_16_BIT_PPI +#define LCD_BPP 16 /* Bit Per Pixel */ +#define CLOCKS_PER_PIX 1 +#define CPLD_PIPELINE_DELAY_COR 0 /* NO CPLB */ +#endif + +/* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD) + * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165 + */ + +#ifdef USE_RGB565_8_BIT_PPI +#define LCD_BPP 16 /* Bit Per Pixel */ +#define CLOCKS_PER_PIX 2 +#define CPLD_PIPELINE_DELAY_COR 3 /* RGB565 */ +#endif + +#ifdef USE_RGB888_8_BIT_PPI +#define LCD_BPP 24 /* Bit Per Pixel */ +#define CLOCKS_PER_PIX 3 +#define CPLD_PIPELINE_DELAY_COR 5 /* RGB888 */ +#endif + + /* + * HS and VS timing parameters (all in number of PPI clk ticks) + */ + +#define U_LINE 4 /* Blanking Lines */ + +#define H_ACTPIX (LCD_X_RES * CLOCKS_PER_PIX) /* active horizontal pixel */ +#define H_PERIOD (336 * CLOCKS_PER_PIX) /* HS period */ +#define H_PULSE (2 * CLOCKS_PER_PIX) /* HS pulse width */ +#define H_START (7 * CLOCKS_PER_PIX + CPLD_PIPELINE_DELAY_COR) /* first valid pixel */ + +#define V_LINES (LCD_Y_RES + U_LINE) /* total vertical lines */ +#define V_PULSE (2 * CLOCKS_PER_PIX) /* VS pulse width (1-5 H_PERIODs) */ +#define V_PERIOD (H_PERIOD * V_LINES) /* VS period */ + +#define ACTIVE_VIDEO_MEM_OFFSET ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8)) + +#define BFIN_LCD_NBR_PALETTE_ENTRIES 256 + +#define PPI_TX_MODE 0x2 +#define PPI_XFER_TYPE_11 0xC +#define PPI_PORT_CFG_01 0x10 +#define PPI_POLS_1 0x8000 + +#if (CLOCKS_PER_PIX > 1) +#define PPI_PMODE (DLEN_8 | PACK_EN) +#else +#define PPI_PMODE (DLEN_16) +#endif + +#define LQ035_INDEX 0x74 +#define LQ035_DATA 0x76 + +#define LQ035_DRIVER_OUTPUT_CTL 0x1 +#define LQ035_SHUT_CTL 0x11 + +#define LQ035_DRIVER_OUTPUT_MASK (LQ035_LR | LQ035_TB | LQ035_BGR | LQ035_REV) +#define LQ035_DRIVER_OUTPUT_DEFAULT (0x2AEF & ~LQ035_DRIVER_OUTPUT_MASK) + +#define LQ035_SHUT (1 << 0) /* Shutdown */ +#define LQ035_ON (0 << 0) /* Shutdown */ + +struct bfin_lq035q1fb_info { + struct fb_info *fb; + struct device *dev; + struct spi_driver spidrv; + struct bfin_lq035q1fb_disp_info *disp_info; + unsigned char *fb_buffer; /* RGB Buffer */ + dma_addr_t dma_handle; + int lq035_open_cnt; + int irq; + spinlock_t lock; /* lock */ + u32 pseudo_pal[16]; +}; + +static int nocursor; +module_param(nocursor, int, 0644); +MODULE_PARM_DESC(nocursor, "cursor enable/disable"); + +struct spi_control { + unsigned short mode; +}; + +static int lq035q1_control(struct spi_device *spi, unsigned char reg, unsigned short value) +{ + int ret; + u8 regs[3] = { LQ035_INDEX, 0, 0 }; + u8 dat[3] = { LQ035_DATA, 0, 0 }; + + if (!spi) + return -ENODEV; + + regs[2] = reg; + dat[1] = value >> 8; + dat[2] = value & 0xFF; + + ret = spi_write(spi, regs, ARRAY_SIZE(regs)); + ret |= spi_write(spi, dat, ARRAY_SIZE(dat)); + return ret; +} + +static int __devinit lq035q1_spidev_probe(struct spi_device *spi) +{ + int ret; + struct spi_control *ctl; + struct bfin_lq035q1fb_info *info = container_of(spi->dev.driver, + struct bfin_lq035q1fb_info, + spidrv.driver); + + ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); + + if (!ctl) + return -ENOMEM; + + ctl->mode = (info->disp_info->mode & + LQ035_DRIVER_OUTPUT_MASK) | LQ035_DRIVER_OUTPUT_DEFAULT; + + ret = lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON); + ret |= lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode); + if (ret) + return ret; + + spi_set_drvdata(spi, ctl); + + return 0; +} + +static int lq035q1_spidev_remove(struct spi_device *spi) +{ + return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); +} + +#ifdef CONFIG_PM +static int lq035q1_spidev_suspend(struct spi_device *spi, pm_message_t state) +{ + return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); +} + +static int lq035q1_spidev_resume(struct spi_device *spi) +{ + int ret; + struct spi_control *ctl = spi_get_drvdata(spi); + + ret = lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode); + if (ret) + return ret; + + return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON); +} +#else +# define lq035q1_spidev_suspend NULL +# define lq035q1_spidev_resume NULL +#endif + +/* Power down all displays on reboot, poweroff or halt */ +static void lq035q1_spidev_shutdown(struct spi_device *spi) +{ + lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); +} + +static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg) +{ + if (info->disp_info->use_bl) + gpio_set_value(info->disp_info->gpio_bl, arg); + + return 0; +} + +static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi) +{ + bfin_write_PPI_DELAY(H_START); + bfin_write_PPI_COUNT(H_ACTPIX - 1); + bfin_write_PPI_FRAME(V_LINES); + + bfin_write_PPI_CONTROL(PPI_TX_MODE | /* output mode , PORT_DIR */ + PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */ + PPI_PORT_CFG_01 | /* two frame sync PORT_CFG */ + PPI_PMODE | /* 8/16 bit data length / PACK_EN? */ + PPI_POLS_1); /* faling edge syncs POLS */ +} + +static inline void bfin_lq035q1_disable_ppi(void) +{ + bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN); +} + +static inline void bfin_lq035q1_enable_ppi(void) +{ + bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN); +} + +static void bfin_lq035q1_start_timers(void) +{ + enable_gptimers(TIMER_VSYNCbit | TIMER_HSYNCbit); +} + +static void bfin_lq035q1_stop_timers(void) +{ + disable_gptimers(TIMER_HSYNCbit | TIMER_VSYNCbit); + + set_gptimer_status(0, TIMER_HSYNC_STATUS_TRUN | TIMER_VSYNC_STATUS_TRUN | + TIMER_HSYNC_STATUS_TIMIL | TIMER_VSYNC_STATUS_TIMIL | + TIMER_HSYNC_STATUS_TOVF | TIMER_VSYNC_STATUS_TOVF); + +} + +static void bfin_lq035q1_init_timers(void) +{ + + bfin_lq035q1_stop_timers(); + + set_gptimer_period(TIMER_HSYNC_id, H_PERIOD); + set_gptimer_pwidth(TIMER_HSYNC_id, H_PULSE); + set_gptimer_config(TIMER_HSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | + TIMER_TIN_SEL | TIMER_CLK_SEL| + TIMER_EMU_RUN); + + set_gptimer_period(TIMER_VSYNC_id, V_PERIOD); + set_gptimer_pwidth(TIMER_VSYNC_id, V_PULSE); + set_gptimer_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | + TIMER_TIN_SEL | TIMER_CLK_SEL | + TIMER_EMU_RUN); + +} + +static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi) +{ + + set_dma_config(CH_PPI, + set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, + INTR_DISABLE, DIMENSION_2D, + DATA_SIZE_16, + DMA_NOSYNC_KEEP_DMA_BUF)); + set_dma_x_count(CH_PPI, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE); + set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8); + set_dma_y_count(CH_PPI, V_LINES); + + set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8); + set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer); + +} + +#if (CLOCKS_PER_PIX == 1) +static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, + P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, + P_PPI0_D6, P_PPI0_D7, P_PPI0_D8, + P_PPI0_D9, P_PPI0_D10, P_PPI0_D11, + P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, + P_PPI0_D15, 0}; +#else +static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, + P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, + P_PPI0_D6, P_PPI0_D7, 0}; +#endif + +static inline void bfin_lq035q1_free_ports(void) +{ + peripheral_free_list(ppi0_req_16); + if (ANOMALY_05000400) + gpio_free(P_IDENT(P_PPI0_FS3)); +} + +static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev) +{ + /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode: + * Drive PPI_FS3 Low + */ + if (ANOMALY_05000400) { + int ret = gpio_request(P_IDENT(P_PPI0_FS3), "PPI_FS3"); + if (ret) + return ret; + gpio_direction_output(P_IDENT(P_PPI0_FS3), 0); + } + + if (peripheral_request_list(ppi0_req_16, DRIVER_NAME)) { + dev_err(&pdev->dev, "requesting peripherals failed\n"); + return -EFAULT; + } + + return 0; +} + +static int bfin_lq035q1_fb_open(struct fb_info *info, int user) +{ + struct bfin_lq035q1fb_info *fbi = info->par; + + spin_lock(&fbi->lock); + fbi->lq035_open_cnt++; + + if (fbi->lq035_open_cnt <= 1) { + + bfin_lq035q1_disable_ppi(); + SSYNC(); + + bfin_lq035q1_config_dma(fbi); + bfin_lq035q1_config_ppi(fbi); + bfin_lq035q1_init_timers(); + + /* start dma */ + enable_dma(CH_PPI); + bfin_lq035q1_enable_ppi(); + bfin_lq035q1_start_timers(); + lq035q1_backlight(fbi, 1); + } + + spin_unlock(&fbi->lock); + + return 0; +} + +static int bfin_lq035q1_fb_release(struct fb_info *info, int user) +{ + struct bfin_lq035q1fb_info *fbi = info->par; + + spin_lock(&fbi->lock); + + fbi->lq035_open_cnt--; + + if (fbi->lq035_open_cnt <= 0) { + lq035q1_backlight(fbi, 0); + bfin_lq035q1_disable_ppi(); + SSYNC(); + disable_dma(CH_PPI); + bfin_lq035q1_stop_timers(); + } + + spin_unlock(&fbi->lock); + + return 0; +} + +static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + switch (var->bits_per_pixel) { +#if (LCD_BPP == 24) + case 24:/* TRUECOLOUR, 16m */ +#else + case 16:/* DIRECTCOLOUR, 64k */ +#endif + var->red.offset = info->var.red.offset; + var->green.offset = info->var.green.offset; + var->blue.offset = info->var.blue.offset; + var->red.length = info->var.red.length; + var->green.length = info->var.green.length; + var->blue.length = info->var.blue.length; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + break; + default: + pr_debug("%s: depth not supported: %u BPP\n", __func__, + var->bits_per_pixel); + return -EINVAL; + } + + if (info->var.xres != var->xres || info->var.yres != var->yres || + info->var.xres_virtual != var->xres_virtual || + info->var.yres_virtual != var->yres_virtual) { + pr_debug("%s: Resolution not supported: X%u x Y%u \n", + __func__, var->xres, var->yres); + return -EINVAL; + } + + /* + * Memory limit + */ + + if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { + pr_debug("%s: Memory Limit requested yres_virtual = %u\n", + __func__, var->yres_virtual); + return -ENOMEM; + } + + + return 0; +} + +int bfin_lq035q1_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + if (nocursor) + return 0; + else + return -EINVAL; /* just to force soft_cursor() call */ +} + +static int bfin_lq035q1_fb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, + struct fb_info *info) +{ + if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES) + return -EINVAL; + + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + + u32 value; + /* Place color in the pseudopalette */ + if (regno > 16) + return -EINVAL; + + red >>= (16 - info->var.red.length); + green >>= (16 - info->var.green.length); + blue >>= (16 - info->var.blue.length); + + value = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + value &= 0xFFFFFF; + + ((u32 *) (info->pseudo_palette))[regno] = value; + + } + + return 0; +} + +static struct fb_ops bfin_lq035q1_fb_ops = { + .owner = THIS_MODULE, + .fb_open = bfin_lq035q1_fb_open, + .fb_release = bfin_lq035q1_fb_release, + .fb_check_var = bfin_lq035q1_fb_check_var, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = bfin_lq035q1_fb_cursor, + .fb_setcolreg = bfin_lq035q1_fb_setcolreg, +}; + +static irqreturn_t bfin_lq035q1_irq_error(int irq, void *dev_id) +{ + /*struct bfin_lq035q1fb_info *info = (struct bfin_lq035q1fb_info *)dev_id;*/ + + u16 status = bfin_read_PPI_STATUS(); + bfin_write_PPI_STATUS(-1); + + if (status) { + bfin_lq035q1_disable_ppi(); + disable_dma(CH_PPI); + + /* start dma */ + enable_dma(CH_PPI); + bfin_lq035q1_enable_ppi(); + bfin_write_PPI_STATUS(-1); + } + + return IRQ_HANDLED; +} + +static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) +{ + struct bfin_lq035q1fb_info *info; + struct fb_info *fbinfo; + int ret; + + ret = request_dma(CH_PPI, DRIVER_NAME"_CH_PPI"); + if (ret < 0) { + dev_err(&pdev->dev, "PPI DMA unavailable\n"); + goto out1; + } + + fbinfo = framebuffer_alloc(sizeof(*info), &pdev->dev); + if (!fbinfo) { + ret = -ENOMEM; + goto out2; + } + + info = fbinfo->par; + info->fb = fbinfo; + info->dev = &pdev->dev; + + info->disp_info = pdev->dev.platform_data; + + platform_set_drvdata(pdev, fbinfo); + + strcpy(fbinfo->fix.id, DRIVER_NAME); + + fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; + fbinfo->fix.type_aux = 0; + fbinfo->fix.xpanstep = 0; + fbinfo->fix.ypanstep = 0; + fbinfo->fix.ywrapstep = 0; + fbinfo->fix.accel = FB_ACCEL_NONE; + fbinfo->fix.visual = FB_VISUAL_TRUECOLOR; + + fbinfo->var.nonstd = 0; + fbinfo->var.activate = FB_ACTIVATE_NOW; + fbinfo->var.height = -1; + fbinfo->var.width = -1; + fbinfo->var.accel_flags = 0; + fbinfo->var.vmode = FB_VMODE_NONINTERLACED; + + fbinfo->var.xres = LCD_X_RES; + fbinfo->var.xres_virtual = LCD_X_RES; + fbinfo->var.yres = LCD_Y_RES; + fbinfo->var.yres_virtual = LCD_Y_RES; + fbinfo->var.bits_per_pixel = LCD_BPP; + + if (info->disp_info->mode & LQ035_BGR) { +#if (LCD_BPP == 24) + fbinfo->var.red.offset = 0; + fbinfo->var.green.offset = 8; + fbinfo->var.blue.offset = 16; +#else + fbinfo->var.red.offset = 0; + fbinfo->var.green.offset = 5; + fbinfo->var.blue.offset = 11; +#endif + } else { +#if (LCD_BPP == 24) + fbinfo->var.red.offset = 16; + fbinfo->var.green.offset = 8; + fbinfo->var.blue.offset = 0; +#else + fbinfo->var.red.offset = 11; + fbinfo->var.green.offset = 5; + fbinfo->var.blue.offset = 0; +#endif + } + + fbinfo->var.transp.offset = 0; + +#if (LCD_BPP == 24) + fbinfo->var.red.length = 8; + fbinfo->var.green.length = 8; + fbinfo->var.blue.length = 8; +#else + fbinfo->var.red.length = 5; + fbinfo->var.green.length = 6; + fbinfo->var.blue.length = 5; +#endif + + fbinfo->var.transp.length = 0; + + fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8 + + ACTIVE_VIDEO_MEM_OFFSET; + + fbinfo->fix.line_length = fbinfo->var.xres_virtual * + fbinfo->var.bits_per_pixel / 8; + + + fbinfo->fbops = &bfin_lq035q1_fb_ops; + fbinfo->flags = FBINFO_FLAG_DEFAULT; + + info->fb_buffer = + dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle, + GFP_KERNEL); + + if (NULL == info->fb_buffer) { + dev_err(&pdev->dev, "couldn't allocate dma buffer\n"); + ret = -ENOMEM; + goto out3; + } + + fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; + fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; + + fbinfo->fbops = &bfin_lq035q1_fb_ops; + + fbinfo->pseudo_palette = &info->pseudo_pal; + + ret = fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0); + if (ret < 0) { + dev_err(&pdev->dev, "failed to allocate colormap (%d entries)\n", + BFIN_LCD_NBR_PALETTE_ENTRIES); + goto out4; + } + + ret = bfin_lq035q1_request_ports(pdev); + if (ret) { + dev_err(&pdev->dev, "couldn't request gpio port\n"); + goto out6; + } + + info->irq = platform_get_irq(pdev, 0); + if (info->irq < 0) { + ret = -EINVAL; + goto out7; + } + + ret = request_irq(info->irq, bfin_lq035q1_irq_error, IRQF_DISABLED, + DRIVER_NAME" PPI ERROR", info); + if (ret < 0) { + dev_err(&pdev->dev, "unable to request PPI ERROR IRQ\n"); + goto out7; + } + + info->spidrv.driver.name = DRIVER_NAME"-spi"; + info->spidrv.probe = lq035q1_spidev_probe; + info->spidrv.remove = __devexit_p(lq035q1_spidev_remove); + info->spidrv.shutdown = lq035q1_spidev_shutdown; + info->spidrv.suspend = lq035q1_spidev_suspend; + info->spidrv.resume = lq035q1_spidev_resume; + + ret = spi_register_driver(&info->spidrv); + if (ret < 0) { + dev_err(&pdev->dev, "couldn't register SPI Interface\n"); + goto out8; + } + + if (info->disp_info->use_bl) { + ret = gpio_request(info->disp_info->gpio_bl, "LQ035 Backlight"); + + if (ret) { + dev_err(&pdev->dev, "failed to request GPIO %d\n", + info->disp_info->gpio_bl); + goto out9; + } + gpio_direction_output(info->disp_info->gpio_bl, 0); + } + + ret = register_framebuffer(fbinfo); + if (ret < 0) { + dev_err(&pdev->dev, "unable to register framebuffer\n"); + goto out10; + } + + dev_info(&pdev->dev, "%dx%d %d-bit RGB FrameBuffer initialized\n", + LCD_X_RES, LCD_Y_RES, LCD_BPP); + + return 0; + + out10: + if (info->disp_info->use_bl) + gpio_free(info->disp_info->gpio_bl); + out9: + spi_unregister_driver(&info->spidrv); + out8: + free_irq(info->irq, info); + out7: + bfin_lq035q1_free_ports(); + out6: + fb_dealloc_cmap(&fbinfo->cmap); + out4: + dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, + info->dma_handle); + out3: + framebuffer_release(fbinfo); + out2: + free_dma(CH_PPI); + out1: + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int __devexit bfin_lq035q1_remove(struct platform_device *pdev) +{ + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_lq035q1fb_info *info = fbinfo->par; + + if (info->disp_info->use_bl) + gpio_free(info->disp_info->gpio_bl); + + spi_unregister_driver(&info->spidrv); + + unregister_framebuffer(fbinfo); + + free_dma(CH_PPI); + free_irq(info->irq, info); + + if (info->fb_buffer != NULL) + dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, + info->dma_handle); + + fb_dealloc_cmap(&fbinfo->cmap); + + bfin_lq035q1_free_ports(); + + platform_set_drvdata(pdev, NULL); + framebuffer_release(fbinfo); + + dev_info(&pdev->dev, "unregistered LCD driver\n"); + + return 0; +} + +#ifdef CONFIG_PM +static int bfin_lq035q1_suspend(struct device *dev) +{ + struct fb_info *fbinfo = dev_get_drvdata(dev); + struct bfin_lq035q1fb_info *info = fbinfo->par; + + if (info->lq035_open_cnt) { + lq035q1_backlight(info, 0); + bfin_lq035q1_disable_ppi(); + SSYNC(); + disable_dma(CH_PPI); + bfin_lq035q1_stop_timers(); + bfin_write_PPI_STATUS(-1); + } + + return 0; +} + +static int bfin_lq035q1_resume(struct device *dev) +{ + struct fb_info *fbinfo = dev_get_drvdata(dev); + struct bfin_lq035q1fb_info *info = fbinfo->par; + + if (info->lq035_open_cnt) { + bfin_lq035q1_disable_ppi(); + SSYNC(); + + bfin_lq035q1_config_dma(info); + bfin_lq035q1_config_ppi(info); + bfin_lq035q1_init_timers(); + + /* start dma */ + enable_dma(CH_PPI); + bfin_lq035q1_enable_ppi(); + bfin_lq035q1_start_timers(); + lq035q1_backlight(info, 1); + } + + return 0; +} + +static struct dev_pm_ops bfin_lq035q1_dev_pm_ops = { + .suspend = bfin_lq035q1_suspend, + .resume = bfin_lq035q1_resume, +}; +#endif + +static struct platform_driver bfin_lq035q1_driver = { + .probe = bfin_lq035q1_probe, + .remove = __devexit_p(bfin_lq035q1_remove), + .driver = { + .name = DRIVER_NAME, +#ifdef CONFIG_PM + .pm = &bfin_lq035q1_dev_pm_ops, +#endif + }, +}; + +static int __init bfin_lq035q1_driver_init(void) +{ + return platform_driver_register(&bfin_lq035q1_driver); +} +module_init(bfin_lq035q1_driver_init); + +static void __exit bfin_lq035q1_driver_cleanup(void) +{ + platform_driver_unregister(&bfin_lq035q1_driver); +} +module_exit(bfin_lq035q1_driver_cleanup); + +MODULE_DESCRIPTION("Blackfin TFT LCD Driver"); +MODULE_LICENSE("GPL"); -- 1.6.5.rc2 |
From: Jiri K. <jk...@su...> - 2009-09-29 12:08:00
|
On Tue, 29 Sep 2009, Imre Deak wrote: > > Trivial patch which adds the __init/__exit macros to the module_init/ > > module_exit functions of the following drivers in media/omap: > > drivers/video/omap/lcd_ams_delta.c > > drivers/video/omap/lcd_mipid.c > > > > Please have a look at the small patch and either pull it through > > your tree, or please ack' it so Jiri can pull it through the trivial tree. > > > > linux version v2.6.32-rc1 - linus git tree, Di 29. Sep 01:10:18 CEST 2009 > > > > Signed-off-by: Peter Huewe <pet...@gm...> > > Acked-by: Imre Deak <imr...@no...> Applied, thanks. -- Jiri Kosina SUSE Labs, Novell Inc. |